当前位置:首页 > VUE

简单实现vue双向绑定

2026-02-24 23:00:10VUE

实现 Vue 双向绑定的核心原理

Vue 的双向绑定主要通过数据劫持和发布-订阅模式实现。以下是一个简化版的实现示例:

数据劫持(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, key, cb) {
    this.vm = vm
    this.key = key
    this.cb = cb

    Dep.target = this
    this.vm[this.key] // 触发 getter 收集依赖
    Dep.target = null
  }

  update() {
    this.cb.call(this.vm, this.vm[this.key])
  }
}

实现编译器(Compile)

class Compile {
  constructor(el, vm) {
    this.vm = vm
    this.el = document.querySelector(el)
    this.fragment = null
    this.init()
  }

  init() {
    if (this.el) {
      this.fragment = this.nodeToFragment(this.el)
      this.compileElement(this.fragment)
      this.el.appendChild(this.fragment)
    }
  }

  nodeToFragment(el) {
    const fragment = document.createDocumentFragment()
    let child = el.firstChild
    while (child) {
      fragment.appendChild(child)
      child = el.firstChild
    }
    return fragment
  }

  compileElement(el) {
    const childNodes = el.childNodes
    Array.from(childNodes).forEach(node => {
      const text = node.textContent
      const reg = /\{\{(.*?)\}\}/g

      if (this.isTextNode(node) && reg.test(text)) {
        this.compileText(node, RegExp.$1)
      }

      if (node.childNodes && node.childNodes.length) {
        this.compileElement(node)
      }
    })
  }

  compileText(node, key) {
    const initText = this.vm[key]
    this.updateText(node, initText)
    new Watcher(this.vm, key, value => {
      this.updateText(node, value)
    })
  }

  updateText(node, value) {
    node.textContent = typeof value === 'undefined' ? '' : value
  }

  isTextNode(node) {
    return node.nodeType === 3
  }
}

整合实现简易 Vue

class MyVue {
  constructor(options) {
    this.data = options.data
    observe(this.data)
    new Compile(options.el, this)
    Object.keys(this.data).forEach(key => {
      this.proxyData(key)
    })
  }

  proxyData(key) {
    Object.defineProperty(this, key, {
      enumerable: true,
      configurable: true,
      get() {
        return this.data[key]
      },
      set(newVal) {
        this.data[key] = newVal
      }
    })
  }
}

使用示例

<div id="app">
  {{ message }}
</div>

<script>
  const vm = new MyVue({
    el: '#app',
    data: {
      message: 'Hello Vue!'
    }
  })

  setTimeout(() => {
    vm.message = 'Updated!'
  }, 2000)
</script>

实现要点说明

  1. 通过 Object.defineProperty 劫持数据属性的 getter 和 setter
  2. 每个属性维护一个 Dep 实例来管理所有 Watcher
  3. Watcher 在初始化时触发 getter 将自己添加到 Dep 中
  4. 数据变化时通过 setter 通知 Dep,Dep 再通知所有 Watcher 更新视图
  5. Compile 解析模板中的指令和插值表达式
  6. 通过代理使 vm.key 可以直接访问 vm.data.key

这个实现展示了 Vue 双向绑定的核心原理,实际 Vue 的实现更加复杂,包含虚拟 DOM、diff 算法等优化。

简单实现vue双向绑定

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

相关文章

vue双向实现数据

vue双向实现数据

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

vue实现双休绑定

vue实现双休绑定

Vue 实现双向绑定 Vue.js 通过 v-model 指令实现双向绑定,主要用于表单输入元素(如 <input>、<textarea>、<select>)与组件…

vue双向实现原理

vue双向实现原理

Vue 双向数据绑定的实现原理 Vue 的双向数据绑定主要通过数据劫持结合发布-订阅模式实现,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。…

vue实现数据双向

vue实现数据双向

在Vue中实现数据双向绑定主要依靠v-model指令,它结合了属性绑定和事件监听,适用于表单元素或自定义组件。以下是具体实现方式: 基础表单元素的双向绑定 对于原生表单元素(如input、text…

vue 实现双向绑定

vue 实现双向绑定

Vue 双向绑定的实现原理 Vue 的双向绑定主要通过 v-model 指令实现,底层基于数据劫持和发布-订阅模式。以下是核心实现机制: 数据劫持(响应式系统) Vue 使用 Object.defi…

vue怎么实现双向

vue怎么实现双向

Vue 双向绑定的实现方式 Vue 中实现双向绑定的核心机制是 v-model 指令,它结合了属性绑定和事件监听,适用于表单元素或自定义组件。 表单元素的双向绑定 在原生表单元素(如 input、…