当前位置:首页 > VUE

实现自己的vue

2026-02-19 14:05:34VUE

实现一个简易 Vue 框架

要实现一个类似 Vue 的响应式框架,需要理解其核心机制:数据劫持、依赖收集和派发更新。以下是关键实现步骤:

数据劫持(响应式系统)

使用 Object.definePropertyProxy 拦截数据访问和修改:

实现自己的vue

class Observer {
  constructor(data) {
    this.walk(data)
  }

  walk(data) {
    if (!data || typeof data !== 'object') return
    Object.keys(data).forEach(key => {
      this.defineReactive(data, key, data[key])
    })
  }

  defineReactive(obj, key, val) {
    const dep = new Dep()
    this.walk(val) // 递归处理嵌套对象
    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())
  }
}

Dep.target = null

观察者(Watcher)

连接响应式数据和视图更新:

实现自己的vue

class Watcher {
  constructor(vm, key, cb) {
    this.vm = vm
    this.key = key
    this.cb = cb
    Dep.target = this
    this.oldValue = vm[key] // 触发getter
    Dep.target = null
  }

  update() {
    const newValue = this.vm[this.key]
    if (newValue !== this.oldValue) {
      this.cb(newValue)
      this.oldValue = newValue
    }
  }
}

编译器

解析模板并建立数据绑定:

class Compiler {
  constructor(el, vm) {
    this.el = document.querySelector(el)
    this.vm = vm
    this.compile(this.el)
  }

  compile(node) {
    Array.from(node.childNodes).forEach(node => {
      if (this.isElement(node)) {
        this.compileElement(node)
      } else if (this.isText(node)) {
        this.compileText(node)
      }
      if (node.childNodes && node.childNodes.length) {
        this.compile(node)
      }
    })
  }

  compileElement(node) {
    Array.from(node.attributes).forEach(attr => {
      if (this.isDirective(attr.name)) {
        const dir = attr.name.substring(2)
        this[dir] && this[dir](node, attr.value)
      }
    })
  }

  compileText(node) {
    const reg = /\{\{(.*?)\}\}/
    if (reg.test(node.textContent)) {
      const key = RegExp.$1.trim()
      this.update(node, key, 'text')
    }
  }

  text(node, key) {
    this.update(node, key, 'text')
  }

  model(node, key) {
    this.update(node, key, 'model')
    node.addEventListener('input', e => {
      this.vm[key] = e.target.value
    })
  }

  update(node, key, type) {
    const updaterFn = this[type + 'Updater']
    updaterFn && updaterFn(node, this.vm[key])
    new Watcher(this.vm, key, value => {
      updaterFn(node, value)
    })
  }

  textUpdater(node, value) {
    node.textContent = value
  }

  modelUpdater(node, value) {
    node.value = value
  }

  isDirective(attr) {
    return attr.startsWith('v-')
  }

  isElement(node) {
    return node.nodeType === 1
  }

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

整合框架

创建主类连接各模块:

class MyVue {
  constructor(options) {
    this.$options = options
    this.$data = options.data
    new Observer(this.$data)
    this.proxyData(this.$data)
    new Compiler(options.el, this)
  }

  proxyData(data) {
    Object.keys(data).forEach(key => {
      Object.defineProperty(this, key, {
        get() {
          return data[key]
        },
        set(newVal) {
          data[key] = newVal
        }
      })
    })
  }
}

使用示例

<div id="app">
  <p>{{ message }}</p>
  <input v-model="message">
</div>

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

实现要点说明

  1. 响应式系统通过拦截对象属性的访问和修改来实现
  2. 每个响应式属性都有对应的 Dep 实例管理依赖
  3. Watcher 在初始化时会触发属性的 getter 进行依赖收集
  4. 数据变化时通过 setter 触发 Dep 的通知机制
  5. 编译器解析模板中的指令和插值表达式
  6. 通过代理将 data 的属性映射到 Vue 实例上

这个实现包含了 Vue 最核心的响应式原理,实际 Vue 还包含虚拟 DOM、组件系统等更多复杂功能,但以上代码已经展示了其最基础的工作机制。

标签: 自己的vue
分享给朋友:

相关文章

vue实现菜单调用

vue实现菜单调用

Vue 实现动态菜单的常见方法 基于路由配置生成菜单 Vue Router 的路由配置可以天然转化为菜单结构,适合权限与路由绑定的系统: // router/index.js const route…

vue中登陆实现逻辑

vue中登陆实现逻辑

Vue 中登录实现逻辑 前端实现逻辑 表单验证 使用 Vue 的表单验证库(如 VeeValidate)或自定义验证规则,确保用户输入的账号和密码符合要求。例如,检查邮箱格式、密码长度等。 发送登录…

vue实现拖放

vue实现拖放

Vue 实现拖放功能 Vue 中实现拖放功能通常可以通过 HTML5 的原生拖放 API 或第三方库(如 vuedraggable)来实现。以下是两种方法的详细说明。 使用 HTML5 原生拖放 A…

vue实现input

vue实现input

Vue 实现 Input 输入框的方法 基本双向绑定 使用 v-model 指令实现双向数据绑定,适用于大多数表单场景: <template> <input v-model=…

vue实现布局

vue实现布局

Vue 实现布局方法 Vue 提供了多种方式实现页面布局,可以通过组件化、CSS 框架或自定义样式完成。以下是几种常见方法: 使用 CSS Flexbox 或 Grid 通过 Vue 单文件组件结…

vue实现123456

vue实现123456

Vue 实现数字 123456 的显示 在 Vue 中显示数字 123456 非常简单,可以通过以下方法实现: 方法一:直接在模板中显示 <template> <div>…