vue的响应式原理(数据变视图变)

vue的双向绑定原理

Object.defineProperty(a,b,c) 方法

    const obj = {
          username: '第嘉',
     userage: 18
       }

当我要修改 obj 的属性时执行一些操作
需要通过 Object.defineProperty 给对象 添加/更新 属性,
或者 使用 Object.defineProperty 重写对象
Object.defineProperty(原对象,属性名,对象(属性名的属性描述))

属性的描述分两大类
  1. 存取描述符 configurable enumerable get set
  2. 数据描述符 configurable enumerable value writable
    configurable:true/false 是否可以用其他描述符描述和是否可以删除该属性,默认false
    writable:true/false 是否可以重写属性
    enumberable 该属性是否可以被枚举,对象遍历时是否可以遍历到该属性,默认true
/ Object.defineProperty(obj, 'username', {
     configurable: false,//不可以用其他描述
     enumerable: false,//不能被遍历,一般都写成true
     writable: true,//可以重写
     value: '杨露'//修改的值
 })

        Object.defineProperty(obj, 'userage', {
            configurable: true,
             enumerable: true,
            //get 的返回值用于设置属性值的,
            get() {
                 return 10
             },
          //set 函数用于监听属性值的变化,属性值改变就会触发
          set(value) {
              //value 表示改变之后的值
               console.log('发生改变', value)
               //更新age相关的视图
            }
       })

对象属性变视图变

        const data = {
            num: 10,
            post: {
                title: '成功之路',
                comments: [
                    {
                        id: 1,
                        text: '666'
                    },
                    {
                        id: 2,
                        text: '牛逼'
                    },
                ]
            },
            tabs: ['good', 'share']
        }

对象更新视图函数,data内属性变就会触发

        function render() {
            console.log('要更新视图')
        }
想让data变视图变,首先重新描述对象
         let num = data.num
         Object.defineProperty(data, 'num', {
             configurable: true,
             enumerable: true,
             get() {
                 return num
             },
             set(value) {
                 num = value
                 render()
             }
         })

data.title = 'Vue'这时候就会触发render()函数

封装对象属性添加描述函数
function definieReactive(obj, propotypeName, value) {
           Object.defineProperty(obj, propotypeName, {
               configurable: true,
               enumerable: true,
               get() {
                   return value
                   // console.log(111)
               },
               set(val) {
                   //相同的值不做视图更新
                   if (val !== value) {
                       value = val
                              render()
                  }
               }
           })
       }
找到data内所有属性,并且添加描述函数
        function observe(obj) {
            if (obj !== null) {//首先判断obj不为空,因为 typeof null 检测出来是 object
                if (typeof obj === 'object') {//判断是不是对象或数组
                    if (Array.isArray(obj)) {//如果是数组,数组内是有可能是对象,这些对象的属性也需要添加描述,所以遍历数组再执行observe,
                        for (let key in obj) {
                            observe(obj[key])
                        }
                    } else {//在这里拿到的就是纯纯对象Object
                        Object.keys(obj)//Object.keys()获取对象属性名返回一个由对象名组成的数组
                            .forEach(key => {//对返回的数组进行遍历,拿到各个属性名添加描述
                                definieReactive(obj, key, obj[key])
                                observe(obj[key])//子集有可能是个对象,调用函数进行判断
                            })
                    }
                }
            }
        }

        observe(data)

数组改变引起视图变化

数组的修改方法 push() reverse() shift() unshift() sort() splic() pop()
如何重写数组的方法 原型链
Array.prototype.push =新方法

        const arr = [1, 2, 3, 4, 5, 6]
        const oldarrPrototype = Array.prototype//先把老方法存起来
        const methods = ['push', 'reverse', 'shift', 'unshift', 'sort', 'splic', 'pop']
        // /拷贝一个原型对象 Array.protype 下的属性不可枚举不能遍历
        // 我们重写这些方法并不是将所有的数组下的这些方法重写了,只有我们的数据是数组的话里面的数组方法才能被修改
        //所以我们的做法是创建一个新的原型对象,里面包含了数组内所偶的方法,以及修改之后的方法
        const proto = Object.create(oldarrPrototype)
        methods.forEach(ele => {
            proto[ele] = function () {
                // 1.执行原来的方法
                // 2.更新视图
                // console.log(111)
                oldarrPrototype[ele].apply(this, [...arguments])
                render()
            }
        })
        arr.__proto__ = proto

        document.querySelector('.a').onclick = function () {
            arr.push(7)
            console.log(arr) //1,2,3,4,5,6,7
        }

Vue里面一些数组或者对象的操作不会导致视图的变化
原因是因为 Vue 的响应式原理处理不了这些变化
vue 提供了 $set用于对象的新增属性 $delete用于对象的删除属性
对于数组来说, 可以直接赋值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值