• 前端开发-如何从已实现的锁屏功能中抽取出锁屏功能模板?
  • 发布于 2个月前
  • 204 热度
    0 评论
一. 故事背景

在前端开发中,常常需要实现锁屏功能;最为常见的情况为点击某个按钮进入锁屏。本文从实际业务出发,从已经实现的锁屏功能中抽取出锁屏功能模板,从功能实现和注意细节两个角度进行说明,以实现后续开发过程中的复用。


二. 锁屏活动流程
1.点击锁屏按钮
2.记录锁屏前的前端路由到本地存储,方便锁屏解除之后回到当前页
3.关闭当前页面弹出的所有窗口
4.关闭锁屏期间不需要的通信服务,提升性能
5.使用react-router-dom的useNavigate进行前端路由跳转
6.通知后端更新前端的锁屏信息(某些服务可以先暂停,保存时间戳等)

2.1 本地存储方法 setLock2Storage
将锁屏前地址写入本地,方便解除锁屏之后恢复
// 将锁屏前地址写入本地,方便解除锁屏之后恢复
const setLock2Storage = (pathName: string) => {
  // store some info in storage
  sessionStorage.setItem('urlBeforeLock', pathName);
};
2.2 关闭现有弹窗方法 clearModals
父组件通过接口将回调函数队列传入此组件,在clearModals方法中依次执行这些回调函数,逐个关闭打开的Modal
clearModals(){
    this.props.clearModals?.forEach(cb => void cb());
  }
2.3 锁屏期间关闭和后端不必要的通信服务的方法 clearWs
clearWs方法显然需要从父组件传递过来,直接调用就可以了:this.props.clearWs();
2.4 导航到前端锁屏路由
使用钩子函数``即可完成任务,对于类组件而言,使用适配器设计模式稍微包装一下即可
this.props.navigate("/lock");
...
// 包装组件
const withNavigation = (Component) => {
  return (props) => <Component {...props} navigate={useNavigate()} />;
};
// 暴露包装后的组件
export default withNavigation(Lock);
2.5 发送消息通知后端更新状态的方法 notify
使用的是fetch方法和URL构造函数
// 通知后端更新锁屏状态
const notify = (apiUrl:string, pathName: string) => {
  // send some info to server
  const requestUrl = new URL('/Lock', apiUrl); 
  const requestBody = {
    params: {
      pathName: pathName
    }
  };

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(requestBody)
  };

  fetch(requestUrl, requestOptions);
};
2.6 功能内聚方法 handleClick(按钮点击函数的回调)
  handleClick() {
    // 将锁屏前的url存到本地,解除锁屏的时候能够恢复到锁屏之间的位置
    setLock2Storage(this.location);
    // 锁屏之前关闭当前页面上的所有弹窗
    this.clearModals();
    // 锁屏之后和有些ws的通信需要关掉,提高性能
    this.props.clearWs();
    // 导航到锁屏
    this.props.navigate("/lock");
    // 向后端发送请求,更新前端状态
    notify(this.appUri, this.location);
  }
三. Lock组件的接口 -- ILockProps
export interface ILockProps {
  cls4style: string; // 父组件为了控制按钮样式传递过来的类名
  navigate: NavigateFunction; // withNavigation钩子函数向props中注入的方法,作用是进行前端跳转
  clearModals: Array<()=>void>; // 清除当前屏幕上的弹窗
  clearWs: ()=>void; // 关闭锁屏之后不需要通信的ws
  notify: ()=>void; // 通知后端更新前端锁屏状态
}
四. Lock组件的参数
  private appUri = 'http://localhost:3000'; // 后端通讯基地址
  private location = location.pathname; // 当前页路由
  private copywriting = "锁屏"; // 按钮上的文案
五. Lock组件依赖库
import React from "react";
import { Tooltip } from "antd"; // 组件
import { useNavigate } from "react-router-dom"; // 前端路由钩子
import { NavigateFunction } from "react-router/dist/lib/hooks"; // 类型约束

六. Lock组件内容 render函数的返回值
  render() {
    return (
      <Tooltip
        title={this.copywriting}
        placement="top"
      >
        <span
          className={this.props.cls4style}
          onClick={this.handleClick}
          style={{width: 100}}
        >
          {this.copywriting}
        </span>
      </Tooltip>
    );
  }
七. Lock组件全部内容
import React from "react";
import { Tooltip } from "antd";
import { useNavigate } from "react-router-dom";
import { NavigateFunction } from "react-router/dist/lib/hooks";

const withNavigation = (Component) => {
  return (props) => <Component {...props} navigate={useNavigate()} />;
};

export interface ILockProps {
  cls4style: string; // 父组件为了控制按钮样式传递过来的类名
  navigate: NavigateFunction; // withNavigation钩子函数向props中注入的方法,作用是进行前端跳转
  clearModals: Array<()=>void>; // 清除当前屏幕上的弹窗
  clearWs: ()=>void; // 关闭锁屏之后不需要通信的ws
  notify: ()=>void; // 通知后端更新前端锁屏状态
}

// 将锁屏前地址写入本地,方便解除锁屏之后恢复
const setLock2Storage = (pathName: string) => {
  // store some info in storage
  sessionStorage.setItem('urlBeforeLock', pathName);
};

// 通知后端更新锁屏状态
const notify = (apiUrl:string, pathName: string) => {
  // send some info to server
  const requestUrl = new URL('/Lock', apiUrl); 
  const requestBody = {
    params: {
      pathName: pathName
    }
  };

  const requestOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(requestBody)
  };

  fetch(requestUrl, requestOptions);
};
class Lock extends React.Component<ILockProps, undefined> {
  private appUri = 'http://localhost:3000'; // 后端通讯基地址
  private location = location.pathname; // 当前页路由
  private copywriting = "锁屏"; // 按钮上的文案
  
  handleClick() {
    // 将锁屏前的url存到本地,解除锁屏的时候能够恢复到锁屏之间的位置
    setLock2Storage(this.location);
    // 锁屏之前关闭当前页面上的所有弹窗
    this.clearModals();
    // 锁屏之后和有些ws的通信需要关掉,提高性能
    this.props.clearWs();
    // 导航到锁屏
    this.props.navigate("/lock");
    // 向后端发送请求,更新前端状态
    notify(this.appUri, this.location);
  }

  clearModals(){
    this.props.clearModals?.forEach(cb => void cb());
  }
  render() {
    return (
      <Tooltip
        title={this.copywriting}
        placement="top"
      >
        <span
          className={this.props.cls4style}
          onClick={this.handleClick}
          style={{display: 'inline-block',  width: '126px'}}
        >
          {this.copywriting}
        </span>
      </Tooltip>
    );
  }
}

export default withNavigation(Lock);

用户评论