data数值设置 vue_[Vue] 3 - 对象的数据劫持? / 双向绑定实现 / Vue响应式原理?

cea2476fcb83c34e91efd539ea1b0c5a.png

Vue 对数据的控制,本质是 [对对象数据的劫持] 和 [对dom的事件绑定]

1. 【对象的数据劫持】Object.defineProperty做什么的? 对对象的某个参数值进行拦截
2. 【对象的数据劫持】Proxy 做什么的? 对整个对象变化进行拦截
3. 【代码实现】Vue 双向绑定是如何实现的?
4. 【Vue响应式原理】https://cn.vuejs.org/v2/guide/reactivity.html
    本质是对对象的数据变化的劫持。
    通过Object.defineProperty实现。
    对象数据某参数值变化,通过set拦截。触发watcher方法, 去重新渲染。

1 - Object.defineProperty

在对象上可以 定义新的属性 或 变更现有属性值的 方法 。

<script>
const targetObj = {
  id: 1
}

// 暂时储存 targetObj.a 的值
let temp_id = 1
Object.defineProperty(targetObj, 'id', {
    configurable: false, // 是否可以删除目标属性或是否可以再次修改属性的特性
    enumerable: true, // 是否可以被枚举
    set: function (newVal) {
      // 对象属性变化的拦截器
      console.log('set', newVal)
      temp_id += newVal
    },
    get: function () {
      return temp_id
    }
  }
)

console.log(targetObj.id)
targetObj.id = 100
console.log(targetObj.id)

</script>

代码实现可参考: vue 的双向绑定原理及实现

下面是个简单的概念说明。

2 - 双向绑定实现 I

从数据变化监听 到 View变化, 核心是Object.defineProperty来拦截 数据set方法

8850f7e565ffb8d3456c604068d350ba.png
<html>
<head></head>

<body>
<!-- {{ }} 空白区域填入某值 -->
<h1 id="app">{{ appName }}</h1>

<script>
function Vue (data, el, key) {
  this.data = data
  // 监听数据变化的注册
  Observer(data, el)
  el.innerHTML = this.data[key] // 将值填入到模板上

  return this
}

// 观察者
function Observer (data, el) {
  // 遍历每个key值
  Object.keys(data).forEach(key => {
    // 当value有变化的拦截器
    let oldVal = data[key]
    Object.defineProperty(
      data,
      key,
      {
        enumerable: true,
        configurable: true,
        set: function (newVal) {
          if (oldVal === newVal) {
            return
          }
          console.log('oldVal newVal', oldVal, newVal)

          // 赋值
          oldVal = newVal
          // 通知数据变化, 可以再去render了
          Render(el, key, newVal)
        },
        get: function () {
          return oldVal
        }
      }
    )
  })
}

// 数据变化 触发 Render
function Render (el, key, newVal) {
  console.log(key, newVal)
  el.innerHTML = newVal
}

const el = document.getElementById('app')
const data = { appName: 'default' }
const vm = new Vue(data, el, 'appName')

data.appName = '我的值变了'
console.log(data.appName)

</script>
</body>
</html>

3 - 双向绑定实现 II

概念是: 初始化获取在模板上的数据,该数据对应data里的值,有不同,则触发从View到Model侧的同步。

// Compile View => Model
function Compile (that) {
  that.el.addEventListener('input', (e) => {
    // that.data[prop] = e.target.value
    console.log('这里绑定了', e.target.value)
  })
}

4 - Recap

本质: 对数据变化进行劫持, 对视图上数据变化进行事件监听

  1. 从Model => View, 当对象里的某参数变化时候(Observer),通过Object.defineProperty对参数值进行set 方法的拦截。从而通知 (Watcher) 去 render el.innerHTML 数据。
  2. 从View => Model, (Compile)方法,View通过得知该节点的数据是有变化,从而触发Model数据的变化。
  3. Watcher是连接Observer和Compile的桥梁

5 - Proxy与Object.defineProperty的优劣对比?

  • Object.defineProperty 是对对象中某个属性 为单位,进行数据拦截。
  • Proxy 监听的是整个对象。但是兼容性不是很好。另外返回的是一个新的对象。
<script>
const obj = {
  a: 1,
  b: 2
}
// 返回个新的对象
const proxy = new Proxy(obj, {
  get (target, key, value) {
    console.log(key, value)
    return target[key]
  },
  set (target, key, value) {
    console.log(key, value)
    target[key] = value
  }
})

proxy.a = '测试'
console.log(proxy.a)
</script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值