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 相关文章推荐
JQuery 确定css方框模型(盒模型Box Model)
Jan 22 Javascript
js 数据类型转换总结笔记
Jan 17 Javascript
如何用ajax来创建一个XMLHttpRequest对象
Dec 10 Javascript
浅谈JavaScript之事件绑定
Jul 08 Javascript
html dom节点操作(获取/修改/添加或删除)
Jan 23 Javascript
js控制文本框禁止输入特殊字符详解
Apr 07 Javascript
详解使用angular的HttpClient搭配rxjs
Sep 01 Javascript
Vue结合SignalR实现前后端实时消息同步
Sep 19 Javascript
如何能分清npm cnpm npx nvm
Jan 17 Javascript
JS中的函数与对象的创建方式
May 12 Javascript
基于Fixed定位的框选功能的实现代码
May 13 Javascript
微信小程序 拍照或从相册选取图片上传代码实例
Aug 28 Javascript
基于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
SONY ICF-SW07收音机电路分析
2021/03/02 无线电
PHP取进制余数函数代码
2012/01/19 PHP
通过php删除xml文档内容的方法
2015/01/23 PHP
php使用mysqli和pdo扩展,测试对比连接mysql数据库的效率完整示例
2019/05/09 PHP
在Laravel中实现使用AJAX动态刷新部分页面
2019/10/15 PHP
用C/C++来实现 Node.js 的模块(二)
2014/09/24 Javascript
javascript实现画不相交的圆
2015/04/07 Javascript
jQuery实现tab选项卡效果的方法
2015/07/08 Javascript
基于vue.js路由参数的实例讲解——简单易懂
2017/09/07 Javascript
vue中配置mint-ui报css错误问题的解决方法
2017/10/11 Javascript
vue二级路由设置方法
2018/02/09 Javascript
js实现控制文件拖拽并获取拖拽内容功能
2018/02/17 Javascript
jQuery无冲突模式详解
2019/01/17 jQuery
基于vue如何发布一个npm包的方法步骤
2019/05/15 Javascript
利用node 判断打开的是文件 还是 文件夹的实例
2019/06/10 Javascript
layui 上传插件 带预览 非自动上传功能的实例(非常实用)
2019/09/23 Javascript
JavaScript 严格模式(use strict)用法实例分析
2020/03/04 Javascript
vue el-upload上传文件的示例代码
2020/12/21 Vue.js
Python实现类似jQuery使用中的链式调用的示例
2016/06/16 Python
python merge、concat合并数据集的实例讲解
2018/04/12 Python
python线程池threadpool使用篇
2018/04/27 Python
Django中使用Celery的方法示例
2018/11/29 Python
解决Django中多条件查询的问题
2019/07/18 Python
Python3.6实现根据电影名称(支持电视剧名称),获取下载链接的方法
2019/08/26 Python
浅谈Python类中的self到底是干啥的
2019/11/11 Python
python实现在一个画布上画多个子图
2020/01/19 Python
电信专业应届生自荐信
2013/09/28 职场文书
应届毕业生自我评价分享
2013/12/15 职场文书
面料业务员岗位职责
2013/12/26 职场文书
爸爸的花儿落了教学反思
2014/02/20 职场文书
如何写自我评价?自我评价写什么好?
2014/03/14 职场文书
公司保密承诺书
2014/03/27 职场文书
如何写好自荐信
2014/04/07 职场文书
大学生评语大全
2014/04/18 职场文书
oracle DGMGRL ORA-16603报错的解决方法(DG Broker)
2021/04/06 Oracle
Nginx 配置 HTTPS的详细过程
2022/05/30 Servers