1. 项目实现介绍
vue
项目搭建参考《Webpack4 搭建 Vue 项目》
文档使用 vuepress
, 官方文档 https://vuepress.vuejs.org
发布文档 github pages
+ gh-page
项目地址 https://github.com/zxpsuper/vui-vue/** * @param {function} func 执行函数 * @param {number} time 防抖节流时间 * @param {boolean} isDebounce 是否为防抖组件 * @param {this} ctx this 的指向 */ const debounce = (func, time, isDebounce, ctx) => { var timer, lastCall, rtn; if (isDebounce) { rtn = (...params) => { if (timer) clearTimeout(timer); timer = setTimeout(() => { func.apply(ctx, params); }, time); }; } else { rtn = (...params) => { const now = new Date().getTime(); if (now - lastCall < time && lastCall) return; lastCall = now; func.apply(ctx, params); }; } return rtn; };
- 使用抽象组件
export default {
name: 'Throttle',
abstract: true,
props: {
time: {
type: Number,
default: 800,
},
events: {
type: String,
default: 'click',
},
isDebounce: {
type: Boolean,
default: false,
},
},
created() {
this.eventKeys = this.events.split(','); // 分隔事件
this.originMap = {}; // 储存事件,用于重新render时与子事件的对比
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,
this.isDebounce,
vnode
);
vnode.data.on[key] = this.debouncedMap[key]; // 重写子组件的事件
}
});
return vnode;
},
};
3. 使用组件
需全局或者组件内注册一下,这里只展示全局注册代码:
Vue.component("Throttle", Throttle);
使用方法:
4. 存在问题与解决方法
当页面元素在防抖节流时间内发生了更新(渲染)(可以用定时器修改页面,如页面倒计时),那么此组件会重新执行一遍
this.debouncedMap[key] = debounce(target,this.time,this.isDebounce,vnode);
导致防抖节流失效,目前的解决方法是在此组件的子元素添加 v-once
,如下:
可解决此问题,有更好的方法请在评论区留言
5. 完整代码
/*
* @descript: 防抖节流组件,前提是页面在等待时间内无其他渲染方可使用,重新渲染导致 debounce() 函数不断重置
* @Author: super
* @Date: 2019-04-09 14:21:18
* @Last Modified by: super
* @Last Modified time: 2019-10-24 16:37:43
*/
const debounce = (func, time, isDebounce, ctx) => {
var timer, lastCall, rtn;
if (isDebounce) {
rtn = (...params) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
func.apply(ctx, params);
}, time);
};
} else {
rtn = (...params) => {
const now = new Date().getTime();
if (now - lastCall < time && lastCall) return;
lastCall = now;
func.apply(ctx, params);
};
}
return rtn;
};
export default {
name: 'Throttle',
abstract: true,
props: {
time: {
type: Number,
default: 800,
},
events: {
type: String,
default: 'click',
},
isDebounce: {
type: Boolean,
default: false,
},
},
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,
this.isDebounce,
vnode
);
vnode.data.on[key] = this.debouncedMap[key];
}
});
return vnode;
},
};
总结
本文是对render及抽象组件的使用总结,若有错误,望指出共同进步。
更多推荐
前端进阶小书(advanced_front_end)
前端每日一题(daily-question)
webpack4 搭建 Vue 应用(createVue)
Canvas 进阶(一)二维码的生成与扫码识别
Canvas 进阶(二)写一个生成带logo的二维码npm插件
Canvas 进阶(三)ts + canvas 重写”辨色“小游戏
Canvas 进阶(四)实现一个“刮刮乐”游戏
VUI创建日志(一)——图片懒加载指令的实现