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 live函数
Dec 24 Javascript
火狐textarea输入法的bug的触发及解决
Jul 24 Javascript
jQuery选择器源码解读(四):tokenize方法的Expr.preFilter
Mar 31 Javascript
基于jquery实现鼠标滚轮驱动的图片切换效果
Oct 26 Javascript
用瀑布流的方式在网页上插入图片的简单实现方法
Sep 23 Javascript
微信小程序 radio单选框组件详解及实例代码
Jan 10 Javascript
js实现淡入淡出轮播切换功能
Jan 13 Javascript
Vue开发中整合axios的文件整理
Apr 29 Javascript
完美解决手机浏览器顶部下拉出现网页源或刷新的问题
Nov 30 Javascript
微信小程序 函数防抖 解决重复点击消耗性能问题实现代码
Sep 12 Javascript
详解JavaScript之Array.reduce源码解读
Nov 01 Javascript
动态实现element ui的el-table某列数据不同样式的示例
Jan 22 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
php将数据库中所有内容生成静态html文档的代码
2010/04/12 PHP
PHP导出MySQL数据到Excel文件(fputcsv)
2011/07/03 PHP
让PHP更快的提供文件下载的代码
2012/06/13 PHP
smarty模板引擎使用内建函数foreach循环取出所有数组值的方法
2015/01/22 PHP
Jquery知识点三 jquery表单对象操作
2011/01/17 Javascript
JavaScript下通过的XMLHttpRequest发送请求的代码
2011/06/28 Javascript
jQuery EasyUI API 中文文档 - Menu菜单
2011/10/03 Javascript
JavaScript中获取样式的原生方法小结
2014/10/08 Javascript
jQuery实现tab标签自动切换的方法
2015/02/28 Javascript
浅析$(function) ready和onload 的区别
2016/09/03 Javascript
20行JS代码实现粘贴板复制功能
2018/02/06 Javascript
babel之配置文件.babelrc入门详解
2018/02/22 Javascript
iview table高度动态设置方法
2018/03/14 Javascript
express express-session的使用小结
2018/12/12 Javascript
详解JS取出两个数组中的不同或相同元素
2019/03/20 Javascript
vue axios post发送复杂对象问题
2019/06/04 Javascript
es6函数之严格模式用法实例分析
2020/03/17 Javascript
[01:13:51]TNC vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python开发利器之ulipad的使用实践
2017/03/16 Python
Python实现的简单线性回归算法实例分析
2018/12/26 Python
Python学习笔记之变量、自定义函数用法示例
2019/05/28 Python
Django框架组成结构、基本概念与文件功能分析
2019/07/30 Python
Python实现二叉树的最小深度的两种方法
2019/09/30 Python
python实现WebSocket服务端过程解析
2019/10/18 Python
python 实现按对象传值
2019/12/26 Python
LORAC官网:美国彩妆品牌
2019/08/27 全球购物
泰国Robinson百货官网:购买知名品牌的商品
2020/02/08 全球购物
杭州-DOTNET笔试题集
2013/09/25 面试题
升学宴主持词
2014/04/02 职场文书
高一学生期末评语
2014/04/25 职场文书
先进个人事迹材料
2014/12/29 职场文书
2016年春节慰问信息
2015/03/25 职场文书
商标侵权律师函
2015/05/27 职场文书
魂断蓝桥观后感
2015/06/10 职场文书
公安纪律作风整顿心得体会
2016/01/23 职场文书
vite+vue3.0+ts+element-plus快速搭建项目的实现
2021/06/24 Vue.js