vue自定义指令实现仅支持输入数字和浮点型的示例


Posted in Javascript onOctober 30, 2019

再开始本篇的讨论之前,先思考几个问题:

使用html元素属性type='number'是否可以满足要求

Vue中指令一般被设计用来操作dom元素的,而vue视图是基于数据模型的,如何在操作dom的同时,同时更新数据

你定义的指令不能只能在input元素上使用,还要支持在其父元素上使用,自定义组件及第三方组件上使用

你的指令是不是支持局部作用域,比如for循环渲染的数据的单元item,如何识别这个item进行数据更新和dom操作

如何控制字符数目,超出禁止输入

如何实现全局性的功能定义,从而在各个子组件中灵活使用

还有没有别的优化替代方案

问题思考

可以肯定的是,针对方案1,答案是:可以。很明显,它只会作为我们此次讨论的一个噱头罢了!为什么呢?因为这种处理方案有兼容性,不说别的,拿谷歌和火狐浏览器对比来看:谷歌浏览器表现堪称完美,而火狐浏览器表现就狠差强人意。而且会衍生出各种各样的问题。这里不再赘述,有兴趣的可以自己试试看

针对方案6,不是本次讨论的重点,但是思路方向很重要。比如使用vue的状态管理机制库vuex来解决这个数据流转的问题是不是可以!这里只是一个方向,感兴趣的同学可以去调研一下。

实现方案

Vue允许我们来定义全局指令,从而在各个子组件中使用。那我问题6我们解决了。那关键是如何实现问题2-5以及其相关的技术问题。比如我们定义指令onlyNum。

1.1 指令宿主

我们在使用指令时,指令的宿主元素不一定是input本身,也有可能使其父级或父级以上元素。那么我们如何来识别?

// 只能输入整数
onlyNum (el,binding,vnode) {
  let ele = el.tagName === 'INPUT' ? el : el.querySelector('input')
  ele.oninput = function() {
   //获取相关的指令配置信息
   let rel = vnode.data.directives.filter(item =>{
    return item.name === "only-num"
   })[0]
   vnode.context.$nextTick(()=>{
    handleInput(ele,vnode,rel)
   })
  }
}

如上所示,我们看到了一个el的参数,它是:指令所绑定的元素,可以用来直接操作 DOM。那么我们也就能通过这样一个宿主元素找到它下边的input元素了,从而不必关心当前是不是input元素不重要,who care!然后我们通过处理事件函数input,来开始操作dom和数据了。

1.2 捕捉指令配置内容

我们会在同一个宿主元素上绑定一个或者多个指令,但是,如何找到当前指令的配置呢?上如定义了一个rel的变量,返回了指令onlyNum的所有配置信息。

vue自定义指令实现仅支持输入数字和浮点型的示例

1.3 数据更新如何与dom更新同步

由于vue的数据渲染是异步的。因此当数据更新后,页面dom并不一定就会按照我们期望的那样来渲染。好在vue里提供了一套处理机制。

vue自定义指令实现仅支持输入数字和浮点型的示例

虚拟节点vnode参数中有一个上下文对象context,它用来表示宿主对象所在的组件对象。那么借助$nextTick就可以实现数据更新后,dom跟着渲染。

1.4 使用指令配置控制数据

/**
 * [handleInput 在输入阶段的处理逻辑]
 * @param {[DOM]} ele  [当前指令操作的dom对象]
 * @param {[虚拟节点]} vnode [当前指令渲染的虚拟节点]
 * @param {[指令信息]} rel  [当前指令的所有指令信息]
 * @param {[校验类型]} type [输入阶段的校验类型]
 *   "number": 仅支持输入数字
 *   "float": 仅支持数字和小数点
 */
function handleInput(ele,vnode,rel){
 let rule;
 switch(true) {
  case rel.modifiers.float: // 浮点型
   rule = /[^\d\.]/g; break;
  default: //默认仅支持输入数字
   rule = /\D/g;
 }
 let val = ele.value.replace(rule,"");
 let maxLen = vnode.data.attrs && vnode.data.attrs['max-len'] ? vnode.data.attrs['max-len'] :0;
 if(maxLen>0){val = val.substr(0,maxLen)}
 setValueWithExpressionVue({
  currObj:vnode.context.$data,
  expression:rel.expression,
  value:val,
  key:vnode.key,
  arg:rel.arg,
  toString:rel.modifiers.string || rel.modifiers.float
 })
}

从上边截图,可以看出,目前为该指令赋予了以下功能:

支持纯数字,浮点型,字符串类型数字3种格式,必要时可以自定义扩充

支持最大字符数控制,超出禁止输入

支持数据作用域的灵活处理(主要针对类似for循环这种渲染操作)

更多功能完善中……

截图红框里的内容可以参照3.2指令配置项来理解。关于属性的配置,借助了虚拟dom节点里的data.attr属性。

1.5 数据更新和dom更新

/**
 * [setValueWithExpressionVue 更新数据模型]
 * @param {Boolean} toString  [是否转化为字符串]
 * @param {[type]} currObj  [当前的数据模型]
 * @param {[type]} expression [指令表达式]
 * @param {[type]} value   [指令的值]
 * @param {[type]} key    [用于批量渲染时的跟踪键]
 * @param {[type]} arg    [指令的参数]
 */
function setValueWithExpressionVue (option) {
 let expression = option.expression.split('.')
 expression.forEach(function (item, i) {
 if (i < expression.length - 1) {
  option.currObj = option.currObj[item]
 } else {
  if(option.key !== undefined){
   option.currObj[item][option.key][option.arg] = (option.value === "" || option.toString) ? option.value : option.value*1
  }else{
   option.currObj[item] = (option.value === "" || option.toString) ? option.value : option.value*1
  }
 }
 })
}

我们知道,我们绑定的数据的层级可能为1级数据直接绑定,如:v-only-num=”age”,也有可能是多层级的,如:v-only-num=”obj.info.age”,也有可能是局部作用域的,如for循环渲染的数据:v-only-num=”item.age”……

‘i < expression.length - 1'是针对情景1做出的处理方案

‘option.key !== undefined'是针对情景3做出的处理方案,注意此时有个key。这个key很重要,是为了追踪for循环的渲染,从而在进行数据更新时,捕获你想要更新数据的那一项。

其余是针对情景2做出的处理方案

如何使用

基于以上实现的指令onlyNum,可以轻松实现以下情景的处理。

以element-ui文本框为例:

仅数字(如:输入09,会自动变成9)

<el-input v-only-num="info.age" v-model="info.age"></el-input>

仅数字,显示8位数以内(如:输入09,会自动变成9)

<el-input v-only-num="info.age" v-model="info.age" :max-len=”8”></el-input>

字符型数字(如:输入09,不会自动变成9)

<el-input v-only-num.string="info.tel" v-model="info.tel"></el-input>

浮点型数据(支持数字和小数点的混合输入)

<el-input v-only-num.float="info.tel" v-model="info.tel"></el-input>

Fro循环产生的局部作用域

vue自定义指令实现仅支持输入数字和浮点型的示例

Element -ui等第三方的局部作用域

vue自定义指令实现仅支持输入数字和浮点型的示例

注意事项

以上处理方案基于vue2.0及以上版本

在使用上述指令时,第三方的指令或者vue本省的指令修饰符不要使用,比如下边

<el-input v-model="param.productId" v-only-num.trim="param.productId"></el-input>

这会带出来一些意想不到的奇葩问题。因为指令的修饰符可以并列使用1至多个。除非你对vue的源码灰常熟悉。

指令使用时,尽量单一。指定的属性和配置要用到指定的场景,不要嵌套使用。否则发生问题了不好聚焦

以上这篇vue自定义指令实现仅支持输入数字和浮点型的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
(JS实现)MapBar中坐标的加密和解密的脚本
May 16 Javascript
Ext JS Grid在IE6 下宽度的问题解决方法
Feb 15 Javascript
Jsonp 跨域的原理以及Jquery的解决方案
May 18 Javascript
两种方法实现文本框输入内容提示消失
Mar 17 Javascript
JavaScript闭包详解
Feb 02 Javascript
JS实现点击按钮获取页面高度的方法
Nov 02 Javascript
MVC Ajax Helper或Jquery异步加载部分视图
Nov 29 Javascript
ng-events类似ionic中Events的angular全局事件
Sep 05 Javascript
微信小程序获取用户信息并保存登录状态详解
May 10 Javascript
Vue中的transition封装组件的实现方法
Aug 13 Javascript
vue 实现cli3.0中使用proxy进行代理转发
Oct 30 Javascript
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
Feb 23 Vue.js
基于Vue中使用节流Lodash throttle详解
Oct 30 #Javascript
Vue最新防抖方案(必看篇)
Oct 30 #Javascript
vue输入节流,避免实时请求接口的实例代码
Oct 30 #Javascript
vue 解决form表单提交但不跳转页面的问题
Oct 30 #Javascript
解决在Vue中使用axios用form表单出现的问题
Oct 30 #Javascript
vue路由 遍历生成复数router-link的例子
Oct 30 #Javascript
vue表单中遍历表单操作按钮的显示隐藏示例
Oct 30 #Javascript
You might like
第六节 访问属性和方法 [6]
2006/10/09 PHP
php的POSIX 函数以及进程测试的深入分析
2013/06/03 PHP
分享下页面关键字抓取components.arrow.com站点代码
2014/01/30 PHP
PHP中strlen()和mb_strlen()的区别浅析
2014/06/19 PHP
Use Word to Search for Files
2007/06/15 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
Extjs4中tree的拖拽功能(可以两棵树之间拖拽) 简单实例
2013/12/08 Javascript
jquery中html、val与text三者属性取值的联系与区别介绍
2013/12/29 Javascript
Jquery元素追加和删除的实现方法
2016/05/24 Javascript
关于function类中定义变量this的简单说明
2016/05/28 Javascript
easyUI combobox实现联动效果
2017/01/17 Javascript
一个简易的js图片轮播效果
2017/07/22 Javascript
C#实现将一个字符转换为整数
2017/12/12 Javascript
Vue传参一箩筐(页面、组件)
2019/04/04 Javascript
vue 对象添加或删除成员时无法实时更新的解决方法
2019/05/01 Javascript
js计算最大公约数和最小公倍数代码实例
2019/09/11 Javascript
你不可不知的Vue.js列表渲染详解
2019/10/01 Javascript
vue基于v-charts封装双向条形图的实现代码
2019/12/09 Javascript
如何修改Vue打包后文件的接口地址配置的方法
2020/04/22 Javascript
jquery实现加载更多&quot;转圈圈&quot;效果(示例代码)
2020/11/09 jQuery
python根据距离和时长计算配速示例
2014/02/16 Python
Python是编译运行的验证方法
2015/01/30 Python
使用python实现省市三级菜单效果
2016/01/20 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
2019/05/15 Python
numpy下的flatten()函数用法详解
2019/05/27 Python
python中的split()函数和os.path.split()函数使用详解
2019/12/21 Python
django数据模型(Model)的字段类型解析
2019/12/25 Python
Python解析多帧dicom数据详解
2020/01/13 Python
美国婴儿和儿童家具网上商店:ABaby.com
2018/07/02 全球购物
Nike法国官方网站:Nike.com FR
2018/07/22 全球购物
英国领先的在线礼品店:Getting Personal
2019/09/24 全球购物
工厂仓管员岗位职责
2014/01/01 职场文书
合作协议书格式范本
2016/03/21 职场文书
springboot+VUE实现登录注册
2021/05/27 Vue.js
利用 SQL Server 过滤索引提高查询语句的性能分析
2021/07/15 SQL Server
SpringCloud之@FeignClient()注解的使用方式
2021/09/25 Java/Android