Vue2数据双向绑定的原理

对于vue2 数据双向绑定的理解,手敲一遍后会有更好的认知~

一、页面数据部分内容

        在实现数据双向绑定之前,我们首先 先准备到我们需要用到的数据,然后再实现代码部分

(一)页面结构

        这里就要完成使用 v-model 绑定的数据 与页面结构插值表达式中的值 互相关联,达到vue 的数据双向绑定的效果

<body id="app">
    <span>up主:{
   
   { name }}</span>
    <input type="text" v-model="name">
    <span>更多:{
   
   { more.like }}</span>
    <input type="text" v-model="more.like">
</body>

(二)script 部分

        通过script 标签部分 引入的vue 文件,并不是真实的 vue,也就是我们马上写的代码部分

         el 中我们存储了html 部分的 <body/> 标签中的 id 便于我们以后方便使用

<script src="./vue.js"></script>
<script>
    const vm = new Vue(
        {
            el: '#app',
            data: {
                name: 'kerwin',
                more: {
                    like: '点赞'
                }
            }
        }
    )
    console.log(vm);
</script>

二、vue.js 代码

(一)创建Vue 实例

        因为我偶们考虑到代码量比较多,再者我们需要使用构造函数,所以我们选择class类来创建构造函数

        obj_instance 为实例时 传递的对象,首先。我们先将他的data 属性,保存至实例中的 $data中,然而vue 中也是这样进行使用的

class Vue {
    constructor(obj_instance) {
        this.$data = obj_instance.data
    }
}

(二)实现数据劫持

        关键点:我们需要使用Object.defineProperty 来实现数据劫持,vue2中是这样,vue3 略微不一样,理解了vue2 再理解vue3 就不难了

     1、创建数据劫持的函数

        因为我们需要双向绑定的是 data中的数据 所以我们需要传递 data

class Vue {
    constructor(obj_instance) {
       // ....
       // 在构造函数中将data 传入
        Observer(this.$data)
    }
}

// 实现数据劫持
function Observer(data_instance) {


}

        2、遍历data对象并实现数据劫持

           理解:Object.defineProperty

            Object.defineProperty( 操作的对象,操作的属性,{ } ) 

             { } 中传入对象,并在对象中实现数据监听

            这个方法可以修改对象中的现有属性

// 数据劫持
function Observer(data_instance) {
    // 遍历对象中的每一个属性
    Object.keys(data_instance).forEach(key => {
        Object.defineProperty(data_instance, key, {
            // 设置属性描述符可以改变
            configurable: true,
            // 设置是否可枚举
            enumerable: true,
            get() {

            },
            set(newValue) {

            },
        })
    })
}

        3、设置setter和getter

        我们可以在设置之前在控制台查看一下数据

        ① getter

        在observer 之前我们输出一下 vm。当我们在访问vm中的属性值的时候,发现数据为undefined,因为在访问的时候我们 get 并没有return导致数据丢失

        所以我们在遍历key 的时候,先将数据保存至 value 这个变量中,当我们访问的时候,会触发get,并将value 返回出来,这样数据就没有问题了

        ② setter

        当我们设置vm 中的数据的时候,会触发set函数,他的形参(newValue) 就是我们设置的数据,所以我们直接将 value设置为newValue 就可以了,此时数据就可以正常的修改

// 数据劫持
function Observer(data_instance) {
    // 如果没有值或不为对象那么直接返回出去
    Object.keys(data_instance).forEach(key => {

++      let value = data_instance[key]

        Object.defineProperty(data_instance, key, {
            configurable: true,
            enumerable: true,

            get() {
++              console.log(`访问了${key}属性 -->  属性值为:${value}`);
++              return value // 将原本数据return出来
            },
            set(newValue) {
++              value = newValue
++              console.log(`修改了${key}属性值${value} --> 为${newValue}`);
            },
        })
    })
}

        4、处理data对象属性中的对象

        因为我们设置的data属性值中 也是有对象的,我们使用 object.key 遍历的只有第一层,要想让data中所有的数据 都可以劫持到,那么我们需要使用递归

        当我们遍历key的时候 首先先递归调用一下是否 有值或 数据类型为对象,如果有那么继续递归,就可以解决这个问题了

function Observer(data_instance) {

    // 如果没有值或不为对象那么直接返回出去
++  if (!data_instance || typeof data_instance !== 'object') return

    Object.keys(data_instance).forEach(key => {
        let value = data_instance[key]
        // 递归,内部属性
++      Observer(value)

        Object.defineProperty(data_instance, key, {
           // ....
        })
    })
}

        5、处理给属性赋值一个新对象

        当我们给一个属性重新赋值为一个对象时,他并不会递归,因为observe 已经运行完了,所以我们需要在 setter 中再进行调用一下observe

Object.defineProperty(data_instance, key, {
    // ...

    set(newValue) {
        // 递归
++      Observer(newValue)
        value = newValue
        return console.log(`修改了${key}属性值${value} --> 为${newValue}`);
    },
})

太多了,不做解释了,以后再补充

详情可见gitee 克隆下来就可以,地址如下

Vue2 实现数据的双向绑定: Vue2 的数据双向绑定,涵盖v-model+input

猜你喜欢

转载自blog.csdn.net/Kerwin__li/article/details/128741065