做为 attribute 和 property 的 value 及 Vue.js 的相关处理

attribute 和 property 是 Web 开发中,比较容易混淆的概念,而对于 value,因其特殊性,更易困惑,本文尝试作一下梳理和例证html

attribute 和 property 的概念

简单的说,attribute 是元素标签的属性,property 是元素对象的属性,例如:vue

<input id="input" value="test value">
<script>
let input = document.getElementById('input');
console.log(input.getAttribute('value')); // test value
console.log(input.value); // test value
</script>
复制代码
  • 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 的值也会随之改变node

可是更新 property value 的值(在文本框输入或给 input.value 赋新值 ),attribute 的值不会随之改变,并且此时再更新 attribute 的值,property 的值也再也不随之改变,如此动画所示,也可访问此页面尝试进行操做web

这实际上是脏值标记(dirty value flag)在起做用,dirty value flag 的初始值为 false,即 attribute value 的更新默认会改变对应的 property value,可是一旦用户交互修改了 property value,dirty value flag 的值就变为 true,即attribute value 的更新就不会改变对应的 property value 了npm

因此在实际项目中,咱们通常都是在处理做为 property 的 valuebash

Vue.js 对 value 的处理

通常状况使用 :value

Vue.js 的 v-bind,通常状况下是在处理 attribute,若是要做为 property 处理的话,须要加上 .propapp

不过 v-bind:value 却大都默认为处理 property 值,由于被强制转化了,例如:dom

<input id="input" :value="'test value'" >
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let input = new Vue({
  el: '#input',
  mounted () {
    console.log(this.$el.getAttribute('value')); // null
    console.log(this.$el.value); // test value
    console.log(this._vnode.data) // {attrs: {id: "input"}, domProps: {value: "test value"}}
  }
});
</script>
复制代码

可见,Vue.js 将 value 做为 VNode 的 data 中的 domProps 的属性,而不是 attrs 的属性,因此挂载后会成为做为 property 的 valueide

在 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 的值并不会显示在多行文本框中

<textarea value="test value"></textarea>
复制代码

可是在 Vue.js 中, 如下代码能成功绑定到 value property 并显示在多行文本框中

<textarea :value="'test value'"></textarea>
复制代码

特殊状况使用 :value.prop

以上 Vue.js 源码须要注意的还有,强制做为 property, 还要知足 !el.component,即不为动态组件,由于动态组件的 el.component 的值为其 is attribute 的值

即动态组件的的 v-bind 默认都是做为 attribute的,若是要做为 property,就要使用 .prop,例如:

<div id="app">
  <component :is="element" :value.prop="'test value'"></component>
  <button @click="change">Change</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let app = new Vue({
  el: '#app',
  data: {
    element: 'input'
  },
  methods: {
    change () {
      this.element = 'input' === this.element ? 'textarea' : 'input';
    }
  }
});
</script>
复制代码

若是以上 component 中,删除 :value.prop 的 .prop,切换到 textarea 时,其值就不会显示在多行文本框中,能够在此页面点击切换标签查看

总结

  • 做为 attribute 和 property 的 value 的绑定关系会在用户交互更新值后失效
  • Vue.js 通常使用 :value 便可让 value 做为 property
  • Vue.js 动态模版须要使用 :value.prop 才可以让 value 做为 property
相关文章
相关标签/搜索