当前位置:首页 > VUE

实现vue双向绑定

2026-01-08 08:42:14VUE

实现vue双向绑定

Vue双向绑定的实现原理

Vue的双向绑定主要通过数据劫持结合发布-订阅模式实现。核心是利用Object.defineProperty()或ES6的Proxy来劫持各个属性的gettersetter,在数据变动时发布消息给订阅者,触发相应的监听回调。

基于Object.defineProperty的实现

// 数据监听器
function observe(data) {
  if (!data || typeof data !== 'object') return
  Object.keys(data).forEach(key => {
    defineReactive(data, key, data[key])
  })
}

function defineReactive(obj, key, val) {
  observe(val) // 递归监听子属性
  const dep = new Dep() // 每个属性都有独立的Dep实例

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      Dep.target && dep.addSub(Dep.target) // 收集依赖
      return val
    },
    set(newVal) {
      if (newVal === val) return
      val = newVal
      dep.notify() // 通知所有订阅者
    }
  })
}

// 依赖收集器
class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  notify() {
    this.subs.forEach(sub => sub.update())
  }
}

// 订阅者
class Watcher {
  constructor(vm, exp, cb) {
    this.vm = vm
    this.exp = exp
    this.cb = cb
    this.value = this.get() // 触发getter添加自己到dep
  }
  get() {
    Dep.target = this
    const value = this.vm.data[this.exp] // 触发getter
    Dep.target = null
    return value
  }
  update() {
    const newVal = this.vm.data[this.exp]
    if (this.value !== newVal) {
      this.value = newVal
      this.cb.call(this.vm, newVal)
    }
  }
}

基于Proxy的实现(Vue 3.x)

function reactive(obj) {
  const handler = {
    get(target, key, receiver) {
      track(target, key)
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver)
      trigger(target, key)
      return true
    }
  }
  return new Proxy(obj, handler)
}

const targetMap = new WeakMap()
function track(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  dep.add(activeEffect)
}

function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const effects = depsMap.get(key)
  effects && effects.forEach(effect => effect())
}

模板编译过程

  1. 解析模板生成AST语法树
  2. 优化AST(标记静态节点)
  3. 生成渲染函数
  4. 创建Watcher实例,在数据变化时执行更新

双向绑定的完整流程

初始化时通过observe()递归遍历data对象 为每个属性创建Dep实例作为依赖收集器 编译模板时遇到指令如v-model创建Watcher Watcher在初始化时触发属性的getter被添加到Dep 数据变化时触发setter,Dep通知所有Watcher更新 Watcher更新触发组件重新渲染

常见指令实现示例

// v-model实现
function model(node, vm, exp) {
  node.value = vm[exp]
  new Watcher(vm, exp, value => {
    node.value = value
  })
  node.addEventListener('input', e => {
    vm[exp] = e.target.value
  })
}

性能优化考虑

  1. 避免深度监听整个对象,可指定具体属性
  2. 对数组的特殊处理(重写数组方法)
  3. 异步更新队列(nextTick机制)
  4. 计算属性和缓存机制减少不必要的计算

实现vue双向绑定

标签: 绑定双向
分享给朋友:

相关文章

vue 绑定实现

vue 绑定实现

Vue 数据绑定实现 Vue 的数据绑定主要通过响应式系统和模板编译实现,以下是核心实现方式: 双向绑定 (v-model) 适用于表单元素,自动同步输入值与 Vue 实例数据: <inpu…

vue 实现循环绑定

vue 实现循环绑定

Vue 实现循环绑定的方法 在 Vue 中,可以通过 v-for 指令实现循环绑定,用于渲染列表或对象数据。以下是几种常见的实现方式: 数组循环绑定 使用 v-for 遍历数组,可以通过索引或直接…

vue如何实现绑定

vue如何实现绑定

数据绑定基础 Vue 通过 v-bind 指令实现动态绑定 HTML 属性或组件 prop。基本语法为 v-bind:属性名="表达式",简写为 :属性名="表达式"。例如绑定 class 或 sty…

vue 双向实现原理

vue 双向实现原理

Vue 双向绑定的实现原理 Vue 的双向绑定主要通过 v-model 指令实现,其核心是结合数据劫持(Object.defineProperty 或 Proxy)和发布-订阅模式。以下是具体实现机制…

实现vue动态绑定

实现vue动态绑定

动态绑定的基本语法 在Vue中,使用v-bind指令或简写:实现动态绑定,将数据属性与HTML元素的属性关联起来。例如动态绑定class或style: <div v-bind:class="…

vue实现双向滚动

vue实现双向滚动

实现双向滚动的 Vue 方法 双向滚动通常指两个关联的滚动区域(如表格的头部和内容部分)同步滚动。以下是几种实现方式: 使用事件监听和 scroll 方法 通过监听一个滚动区域的 scroll 事…