likes
comments
collection
share

vue2中怎么更优雅的使用节流,自定义options

作者站长头像
站长
· 阅读数 14

一直以来在vue中写业务代码的时候,使用节流都是像下方这样:

<template>
  <div>
    <img alt="排序" src="./排序.png" @click="handleSortThrottle" />
  </div>
</template>
<script>
import { throttle } from 'lodash';
export default {
  data() {
    return {
      handleSortThrottle: null
    };
  },
  created() {
    this.handleSortThrottle = throttle(this.handleSort, 1000);
  },
  methods: {
    handleSort() {
      //...
    }
  }
};
</script>

如果组件中有多个操作需要进行节流,就会在created中定义多个节流的属性。

这样的写法一直困扰我,不能忍受它的不够优雅。

于是决定抽空来解决这个问题了。

思考

怎样使用才是优雅的方式?首先想到的是自定义节流的方法修饰符(template中使用的)。

像这样:<img @click.throttle="handleSort">

vue好像不能自定义方法或属性的修饰符。并且只能限于template中使用,指定等待时间也不方便。

再来看一下原来使用节流的方式:

// 在created生命周期中
this.handleSortThrottle = throttle(this.handleSort, 1000);

那么有没有办法不在created中做这一步呢?或者说有没有办法自动在created中做这些事情,只需要定义好哪些方法需要做节流,以及这些方法的节流时间。

使用自定义options

<template>
  <div>
    <img alt="排序" src="./排序.png" @click="handleSort" />
  </div>
</template>
<script>
import { throttle } from 'lodash';
export default {
  data() {
    return {
      handleSortThrottle: null
    };
  },
  // 最好放在methods选项上方,数组中每一项是要进行节流的方法
  throttles: ['handleSort'],
  methods: {
    handleSort() {
      //...
    }
  }
};
</script>

上面在组件中去掉了created,并且<img>中的click的处理方法也换成了methods中的handleSort

现在来看一下怎么去实现throttles这个自定义option。

import { throttle } from 'lodash';

export default function install(Vue) {
  Vue.mixin({
    // 在属性没有解析前拿到所有option
    beforeCreate() {
      const { throttles, methods } = this.$options;
      if (!throttles?.length) return;
      throttles.forEach(methodName => {
        if (typeof methodName !== 'string') return;
        let wait;
        // methodName支持使用|来指定等待的时间,如:handleSort|3000
        [methodName, wait = 1000] = methodName.split('|');
        const method = methods[methodName];
        if (!method) return;
        // 最重要的一步:使用节流后的方法去替换原来的方法,那样在组件中使用的就是节流后的方法了。
        methods[methodName] = throttle(method, wait);
      });
    }
  });
}

上面的自定义option就完成了。但如果这个throttles选项是用在mixin中的那就可能出问题了,因为每个option都要定义合并规则,默认是使用组件本身的选项。

现在来给这个自定义option实现合并策略。

export default function install(Vue) {
  // Vue.config.optionMergeStrategies 存放vue组件中所有option的合并规则
  // 现在给optionMergeStrategeis中添加一个throttles的选项的合并策略
  // prev是mixin中的throttles选项,cur是组件中throttles选项
  Vue.config.optionMergeStrategies.throttles = (prev, cur) => {
    if (!prev) return cur;
    if (!cur) return prev;
    // 若mixin和组件中都定义了同一方法的节流方案,则使用组件的
    // 组件中所有进行节流的方法
    const methodNames = cur.map(methodName => {
      [methodName] = methodName.split('|');
      return methodName;
    });
    return cur.concat(
      prev.filter(methodName => {
        [methodName] = methodName.split('|');
        return !methodNames.includes(methodName);
      })
    );
  };
  // 上面写过的创建全局mixin,这里省略
  Vue.mixin({ ... });
}

然后,在main.js文件中引入这个install方法,使用Vue.use()即可。

至此,一个根据时间节流的自定option方案就完成的。

更多思考与完善

仅仅是代码使用优雅吗?

能否通过自定义throttles选项做更多呢?

节流一般是按时间来做的,有时需要的是等待上一次操作完成或失败后才允许下一次操作,这里大家自己去修改完成吧。

转载自:https://juejin.cn/post/7270912365166886966
评论
请登录