1. 原理
vue的双向数据绑定主要是通过Object对象的defineProperty属性,重写data的set和get函数来实现。
vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调。
主要实现v-bind
,v-model
,v-click
2. v-model
v-model
原理其实就是给input事件绑定oninput
事件 就会立刻调用底层对象对应的setter
方法 改变data
里的属性的值 从而实现双向数据绑定
比如一个单选框
<ul>
<li>性别:
<input type="radio" name="sex" id="sex1" value="male" v-model="userinfo.sex"> <label for="sex1">男</label>
<input type="radio" name="sex" id="sex2" value="female" v-model="userinfo.sex"> <label for="sex2">女</label>
</li>
</ul>
<li>
<select v-model="user.infocity">
<option v-for="(item, index) in userinfo.cityList" :key="index" :value="item">{{item}}</option>
</select>
</li>
<button @click="doSubmit()" class="submit">Submit</button>
<script>
export default {
data() {
return {
username: "kuli",
userinfo: {
username: "",
age: "",
sex: "male",
cityList: ["Beijing", "Shanghai", "Shenzhen"],
city: "Shenzhen",
}
}
},
methods: {
doSubmit() {
console.log(this.userinfo)
}
}
}
</script>
v-model自定义指令下包裹的语法是input的value属性、input事件
<input v-modle="inputV" />
// 等同于
<input :value="inputV" @input="inputV = $event.target.value"/>
比如checkbox:
// 看似执行了v-model一个指令
<input type="checkbox" v-model="checkedNames">
// 实际上
<input
type="checkbox"
:value="checkedNames"
@change="checkedNames = $event.target.value"
/>
v-model与v-bind的区别有两点:
v-model是双向绑定数据,也就是当父组件的传进去的数据发生改变时,子组件的数据也会发生改变,当子组件发生改变时,父组件也会发生改变
v-bind是单向绑定,当父组件的数据发生改变时,子组件的数据也会改变,但是当子组件发生改变时,父组件的数据不会发生改变
-
v-model默认绑定value值
-
v-bind的绑定值是可以自定义的
自定义组件的v-model
父组件标签写法
<my-component v-model="myData" />
复制代码
子组件写法,按照value值绑定和input事件更新值来拆解。
首先,需要在子组件接收一个value的prop(用于值绑定,或者设置初始值)
props:{
value:{
type:String,
default:''
}
}
然后,在组件内部更新值,在需要更新值的逻辑部分写入
this.$emit('input', newData);
这样就是在组件内部拿到了值,并且手动触发input事件更新了值,但在父组件只需要写入v-model
指令即可,也算是父子组件传值的一种。
3. Proxy
Object.defineProperty
的缺陷:
在Vue2.0
中,数据双向绑定就是通过Object.defineProperty
去监听对象的每一个属性,然后在get
,set
方法中通过发布订阅者模式来实现的数据响应,但是存在一定的缺陷,比如只能监听已存在的属性,对于新增删除属性就无能为力了,同时无法监听数组的变化,所以在Vue3.0
中将其换成了功能更强大的Proxy
。
了解Proxy
Proxy
是ES6
新推出的一个特性,可以用它去拦截js
操作的方法,从而对这些方法进行代理操作。
console.log(typeof Proxy)//function
由上可以得知:
Proxy
是定义在window
上的全局变量- 它的类型是
function
Proxy
在构造对象时接受两个参数:target
和handler
- 两个参数的类型必须是
object
所以,target
表示的就是要拦截(代理)的目标对象;而handler
是用来定制拦截行为
Vue3定义了一系列的响应式API,比如reactive、ref等等,它们的特点是:当时数据发生变化时,页面会对应更新UI,而底层用的就是Proxy!
数据对象obj通过reactive包装成了代理对象,当数据发生变化时,会调用set方法,在更新数据的同时,同时执行一些update的操作。
Proxy特点(important)
- Proxy可以直接监听对象而非属性
- Proxy可以直接监听数组变化
- Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是
Object.defineProperty
不具备的。 - Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而
Object.defineProperty
只能遍历对象属性直接修改。 - Proxy的劣势就是兼容性问题,而且无法用polyfill磨平