01. v-model
语法糖
(1)使用
-
v-model
是一个语法糖,可以拆解为props: value
和events: input
-
组件必须提供一个名为
value
的 prop,以及名为input
的自定义事件props
不能在组件内修改,需要通过父组件修改的因此实现
v-model
一般都会有一个currentValue
的内部 data 属性这个属性在开始时从 value 获取一次值
然后监听 value ,当 value 修改时,通过 watch 更新这个属性
子组件不会修改 value 的值,而是修改
currentValue
修改后,会通过自定义事件
input
将修改值派发给父组件父组件监听这个事件并接收到后,由父组件修改 value
<!-- 父组件 --> <son v-model="value"></son> <!-- 正常情况下相当于(v-model默认绑定input事件) --> <son :value="value" @input="value = $event.target.value"></son>
<!-- 子组件 --> <template> <span>{{ value }}</span> <button @click="handleInput">语~法~糖</button> </template> <script> export default { props: { value: { type: Number } }, data () { return { // 组件内不能直接修改父组件传递过来的值 // 需要一个 currentValue 的内部 data 属性 currentValue: this.value } }, watch: { // 通过监听值 value 的改变, 以更新 currentValue value (val) { this.currentValue = val; } }, methods: { // 通过 emit 派发 input事件 给父组件 handleInput (val) { this.currentValue += val; // 父组件是通过 v-model 语法糖来实现数据更新的 this.$emit('input', this.currentValue); } } } </script>
-
(2)自定义
-
自定义
v-model
的属性和事件-
对其它元素来说,不一定要监听
input
事件,也不一定是value
属性- 所以,可以在子组件内部,通过
model
来对v-model
进行自定义
<!-- 父组件 --> <son v-model="checked"></son> <!-- 子组件 --> <template> <input type="checkbox" > </template> <script> export default { // 还是需要通过 props 接收父组件传递的参数 props: ['checked'], // 然后通过 model 来自定义属性和事件 model: { prop: 'checked', // 表示 绑定的属性 event: 'change' // 表示 监听 change 自定义事件 } }, </script>
- 所以,可以在子组件内部,通过
-
(3)修饰符
lazy
:取代input监听change事件number
:字符串转为数字trim
:首尾空格过滤
02. .sync
修饰符
-
.sync
不是真正的双向绑定,而是一个语法糖,修改数据还是在父组件完成的,并非在子组件// 父组件 <son :value.sync="value"></son> // 等于 <son :value="value" @update:value="..."></son> // 子组件 <script> handleInput(){ this.$emit('update:value', this.value) } </script>
不能和表达式一起使用
不能用在字面量对象上
03. $nextTick
-
在Vue中,并不是数据发生变化之后,DOM立即发生变化,当修改了data的值,然后马上获取这个dom元素的值,是不能立即获取到更新后的值
-
需要使用
$nextTick
这个回调,让修改后的data值渲染更新到dom元素之后再获取,才能成功$nextTick
表示:在下次DOM更新循环结束之后执行- 在修改数据之后使用这个方法,可以立即获取更新后的DOM元素
this.$nextTick( () => { // 在这里可以立即获取更新后的 属性值 })
04. $set
和vue.set()
-
由于JavaScript的限制,vue无法检测对象属性的添加或删除、不能检测非数组方法变化的数组
- 这是因为 Vue.js 在初始化实例时将属性转为
getter/setter
,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的
- 这是因为 Vue.js 在初始化实例时将属性转为
-
可以通过
vm.$set()
或者Vue.set()
来为对象添加响应式属性Vue.set
是定义在构造函数上的,而vm.$set
是定义在原型对象上的Vue.set(target, key, value); // 或者 vm.$set(target, key, value)
export default { data () { return { arr: ['a', 'b', 'c'], obj: { a: 1 } } }, methods: { handleArr () { this.arr[1] = 'x'; // 通过数组下标直接改变数组的值,不是响应性的 this.$set(this.arr, 1, 'x'); // 是响应性的 }, handleObj () { this.obj.b = 2; // 对象属性的添加,不是响应性的 Vue.set(this.obj, 'b', 2); // 是响应性的 } } }
注意:
- 监听器watch无法监听到通过
this.$set
改变对象的
- 监听器watch无法监听到通过
-
响应式更改数组的其他方法:
-
数组的以下方法,都是可以触发视图更新的,也就是响应式的:
push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
-
还有一种小技巧,就是先 copy 一个数组,然后通过 index 修改后,再把原数组整个替换,比如:
handler () { const data = [...this.arr]; data[1] = 'x'; this.arr = data; }
-