未加星标

Vue实现函数防抖组件

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二05 | 时间 2019 | 作者 红领巾 ] 0人收藏点击收藏

最近在掘金看到两篇非常不错的文章:

以vue组件或者插件的形式,实现throttle或者debounce 奇技淫巧 - Vue Mixins 高级组件 与 Vue HOC 高阶组件 实践

这两篇文章中作者都分享了关于把函数防抖/函数节流包装成通用组件的经验。

在这里我就不介绍函数防抖/函数节流的概念了,将这样的功能封装是组件真的是非常实用。

通过HOC(高阶组件)的方式进行封装的思路我也很喜欢,这里也想分享一个类似的封装方法

抽象组件

这里我使用了 abstract: true 来创建一个抽象组件。

我们常用的 transition 和 keep-alive 就是一个抽象组件。抽象组件是无状态的,同样也是“不存在的”,它自己并不会被渲染为实际的DOM,而是直接返回以及操作它的子元素。

例如对于模板( Debounce 是一个抽象组件):

<Debounce> <button>123</button> </Debounce> 复制代码

会被渲染成:

<button>123</button> 复制代码 实现

这里直接贴出组件代码:

const debounce = (func, time, ctx) => { let timer const rtn = (...params) => { clearTimeout(timer) timer = setTimeout(() => { func.apply(ctx, params) }, time) } return rtn } Vue.component('Debounce', { abstract: true, props: ['time', 'events'], created () { this.eventKeys = this.events.split(',') this.originMap = {} this.debouncedMap = {} }, render() { const vnode = this.$slots.default[0] this.eventKeys.forEach((key) => { const target = vnode.data.on[key] if (target === this.originMap[key] && this.debouncedMap[key]) { vnode.data.on[key] = this.debouncedMap[key] } else if (target) { this.originMap[key] = target this.debouncedMap[key] = debounce(target, this.time, vnode) vnode.data.on[key] = this.debouncedMap[key] } }) return vnode }, }) 复制代码

Debounce 组件会接受 time 和 events (用逗号分隔)的两个参数。

在 render 函数中, Debounce 组件修改了子VNode的事件,再将其返回回去。

使用

然后我们来使用一下:

<div id="app"> <Debounce :time="1000" events="click"> <button @click="onClick($event, 1)">click+1 {{val}}</button> </Debounce> <Debounce :time="1000" events="click"> <button @click="onClick($event, 2)">click+2 {{val}}</button> </Debounce> <Debounce :time="1000" events="mouseup"> <button @mouseup="onAdd">click+3 {{val}}</button> </Debounce> <Debounce :time="1000" events="click"> <button @mouseup="onAdd">click+3 {{val}}</button> </Debounce> </div> 复制代码 const app = new Vue({ el: '#app', data () { return { val: 0, } }, methods: { onClick ($ev, val) { this.val += val }, onAdd () { this.val += 3 } } }) 复制代码 使用指令

使用自定义指令也是一种思路,不过指令的bind发生在 created 的回调中,也就是晚于事件的初始化的,这样的话就不能通过修改 vnode.data.on 来改变绑定的事件回调,只能自己来绑定事件了:

Vue.directive('debounce', { bind (el, { value }, vnode) { const [target, time] = value const debounced = debounce(target, time, vnode) el.addEventListener('click', debounced) el._debounced = debounced }, destroy (el) { el.removeEventListener('click', el._debounced) } }) 复制代码

这里要注意的一点是,指令 binding.value 的求值过程和事件绑定是不同的,并不支持 onClick($event, 2) 的写法,因此如果这样的绑定就只能再包一层了:

<button v-debounce="[($ev) => { onClick($ev, 4) }, 500]">click+4 {{val}}</button> 复制代码 小结

使用抽象组件的好处是提高了组件的通用性,不会因为组件的使用而污染DOM(添加并不想要的div标签等)、可以包裹任意的单一子元素,当然也有缺点,比如使用时要注意子元素只能包含一个根,使用起来也比较Up嗦(参考文章中 ButtonHoc 在使用时更简洁一些,但相应的是只能作为 Button 渲染)。

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

分页:12
转载请注明
本文标题:Vue实现函数防抖组件
本站链接:https://www.codesec.net/view/628486.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(19)