wisetc / practice

Practice conclusion
5 stars 0 forks source link

定义 VConsole 唤起组件 #32

Open wisetc opened 4 years ago

wisetc commented 4 years ago

定义 VConsole 唤起组件

背景

将封装好的 VConsole 唤起方法给 App 作为属性调用,当点击页面任意一个位置时,会触发冒泡,也就会引起 App 最外层容器点击事件绑定方法的执行,进而唤起 VConsole。而同时这个封装好的 VConsole 也可以方便的复用于其他的项目。

具体实现

定义 WithConsole 组件,

// WithConsole.js
import React from 'react';
import { feedback, utils } from 'src/lib';

export default function WithConsole(Comp) {
  let isVConsoleImported = false;

  const summon = () => {
    if (isVConsoleImported) return;

    import('vconsole').then(VConsole => {
      isVConsoleImported = true;
      feedback.success('神龙降临..', () => {
        console.log('神龙已降临');
      });

      // @ts-ignore
      new VConsole();
    });
  };

  return props => <Comp {...props} summon={utils.charge(summon)} />;
}

定义蓄能方法 charge

// utils.charge
/**
 * 当每次触发在有效时间间隔内共触发的次数满足条件时,唤起方法,并且重置触发次数。
 * 否则直接重置触发次数。
 * @param {function} func 待唤起的方法
 * @param {number} maxTimes 唤起需要触发的次数
 * @param {number} delay 有效的时间间隔
 */
function charge(func, maxTimes = 5, delay = 500) {
  if (!(Number.isInteger(maxTimes) && maxTimes >= 1)) {
    throw new TypeError('maxTimes type error.');
  }

  let args;
  let ctx;
  let triggeredTimes = 0;
  let timer;
  let result;

  const invoke = () => {
    result = func.apply(ctx, args);
    timer = null;
    triggeredTimes = 0;
  };

  const credit = () => {
    triggeredTimes++;

    clearTimeout(timer);
    timer = setTimeout(shouldInvoke, delay);
  };

  const shouldInvoke = () => {
    if (triggeredTimes >= maxTimes) {
      invoke();
    }

    timer = null;
  };

  const reCredit = () => {
    timer = setTimeout(shouldInvoke, delay);
    triggeredTimes = 1;
  };

  return function charged() {
    args = arguments;
    ctx = this;

    if (timer) {
      credit();
    } else {
      reCredit();
    }

    return result;
  };
}

使用这个 WithConsole 组件,

// App.jsx
// ... import
class App extends Component {
  render() {
    return (
      <div className="App" onClick={this.props.summon}>
        <HashRouter>
            {routes.map((route, i) =>
              route.requiresAuth ? (
                <PrivateRoute key={i} {...route} />
              ) : (
                <Route key={i} {...route} />
              )
            )}
        </HashRouter>
      </div>
    );
  }
}

export default WithConsole(App);

总结

JS function is so good. --- Mark Wang 💯.