您好,登錄后才能下訂單哦!
再開始本篇的討論之前,先思考幾個(gè)問題:
使用html元素屬性type='number'是否可以滿足要求
Vue中指令一般被設(shè)計(jì)用來操作dom元素的,而vue視圖是基于數(shù)據(jù)模型的,如何在操作dom的同時(shí),同時(shí)更新數(shù)據(jù)
你定義的指令不能只能在input元素上使用,還要支持在其父元素上使用,自定義組件及第三方組件上使用
你的指令是不是支持局部作用域,比如for循環(huán)渲染的數(shù)據(jù)的單元item,如何識(shí)別這個(gè)item進(jìn)行數(shù)據(jù)更新和dom操作
如何控制字符數(shù)目,超出禁止輸入
如何實(shí)現(xiàn)全局性的功能定義,從而在各個(gè)子組件中靈活使用
還有沒有別的優(yōu)化替代方案
問題思考
可以肯定的是,針對(duì)方案1,答案是:可以。很明顯,它只會(huì)作為我們此次討論的一個(gè)噱頭罷了!為什么呢?因?yàn)檫@種處理方案有兼容性,不說別的,拿谷歌和火狐瀏覽器對(duì)比來看:谷歌瀏覽器表現(xiàn)堪稱完美,而火狐瀏覽器表現(xiàn)就狠差強(qiáng)人意。而且會(huì)衍生出各種各樣的問題。這里不再贅述,有興趣的可以自己試試看
針對(duì)方案6,不是本次討論的重點(diǎn),但是思路方向很重要。比如使用vue的狀態(tài)管理機(jī)制庫vuex來解決這個(gè)數(shù)據(jù)流轉(zhuǎn)的問題是不是可以!這里只是一個(gè)方向,感興趣的同學(xué)可以去調(diào)研一下。
實(shí)現(xiàn)方案
Vue允許我們來定義全局指令,從而在各個(gè)子組件中使用。那我問題6我們解決了。那關(guān)鍵是如何實(shí)現(xiàn)問題2-5以及其相關(guān)的技術(shù)問題。比如我們定義指令onlyNum。
1.1 指令宿主
我們?cè)谑褂弥噶顣r(shí),指令的宿主元素不一定是input本身,也有可能使其父級(jí)或父級(jí)以上元素。那么我們?nèi)绾蝸碜R(shí)別?
// 只能輸入整數(shù) onlyNum (el,binding,vnode) { let ele = el.tagName === 'INPUT' ? el : el.querySelector('input') ele.oninput = function() { //獲取相關(guān)的指令配置信息 let rel = vnode.data.directives.filter(item =>{ return item.name === "only-num" })[0] vnode.context.$nextTick(()=>{ handleInput(ele,vnode,rel) }) } }
如上所示,我們看到了一個(gè)el的參數(shù),它是:指令所綁定的元素,可以用來直接操作 DOM。那么我們也就能通過這樣一個(gè)宿主元素找到它下邊的input元素了,從而不必關(guān)心當(dāng)前是不是input元素不重要,who care!然后我們通過處理事件函數(shù)input,來開始操作dom和數(shù)據(jù)了。
1.2 捕捉指令配置內(nèi)容
我們會(huì)在同一個(gè)宿主元素上綁定一個(gè)或者多個(gè)指令,但是,如何找到當(dāng)前指令的配置呢?上如定義了一個(gè)rel的變量,返回了指令onlyNum的所有配置信息。
1.3 數(shù)據(jù)更新如何與dom更新同步
由于vue的數(shù)據(jù)渲染是異步的。因此當(dāng)數(shù)據(jù)更新后,頁面dom并不一定就會(huì)按照我們期望的那樣來渲染。好在vue里提供了一套處理機(jī)制。
虛擬節(jié)點(diǎn)vnode參數(shù)中有一個(gè)上下文對(duì)象context,它用來表示宿主對(duì)象所在的組件對(duì)象。那么借助$nextTick就可以實(shí)現(xiàn)數(shù)據(jù)更新后,dom跟著渲染。
1.4 使用指令配置控制數(shù)據(jù)
/** * [handleInput 在輸入階段的處理邏輯] * @param {[DOM]} ele [當(dāng)前指令操作的dom對(duì)象] * @param {[虛擬節(jié)點(diǎn)]} vnode [當(dāng)前指令渲染的虛擬節(jié)點(diǎn)] * @param {[指令信息]} rel [當(dāng)前指令的所有指令信息] * @param {[校驗(yàn)類型]} type [輸入階段的校驗(yàn)類型] * "number": 僅支持輸入數(shù)字 * "float": 僅支持?jǐn)?shù)字和小數(shù)點(diǎn) */ function handleInput(ele,vnode,rel){ let rule; switch(true) { case rel.modifiers.float: // 浮點(diǎn)型 rule = /[^\d\.]/g; break; default: //默認(rèn)僅支持輸入數(shù)字 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 }) }
從上邊截圖,可以看出,目前為該指令賦予了以下功能:
支持純數(shù)字,浮點(diǎn)型,字符串類型數(shù)字3種格式,必要時(shí)可以自定義擴(kuò)充
支持最大字符數(shù)控制,超出禁止輸入
支持?jǐn)?shù)據(jù)作用域的靈活處理(主要針對(duì)類似for循環(huán)這種渲染操作)
更多功能完善中……
截圖紅框里的內(nèi)容可以參照3.2指令配置項(xiàng)來理解。關(guān)于屬性的配置,借助了虛擬dom節(jié)點(diǎn)里的data.attr屬性。
1.5 數(shù)據(jù)更新和dom更新
/** * [setValueWithExpressionVue 更新數(shù)據(jù)模型] * @param {Boolean} toString [是否轉(zhuǎn)化為字符串] * @param {[type]} currObj [當(dāng)前的數(shù)據(jù)模型] * @param {[type]} expression [指令表達(dá)式] * @param {[type]} value [指令的值] * @param {[type]} key [用于批量渲染時(shí)的跟蹤鍵] * @param {[type]} arg [指令的參數(shù)] */ 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 } } }) }
我們知道,我們綁定的數(shù)據(jù)的層級(jí)可能為1級(jí)數(shù)據(jù)直接綁定,如:v-only-num=”age”,也有可能是多層級(jí)的,如:v-only-num=”obj.info.age”,也有可能是局部作用域的,如for循環(huán)渲染的數(shù)據(jù):v-only-num=”item.age”……
‘i < expression.length - 1'是針對(duì)情景1做出的處理方案
‘option.key !== undefined'是針對(duì)情景3做出的處理方案,注意此時(shí)有個(gè)key。這個(gè)key很重要,是為了追蹤for循環(huán)的渲染,從而在進(jìn)行數(shù)據(jù)更新時(shí),捕獲你想要更新數(shù)據(jù)的那一項(xiàng)。
其余是針對(duì)情景2做出的處理方案
如何使用
基于以上實(shí)現(xiàn)的指令onlyNum,可以輕松實(shí)現(xiàn)以下情景的處理。
以element-ui文本框?yàn)槔?/strong>
僅數(shù)字(如:輸入09,會(huì)自動(dòng)變成9)
<el-input v-only-num="info.age" v-model="info.age"></el-input>
僅數(shù)字,顯示8位數(shù)以內(nèi)(如:輸入09,會(huì)自動(dòng)變成9)
<el-input v-only-num="info.age" v-model="info.age" :max-len=”8”></el-input>
字符型數(shù)字(如:輸入09,不會(huì)自動(dòng)變成9)
<el-input v-only-num.string="info.tel" v-model="info.tel"></el-input>
浮點(diǎn)型數(shù)據(jù)(支持?jǐn)?shù)字和小數(shù)點(diǎn)的混合輸入)
<el-input v-only-num.float="info.tel" v-model="info.tel"></el-input>
Fro循環(huán)產(chǎn)生的局部作用域
Element -ui等第三方的局部作用域
注意事項(xiàng)
以上處理方案基于vue2.0及以上版本
在使用上述指令時(shí),第三方的指令或者vue本省的指令修飾符不要使用,比如下邊
<el-input v-model="param.productId" v-only-num.trim="param.productId"></el-input>
這會(huì)帶出來一些意想不到的奇葩問題。因?yàn)橹噶畹男揎椃梢圆⒘惺褂?至多個(gè)。除非你對(duì)vue的源碼灰常熟悉。
指令使用時(shí),盡量單一。指定的屬性和配置要用到指定的場(chǎng)景,不要嵌套使用。否則發(fā)生問題了不好聚焦
以上這篇vue自定義指令實(shí)現(xiàn)僅支持輸入數(shù)字和浮點(diǎn)型的示例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。