為什么未使用特定指令的輸入框也會(huì)受到Vue自定義指令的影響?

為什么未使用特定指令的輸入框也會(huì)受到Vue自定義指令的影響?

vue自定義指令意外生效之謎:深入探討

本文探討一個(gè)常見(jiàn)的Vue.JS開(kāi)發(fā)問(wèn)題:自定義指令在未綁定目標(biāo)元素上生效的原因。我們分析一個(gè)案例,解釋這種現(xiàn)象背后的機(jī)制,并提供解決方案。

案例描述

我們創(chuàng)建了一個(gè)全局自定義指令 validatenumber,用于限制輸入框只能輸入數(shù)字:

Vue.directive('validateNumber', {     bind(el, binding, vnode) {         let lastData = null;         el.onkeyup = (e) => {             if (String.fromCharCode(e.keyCode) === 'E' || String.fromCharCode(e.keyCode) === 'KeyE') {                 e.target.value = lastData;                 return false;             } else {                 lastData = e.target.value;             }             e.target.value = e.target.value.replace(/[^d]/ig, '');              let _this = vnode.context;             _this.AccessNestedObject(_this, vnode.data.model.expression, e.target.value);              if (binding.expression && e.target.value) {                 let obj = (new Function("return " + binding.expression))();                 let keys = Object.keys(obj);                 let values = Object.values(obj);                 if (keys[0] === 'min') {                     if (parseInt(e.target.value) < parseInt(values[1])) {                         e.target.value = values[1];                     }                 }             }              el.dispatchEvent(new Event('input'));         };     } });

在Vue模板中,我們僅在一個(gè)輸入框上使用了該指令:

<el-form-item label="等待時(shí)間" prop="timeInterval">   <el-input id="alarm-rule-time-interval" style="width:100%" type="number" v-model="alertRulesForm.timeInterval" v-validateNumber>     <template slot="append">秒</template>   </el-input> </el-form-item> <el-form-item label="空間間隔" prop="distanceInterval">   <el-input id="alarm-rule-distance-interval" type="number" v-model="alertRulesForm.distanceInterval">     <template slot="append">米</template>   </el-input> </el-form-item>

然而,第二個(gè)輸入框(distanceInterval),盡管未應(yīng)用 v-validateNumber 指令,卻也表現(xiàn)出相同的數(shù)字校驗(yàn)行為。

立即學(xué)習(xí)前端免費(fèi)學(xué)習(xí)筆記(深入)”;

問(wèn)題分析

關(guān)鍵在于 el.onkeyup 事件監(jiān)聽(tīng)器。該監(jiān)聽(tīng)器綁定在 el 元素上,而 el 指的是所有應(yīng)用了 validateNumber 指令的元素。 由于指令的綁定機(jī)制,事件監(jiān)聽(tīng)器可能會(huì)意外地捕獲到其他元素的 keyup 事件,特別是當(dāng)這些元素在 dom 結(jié)構(gòu)上與已綁定指令的元素存在父子或兄弟關(guān)系時(shí)。 type=”number” 屬性雖然限制了輸入,但這并不能解釋為什么第二個(gè)輸入框會(huì)觸發(fā) validateNumber 指令的邏輯。

解決方案

為了避免這種意外的指令生效,我們需要改進(jìn)指令的實(shí)現(xiàn):

  1. 更精確的事件監(jiān)聽(tīng): 不要直接監(jiān)聽(tīng) el.onkeyup,而是利用更精確的事件委托機(jī)制,例如,將事件監(jiān)聽(tīng)器綁定到父元素,并使用 e.target 判斷事件源是否為目標(biāo)元素。

  2. 指令范圍限制: 在指令的 bind 或 inserted 方法中,可以檢查 el 是否為目標(biāo)元素,如果不是,則不執(zhí)行指令邏輯。

修改后的指令:

Vue.directive('validateNumber', {     bind(el, binding, vnode) {         // 添加判斷,確保指令只在目標(biāo)元素上生效         if (el.id !== 'alarm-rule-time-interval') return;          let lastData = null;         el.onkeyup = (e) => {             // ... (其余邏輯保持不變)         };     } });

或者,使用事件委托:

Vue.directive('validateNumber', {     bind(el, binding, vnode) {         const parent = el.parentElement; // 獲取父元素         parent.addEventListener('keyup', (e) => {             if (e.target === el) { // 檢查事件源是否為目標(biāo)元素                 // ... (指令邏輯)             }         });     } });

通過(guò)以上改進(jìn),我們可以確保自定義指令只在目標(biāo)元素上生效,避免了意外的干擾。 記住,在編寫(xiě)自定義指令時(shí),要格外注意事件監(jiān)聽(tīng)器的作用范圍和事件委托的正確使用,以確保指令的可靠性和可預(yù)測(cè)性。

以上就是

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊12 分享