vue自定義指令實現僅支持輸入數字和浮點型的示例
再開始本篇的討論之前,先思考幾個問題:
使用html元素屬性type='number'是否可以滿足要求
Vue中指令一般被設計用來操作dom元素的,而vue視圖是基于數據模型的,如何在操作dom的同時,同時更新數據
你定義的指令不能只能在input元素上使用,還要支持在其父元素上使用,自定義組件及第三方組件上使用
你的指令是不是支持局部作用域,比如for循環(huán)渲染的數據的單元item,如何識別這個item進行數據更新和dom操作
如何控制字符數目,超出禁止輸入
如何實現全局性的功能定義,從而在各個子組件中靈活使用
還有沒有別的優(yōu)化替代方案
問題思考
可以肯定的是,針對方案1,答案是:可以。很明顯,它只會作為我們此次討論的一個噱頭罷了!為什么呢?因為這種處理方案有兼容性,不說別的,拿谷歌和火狐瀏覽器對比來看:谷歌瀏覽器表現堪稱完美,而火狐瀏覽器表現就狠差強人意。而且會衍生出各種各樣的問題。這里不再贅述,有興趣的可以自己試試看
針對方案6,不是本次討論的重點,但是思路方向很重要。比如使用vue的狀態(tài)管理機制庫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的所有配置信息。

1.3 數據更新如何與dom更新同步
由于vue的數據渲染是異步的。因此當數據更新后,頁面dom并不一定就會按照我們期望的那樣來渲染。好在vue里提供了一套處理機制。

虛擬節(jié)點vnode參數中有一個上下文對象context,它用來表示宿主對象所在的組件對象。那么借助$nextTick就可以實現數據更新后,dom跟著渲染。
1.4 使用指令配置控制數據
/**
* [handleInput 在輸入階段的處理邏輯]
* @param {[DOM]} ele [當前指令操作的dom對象]
* @param {[虛擬節(jié)點]} vnode [當前指令渲染的虛擬節(jié)點]
* @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循環(huán)這種渲染操作)
更多功能完善中……
截圖紅框里的內容可以參照3.2指令配置項來理解。關于屬性的配置,借助了虛擬dom節(jié)點里的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循環(huán)渲染的數據:v-only-num=”item.age”……
‘i < expression.length - 1'是針對情景1做出的處理方案
‘option.key !== undefined'是針對情景3做出的處理方案,注意此時有個key。這個key很重要,是為了追蹤for循環(huán)的渲染,從而在進行數據更新時,捕獲你想要更新數據的那一項。
其余是針對情景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循環(huán)產生的局部作用域

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

注意事項
以上處理方案基于vue2.0及以上版本
在使用上述指令時,第三方的指令或者vue本省的指令修飾符不要使用,比如下邊
<el-input v-model="param.productId" v-only-num.trim="param.productId"></el-input>
這會帶出來一些意想不到的奇葩問題。因為指令的修飾符可以并列使用1至多個。除非你對vue的源碼灰常熟悉。
指令使用時,盡量單一。指定的屬性和配置要用到指定的場景,不要嵌套使用。否則發(fā)生問題了不好聚焦
以上這篇vue自定義指令實現僅支持輸入數字和浮點型的示例就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
vue+elementUi中的table實現跨頁多選功能(示例詳解)
最近在開發(fā)工業(yè)品超市的后臺系統(tǒng),遇到一個需求,就是實現在一個table表格中多選數據,在網上查了好多,有些方法真的是無語,下面通過本文給大家分享vue+elementUi中的table實現跨頁多選功能,感興趣的朋友跟隨小編一起看看吧2024-05-05
vue項目配置 webpack-obfuscator 進行代碼加密混淆的實現
這篇文章主要介紹了vue項目配置 webpack-obfuscator 進行代碼加密混淆,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02
Vue配置marked鏈接添加target="_blank"的方法
這篇文章主要介紹了Vue配置marked鏈接添加target="_blank"的方法,文中給大家提到了vue實現類似target="_blank"打開新窗口的代碼,感興趣的朋友參考下吧2019-07-07

