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中的null和undefined解析
Apr 14 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
Aug 24 Javascript
JS、jquery实现几分钟前、几小时前、几天前等时间差显示效果的代码实例分享
Apr 11 Javascript
js实现透明度渐变效果的方法
Apr 10 Javascript
简介JavaScript中的setTime()方法的使用
Jun 11 Javascript
详解JavaScript基于面向对象之创建对象(2)
Dec 10 Javascript
H5移动端适配 Flexible方案
Oct 24 Javascript
微信小程序 空白页重定向解决办法
Jun 27 Javascript
JS库中的Particles.js在vue上的运用案例分析
Sep 13 Javascript
JS与CSS3实现图片响应鼠标移动放大效果示例
May 04 Javascript
详解vue项目打包步骤
Mar 29 Javascript
vue配置型表格基于el-table拓展之table-plus组件
Apr 12 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
php实现文件下载(支持中文文名)
2013/12/04 PHP
PHP abstract 抽象类定义与用法示例
2018/05/29 PHP
ThinkPHP5&amp;5.1框架关联模型分页操作示例
2019/08/03 PHP
PHP各种常见经典算法总结【排序、查找、翻转等】
2019/08/05 PHP
Apache+PHP+MySQL搭建PHP开发环境图文教程
2020/08/06 PHP
Nodejs sublime text 3安装与配置
2014/06/19 NodeJs
jQuery中关于ScrollableGridPlugin.js(固定表头)插件的使用逐步解析
2014/07/17 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
JavaScript的null和undefined区别示例介绍
2014/09/15 Javascript
JS实现简单路由器功能的方法
2015/05/27 Javascript
javascript每日必学之基础入门
2016/02/16 Javascript
Bootstrap~多级导航(级联导航)的实现效果【附代码】
2016/03/08 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
利用Angular.js限制textarea输入的字数
2016/10/20 Javascript
JS弹性运动实现方法分析
2016/12/15 Javascript
在 Angular 中实现搜索关键字高亮示例
2017/03/21 Javascript
详解微信小程序Radio选中样式切换
2017/07/06 Javascript
JavaScript实现的文本框placeholder提示文字功能示例
2018/07/25 Javascript
原生js实现的移动端可拖动进度条插件功能详解
2019/08/15 Javascript
微信小程序实现购物车代码实例详解
2019/08/29 Javascript
简单了解JS打开url的方法
2020/02/21 Javascript
Vue点击切换Class变化,实现Active当前样式操作
2020/07/17 Javascript
微信小程序自定义yPicker组件实现省市区三级联动功能
2020/10/29 Javascript
[52:03]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第三场 1月31日
2021/03/11 DOTA
Python中的startswith和endswith函数使用实例
2014/08/25 Python
深入Python函数编程的一些特性
2015/04/13 Python
python爬虫之BeautifulSoup 使用select方法详解
2017/10/23 Python
Python退火算法在高次方程的应用
2018/07/26 Python
Python之修改图片像素值的方法
2019/07/03 Python
pytorch梯度剪裁方式
2020/02/04 Python
python GUI库图形界面开发之PyQt5时间控件QTimer详细使用方法与实例
2020/02/26 Python
Python接口测试get请求过程详解
2020/02/28 Python
Zipadee-Zip襁褓过渡毯:Sleeping Baby
2018/12/30 全球购物
六月份红领巾广播稿
2014/02/03 职场文书
禁毒心得体会范文
2016/01/15 职场文书
使用 CSS 构建强大且酷炫的粒子动画效果
2022/08/14 HTML / CSS