1. 程式人生 > >作為 attribute 和 property 的 value 及 Vue.js 的相關處理

作為 attribute 和 property 的 value 及 Vue.js 的相關處理

attribute 和 property 是 Web 開發中,比較容易混淆的概念,而對於 value,因其特殊性,更易困惑,本文嘗試做一下梳理和例證 ## attribute 和 property 的概念 簡單的說,attribute 是元素標籤的屬性,property 是元素物件的屬性,例如: ``` ``` input 的 value attribute 是通過標籤裡的 value="test value" 定義的,可以通過 input.getAttribute('value') 獲取,可以通過 input.setAttribute('value', 'New Value') 更新 input 的 value property 可通過 input.value 獲取和更新,初始值是與 attribute 中的賦值一致的 ## attribute 和 property 的繫結 如果在最開始的時候,更新 attribute value 的值,property 的值也會隨之改變 但是更新 property value 的值(在文字框輸入或給 input.value 賦新值 ),attribute 的值不會隨之改變,而且此時再更新 attribute 的值,property 的值也不再隨之改變,如此[動畫][gif-value]所示,也可訪問此[頁面][codepen-value]嘗試進行操作 這其實是髒值標記([dirty value flag][dirty-value-flag])在起作用,dirty value flag 的初始值為 false,即 attribute value 的更新預設會改變對應的 property value,但是一旦使用者互動修改了 property value,dirty value flag 的值就變為 true,即attribute value 的更新就不會改變對應的 property value 了 所以在實際專案中,我們一般都是在處理作為 property 的 value ## Vue.js 對 value 的處理 ### 一般情況使用 :value Vue.js 的 v-bind,一般情況下是在處理 attribute,如果要作為 property 處理的話,需要加上 .prop 不過 v-bind:value 卻大都預設為處理 property 值,因為被強制轉化了,例如: ``` ``` 可見,Vue.js 將 value 作為 VNode 的 data 中的 domProps 的屬性,而不是 attrs 的屬性,所以掛載後會成為作為 property 的 value 在 Vue.js 原始碼中,強制轉化 property 的處理如下: ``` // src/compiler/parser/index.js function processAttrs (el) { ... if ((modifiers && modifiers.prop) || ( !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name) )) { addProp(el, name, value, list[i], isDynamic) } else { addAttr(el, name, value, list[i], isDynamic) } ``` 其中 platformMustUseProp 在 web 平臺的定義如下: ``` // src/platforms/web/util/attrs.js const acceptValue = makeMap('input,textarea,option,select,progress') export const mustUseProp = (tag: string, type: ?string, attr: string): boolean => { return ( (attr === 'value' && acceptValue(tag)) && type !== 'button' || (attr === 'selected' && tag === 'option') || (attr === 'checked' && tag === 'input') || (attr === 'muted' && tag === 'video') ) } ``` 由上可知,型別不為 button 的 input, textarea, option, select, progress 的 value 會強制作為 property,而不需要設定為 :value.prop 例如 textarea 標籤,其本身其實並不支援 value attribute,所以以下程式碼中的 value 的值並不會顯示在多行文字框中 ``` ``` 但是在 Vue.js 中, 以下程式碼能成功繫結到 value property 並顯示在多行文字框中 ``` ``` ### 特殊情況使用 :value.prop 以上原始碼需要注意的還有,強制作為 property, 還要滿足 !el.component,即不為動態元件,因為動態元件的 el.component 的值為其 is attribute 的值 即動態元件的的 v-bind 預設都是作為 attribute的,如果要作為 property,就要使用 .prop,例如: ``` ``` 如果以上 component 中,刪除 :value.prop 的 .prop,切換到 textarea 時,其值就不會顯示在多行文字框中,可以在此[頁面][codepen-textarea]點選切換標籤檢視 ## 總結 - 作為 attribute 和 property 的 value 的繫結關係會在使用者互動更新值後失效 - Vue.js 一般使用 :value 即可讓 value 作為 property - Vue.js 動態模版需要使用 :value.prop 才可讓 value 作為 property [gif-value]: https://img2020.cnblogs.com/blog/1984620/202004/1984620-20200406125938182-431725928.gif [codepen-value]: https://codepen.io/chanvin/pen/RwPzdMd?editors=1010 [codepen-textarea]: https://codepen.io/chanvin/pen/KKpjYmy?editors=1010 [dirty-value-flag]: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-