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 相关文章推荐
javascript下string.format函数补充
Aug 24 Javascript
jQuery操作select下拉框的text值和value值的方法
May 31 Javascript
JavaScript数值转换的三种方式总结
Jul 31 Javascript
js动态生成Html元素实现Post操作(createElement)
Sep 14 Javascript
JS实现带有抽屉效果的产品类网站多级导航菜单代码
Sep 15 Javascript
原生JS轮播图插件
Feb 09 Javascript
深入理解vue.js中的v-if和v-show
Jun 22 Javascript
微信小程序中使用ECharts 异步加载数据实现图表功能
Jul 13 Javascript
VUE-Table上绑定Input通过render实现双向绑定数据的示例
Aug 27 Javascript
vue实现路由切换改变title功能
May 28 Javascript
vue项目中引入Sass实例方法
Aug 27 Javascript
Vue解析剪切板图片并实现发送功能
Feb 04 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
thinkphp跨库操作的简单代码实例
2016/09/22 PHP
微信公众号开发客服接口实例代码
2016/10/21 PHP
laravel5.1框架model类查询的实现方法
2019/10/08 PHP
JS 的应用开发初探(mootools)
2009/12/19 Javascript
事件绑定之小测试  onclick &amp;&amp; addEventListener
2011/07/31 Javascript
jQuery EasyUI API 中文文档 - Dialog对话框
2011/11/15 Javascript
jQuery 过滤not()与filter()实例代码
2012/05/10 Javascript
JavaScript等比例缩放图片控制超出范围的图片
2013/08/06 Javascript
js去空格技巧分别去字符串前后、左右空格
2013/10/21 Javascript
用Jquery实现滚动新闻
2014/02/12 Javascript
JavaScript实现更改网页背景与字体颜色的方法
2015/02/02 Javascript
JS实现弹性菜单效果代码
2015/09/07 Javascript
JS实现黑色大气的二级导航菜单效果
2015/09/18 Javascript
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
vue-loader教程介绍
2017/06/14 Javascript
vue-cli3+ts+webpack实现多入口多出口功能
2019/05/30 Javascript
详解简单易懂的 ES6 Iterators 指南和示例
2019/09/24 Javascript
详解Python中__str__和__repr__方法的区别
2015/04/17 Python
在Python的Flask中使用WTForms表单框架的基础教程
2016/06/07 Python
python实现unicode转中文及转换默认编码的方法
2017/04/29 Python
python读取二进制mnist实例详解
2017/05/31 Python
基于循环神经网络(RNN)的古诗生成器
2018/03/26 Python
Python实现爬取百度贴吧帖子所有楼层图片的爬虫示例
2018/04/26 Python
钉钉群自定义机器人消息Python封装的实例
2019/02/20 Python
python自动发邮件总结及实例说明【推荐】
2019/05/31 Python
opencv转换颜色空间更改图片背景
2019/08/20 Python
Python操作注册表详细步骤介绍
2020/02/05 Python
Keras: model实现固定部分layer,训练部分layer操作
2020/06/28 Python
CSS3 text-shadow实现文字阴影效果
2016/02/24 HTML / CSS
canvas实现烟花的示例代码
2020/01/16 HTML / CSS
Allsole美国/加拿大:英国一家专门出售品牌鞋子的网站
2018/10/21 全球购物
18岁生日感言
2014/01/12 职场文书
翻译学院毕业生自荐书
2014/02/02 职场文书
课程改革实施方案
2014/03/16 职场文书
车辆工程专业求职信
2014/04/28 职场文书
关于springboot 配置date字段返回时间戳的问题
2021/07/25 Java/Android