前置知识
为了层层递进到最后的一个问题,需要一些前置知识点。
数据响应
data 中的数据都是响应式的,当你修改这个属性,对应的视图层会发生变化。
<div id="app">
<p> {{ message }} </p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'hello'
}
})
vm.message = 'world' // 修改message,视图也会响应
</script>
但是当你直接新增一个属性的时候,这个属性不是响应式的。
<div id="app">
<p>{{ myData.title }}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
myData: {
}
}
})
vm.myData.title = "你好" // 并不会被渲染到视图上,也不是响应式的。
</script>
所以,这里的需要注意的是:
只有当实例被创建时就已经存在于 data 中的属性才是响应式的。
Vue.set
这个方法是Vue提供的,用于向响应式对象上添加新属性,这个新属性也会是响应式的。
<div id="app">
<p>{{ myData.title }}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
myData: {
}
}
})
Vue.set(vm.myData, 'title', 'hello')// 可以这样添加一个响应式属性
但要注意的是,不能通过这个Vue.set 新增一个根级响应式的属性。也就是说只能向响应式对象中新增一个属性,而不能直接新增一个根级属性。
v-model
v-model 可以实现双向绑定
<div id="app">
<input type="text" v-model="user_input">
<p>{{ user_input }}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
user_input: ''
}
})
</script>
但本质上,v-model 是下面写法的一种更方便的的写法而已。
<div id="app">
<input type="text" v-bind:value="user_input" v-on:input="user_input=$event.target.value">
<p>{{ user_input }}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
user_input: ''
}
})
</script>
好了,上面几点就是前置知识,小结一下:
- data 中已存在的属性才是响应式的。
- 无法在实例化Vue后新增一个根级的响应式数据。
- 可以通过Vue.set方法在一个响应对象上新增一个属性。
- v-model 是一种语法糖。
到目前为止,一切都是很顺畅,没有疑惑。
v-model 的骚操作
<div id="app">
<input type="text" v-model="myData.user_input">
<p>{{myData.user_input}}</p>
</div>
<script>
var vue = new Vue({
el: '#app',
data: {
myData: {
},
},
})
</script>
上面,我们没有提前声明use_input这个属性,按理说,这个属性并不是一个响应式的属性,而且前面说过,v-model是一种语法糖,上面的代码等价于
<div id="app">
<input v-bind:value="myData.user_input" v-on:input="myData.user_input = $event.target.value">
<p>{{myData.user_input}}</p>
</div>
<script>
var vue = new Vue({
el: '#app',
data: {
myData: {
},
},
})
</script>
但是,你如果运行这两段代码,你会发现,第一种写法能够实现正常的双向绑定,但是第二种写法却不能实现。
这就是我今天对v-model的一个疑惑,也就是,当v-model的值是一个对象的属性值,那么这个属性值可以不用提前声明,这个属性值仍会是响应式的。 经过研究半天,才发现:
v-model 处理对象属性会自动触发 set
好吧,我其实一开始就这样猜测了,只是没有实锤。 下面是Vue里面关于v-model的实现源码:v-model源码
终于算是解决了我心中的一个疑惑,开心。