Attribute and property are confusing concepts in web development, and for value, because of its particularity, are more easy to puzzle us, I'm trying to distinguish them with examples
Concept of Attribute and Property
To put it simplely, attribute is for element tag, and property is for element object, such as:
<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>
- Value attribute of input is defined through
value="test value"
of tag, and can be gotten viainput.getAttribute('value')
, and can be updated viainput.setAttribute('value', 'New Value')
- Value property of input can be gotten and updated via
input.value
,and the initial value is the same as attribute
Binding of Attribute and Property
At the very beginning, if the attribute value is updated, the property value will be changed too.
But if property value is updated (input in the input element or assign new value to input.value
), the attribute value will not be changed, further more, if attribute value is updated again now, the property value will not be changed with it, such as this animation shown, and you can also try to operate in this page
Actually, the dirty value flag is taking effect. the initial value of dirty value flag
is false
, namely update of attribute value will be changed, but once property value is updated by user interaction, value of dirty value flag will become true, namely update of attribute value will not affect corresponding property value
So in the real world project, we're generally handling value as property
Value handled by Vue.js
Usually use :value
v-bind
of Vue.js, is handling attribute normally, if need to be handled as property, we need to add .prop
But v-bind:value
are mostly handling property value by default, because it's transformed forcibly
<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>
Visible, Vue.js treat value as domProps of VNode's data, not attrs, so it will become value as property after mounted
In the source code of Vue.js, the handling of forcibly transfer property is as following
// 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)
}
inside it, definition of platformMustUseProp
in web platform is as following:
// 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')
)
}
From the foregoing, value of input whose type is not button, textarea, option, select and progress will forcibly to be property, without the need to set :value.prop
For example, textarea tab does not support value attribute, so the value of following code will not shown in the textarea
<textarea value="test value"></textarea>
But in Vue.js, the following code can successfully bind to value property and show in the textarea
<textarea :value="'test value'"></textarea>
Explicitly use :value.prop
One more thing deserves attention in the above Vue.js source code is that, to be treated forcibly as property, !el.component
need to be met, namely it's not a dynamical component, because el.component of dynamical component will be its is
attribute value
Namely v-bind
of dynamical component will be treated as attribute, if need to be as property, the .prop
need to be added, such as:
<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>
If in the above component
, substitute :value.prop
with .prop
, when switch to textarea
, the value will not show in the textarea, you can click to switch tab to see it in this page
Summary
- The binding relationship of value as attribute and property will invalid after property value update by user interaction
- Vue.js usually use
:value
to treat value as property - Dynamic component of Vue.js need to use
:value.prop
to treat value as property
Top comments (0)