这几天学习Vue的官网,看到 customRef 提供了一个例子,研究半天发现这是一个防抖函数,觉得挺好,于是把这个例子扩展了一下,可以用于表单子控件和查询子控件。
用 customRef (自定义的ref)设计get 和 set。
想法挺好的,演示为0的时候也是好用的,但是把延迟设为200的时候确出现问题,首先是 el-input 的字符显示也一起延迟了,另外只会显示最后一个字符,中间的字符都被吃掉了。
这是怎么回事?用html5的 input 试验的时候是没有问题的呀。
办法重臂困难多,几经修改之后终于好用了。
/**
* 自定义的ref,实现属性和内部变量的数据转换
* @param { reactive } props 组件的属性
* @param { object } context 组件的上下文
* @param { number } delay 延迟刷新的时间,单位:毫秒,默认:0
* @param { string } name 要对应的属性名称,默认:modelValue
* @returns 自定义的ref
*/
export const debounceRef = (props, context, delay = 0, name = 'modelValue') => {
let value = props[name]
// 计时器
let timeout
// 是否输入状态。输入时取 value;输入完毕取 modelValue 属性
let isInput = false
return customRef((track, trigger) => {
return {
get () {
track()
if (isInput) {
return value
} else {
return props[name]
}
},
set (newValue) {
isInput = true
value = newValue // 绑定值
trigger() // 组件内部刷新模板
clearTimeout(timeout) // 清掉上一次的计时
timeout = setTimeout(() => {
// 修改 modelValue 属性
context.emit(`update:${name}`, newValue) // 提交给父组件
// 用于区分是哪个组件触发的事件。
context.emit('my-change', newValue, props.controlId, props.colName)
isInput = false
}, delay)
}
}
})
}
为啥要这么设置呢?没办法,如果直接获取组件的属性值的话,那么会出现延迟的情况,如果获取内部 value 的话,父组件的属性变化的时候,内部 el-input 不会有变化,所以只好这么折腾一下。
后面的就是常规操作了,get 里面根据状态获取属性和 value,set 里面向父组件提交。
setup (props, context) {
const value = debounceRef(props, context)
return {
value
}
}
<el-input v-model="value"></el-input>
基本上和普通的 ref 很像,只是需要设置组件的属性和上下文。