用 customRef 做一个防抖函数,支持 element 等UI库。
这几天学习Vue的官网,看到 customRef 提供了一个例子,研究半天发现这是一个防抖函数,觉得挺好,于是把这个例子扩展了一下,可以用于表单子控件和查询子控件。
需求
v-model
基于 element-plus 封装表单控件,同时也要封装一下表单子控件,还有查询控件。
由于 el-input 这类的组件,把 value 封装成了 v-model,所以无法把组件的属性直接设置给内部的 el-input。
必须在内部设置一个变量,然后做“属性” <==> “变量” 的转换。
这样就比较麻烦,需要一个既优雅又实用的方式来解决。查询的防抖
查询的时候,理想情况是用户输入一个完整的查询条件,然后自动去后端申请查询,但是vue默认的响应形式是,输入一个字符就会响应,如果立即去后端查询的话,会造成浪费的情况,另外用户体验也不好。
如果用change事件,那么用户输入完毕,还得在其他的地方点一下,比较麻烦。
所以需要一个简单的方式,比如防抖功能来优化用户体验。
设计
用 customRef (自定义的ref)设计get 和 set。
- get:获取组件属性,返回给内部组件,比如 el-input。
- set:用smit提交给父组件。
- settimeout:实现防抖。
实施验证
想法挺好的,演示为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)
}
}
})
}
- 参数
- props: 组件的属性,便于属性值变更的时候可以获得最新值。
- context 组件的上下文,方便向父组件提交。
- name:v-model的名称,默认是 modelValue。
- delay:延迟时间,默认是0。
value:内部变量,用于初始值和用户输入的时候的绑定。
let timeout:定时器,便于清掉之前的定时。
let isInput = false
用户的输入状态,如果用户处于敲键盘的状态,那么获取内部的 value 绑定到 el-inupt;
如果用户没有敲键盘,那么获取父组件的属性值,绑定到 el-inupt。
为啥要这么设置呢?没办法,如果直接获取组件的属性值的话,那么会出现延迟的情况,如果获取内部 value 的话,父组件的属性变化的时候,内部 el-input 不会有变化,所以只好这么折腾一下。
后面的就是常规操作了,get 里面根据状态获取属性和 value,set 里面向父组件提交。
使用
setup (props, context) {
const value = debounceRef(props, context)
return {
value
}
}
<el-input v-model="value"></el-input>
基本上和普通的 ref 很像,只是需要设置组件的属性和上下文。
- 如果名称不是默认的 modelValue 的话,需要传递名称;
- 如果需要延迟响应的话,需要设置延迟时间,默认是不延迟的。
缺点:
灵活性欠佳,只是针对一个特定需求封装的,没有考虑更多的情况。其他情况在写个函数好了,函数要符合原子性,不要承担太多的职责。
还是要传递属性和上下文,这个也没啥办法省略。
CheckBox又不支持延迟了。记得之前好用的。。。
优点:
- 自我感觉还是比较优雅的。
用 customRef 做一个防抖函数,支持 element 等UI库。的更多相关文章
- JS节流和防抖函数
一. 实现一个节流函数 // 思路:在规定时间内只触发一次function throttle (fn, delay) { // 利用闭包保存时间 let prev = Date.now() re ...
- 做一个牛XX的身份证号验证类(支持15位和18位)
原文:做一个牛XX的身份证号验证类(支持15位和18位) #region 是否合法的中国身份证号码 protected bool IsChineseID() { if (str.Length == 1 ...
- 告别收费BI!如何自己动手做一个免费的可视化数据报表还支持文档在线预览?
本人大学刚毕业目前在一家互联网公司从事产品运营工作,一季度刚过,公司需要我出一份产品运营数据报表,由于产品用户数据.订单数据等数据量太大,我希望找一款Bi产品,支持我做出一个精美的可视化报表,还可以让 ...
- vue-cli3和element做一个简单的登陆页面
1.先用vue-cli3创建一个项目 2.安装element模块 全局安装 npm i element-ui -S 3在main.js引入模块 import ElementUI from 'eleme ...
- [转]jsPlumb插件做一个模仿viso的可拖拉流程图
原贴:https://www.cnblogs.com/sggx/p/3836432.html 前言 这是我第一次写博客,心情还是有点小小的激动!这次主要分享的是用jsPlumb,做一个可以给用户自定义 ...
- 4-13 Webpacker-React.js; 用React做一个下拉表格的功能: <详解>
Rails5.1增加了Webpacker: Webpacker essentially is the decisions made by the Rails team and bundled up i ...
- 【Qt】2.4 做一个“猜数字”的游戏
使用对话框和Qt设计师来实现一个相当简单的小游戏.同时将通过这个程序来看布局的隐藏和显示是如何来影响窗口界面的变化的. 新建一个Qt项目,把Qt Creator默认给的mainwindow.h.mai ...
- 如何实现一个malloc函数
一.概述 1.malloc简介 函数所在头文件:<stdlib.h> 函数原型是:void *malloc (size_t n) 函数功能:在内存的动态存储区中分配一个长度为size的连续 ...
- 又见angular----步一步做一个angular4小项目
这两天看了看angular4的文档,发现他和angular1.X的差别真的是太大了,官方给出的那个管理英雄的Demo是一个非常好的入门项目,这里给出一个管理个人计划的小项目,从头至尾一步一步讲解如何去 ...
随机推荐
- eyes protect app
eyes protect app https://awaremac.com/
- Taro 物料市场
Taro 物料市场 taro component demo https://taro-ext.jd.com/ https://taro-ext.jd.com/plugin/view/5caab6c68 ...
- nasm astrrchr函数 x86
xxx.asm %define p1 ebp+8 %define p2 ebp+12 %define p3 ebp+16 section .text global dllmain export ast ...
- webpack + ts 配置路径别名无死角方法总结
webpack + ts 配置路径别名总结 自我体验加总结:在配置脚手架时,定制别名很有必要,可以使得代码更优雅,可读性更强.但在使用ts的时候,即便项目能够运行,vscode 确时长会提示 can' ...
- 刚学会 C++ 的小白用这个开源框架,做个 RPC 服务要多久?
本文适合有 C++ 基础的朋友 本文作者:HelloGitHub-Anthony HelloGitHub 推出的<讲解开源项目>系列,本期介绍基于 C++ 的 RPC 开源框架--rest ...
- 两个"�"="锟斤拷"?
关于作者:程序猿石头(ID: tangleithu),现任阿里巴巴技术专家,清华学渣,前大疆后端 Leader.欢迎关注,交流和指导! 本文首发于微信公众号,原文链接,转载请全文保留. 以一首七言绝句 ...
- 力扣832. 翻转图像-C语言实现-简单题
题目 传送门 文本 给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果. 水平翻转图片就是将图片的每一行都进行翻转,即逆序.例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, ...
- HashMap什么时候进行扩容?
Threshold:table数组元素个数size的大小超过threshold且且Node<K,V>[] table数组长度没有超过64时时table数组扩容.当hashmap中的元素个数 ...
- 按照阿里巴巴规范创建Java线程池
前言 Executors Executors 是一个Java中的工具类.提供工厂方法来创建不同类型的线程池. 常用方法: 1.newSingleThreadExecutor 介绍:创建一个单线程的 ...
- Guava-RateLimiter实现令牌桶控制接口限流方案
一.前言 对于一个应用系统来说,我们有时会遇到极限并发的情况,即有一个TPS/QPS阀值,如果超了阀值可能会导致服务器崩溃宕机,因此我们最好进行过载保护,防止大量请求涌入击垮系统.对服务接口进行限流可 ...