当前位置:首页 > JavaScript

js实现vue

2026-04-05 06:44:18JavaScript

使用原生 JavaScript 实现类似 Vue 的功能

原生 JavaScript 可以通过数据绑定、观察者模式和虚拟 DOM 等技术实现类似 Vue 的功能。以下是一个简化版的实现示例:

class MiniVue {
  constructor(options) {
    this.$options = options
    this.$data = options.data()
    this.$el = document.querySelector(options.el)

    this.proxyData()
    this.observe(this.$data)
    this.compile(this.$el)
  }

  proxyData() {
    for (let key in this.$data) {
      Object.defineProperty(this, key, {
        get() {
          return this.$data[key]
        },
        set(newVal) {
          this.$data[key] = newVal
        }
      })
    }
  }

  observe(data) {
    if (!data || typeof data !== 'object') return

    Object.keys(data).forEach(key => {
      let value = data[key]
      const dep = new Dep()

      Object.defineProperty(data, key, {
        get() {
          Dep.target && dep.addSub(Dep.target)
          return value
        },
        set(newVal) {
          if (newVal === value) return
          value = newVal
          dep.notify()
        }
      })

      this.observe(value)
    })
  }

  compile(el) {
    const nodes = el.childNodes

    nodes.forEach(node => {
      if (node.nodeType === 1) {
        this.compileElement(node)
      } else if (node.nodeType === 3) {
        this.compileText(node)
      }

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

  compileElement(node) {
    const attrs = node.attributes

    Array.from(attrs).forEach(attr => {
      if (attr.name.startsWith('v-')) {
        const dir = attr.name.substring(2)
        const exp = attr.value

        if (dir === 'model') {
          this.handleModel(node, exp)
        }

        node.removeAttribute(attr.name)
      }
    })
  }

  compileText(node) {
    const reg = /\{\{(.+?)\}\}/
    const text = node.textContent

    if (reg.test(text)) {
      const exp = RegExp.$1.trim()
      new Watcher(this, exp, (val) => {
        node.textContent = text.replace(reg, val)
      })

      node.textContent = text.replace(reg, this[exp])
    }
  }

  handleModel(node, exp) {
    node.value = this[exp]

    new Watcher(this, exp, (val) => {
      node.value = val
    })

    node.addEventListener('input', (e) => {
      this[exp] = e.target.value
    })
  }
}

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

    Dep.target = this
    this.value = vm[exp]
    Dep.target = null
  }

  update() {
    const newVal = this.vm[this.exp]
    if (newVal !== this.value) {
      this.value = newVal
      this.cb(newVal)
    }
  }
}

使用示例

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

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

实现原理说明

  1. 数据代理:通过 proxyData 方法将 data 中的属性代理到 Vue 实例上,可以直接通过 this.xxx 访问 data 中的属性

  2. 数据劫持:使用 Object.defineProperty 对数据进行劫持,当数据变化时通知依赖更新

  3. 依赖收集:通过 Dep 类管理依赖,Watcher 类作为观察者,在数据变化时执行回调

  4. 模板编译:通过 compile 方法解析模板,处理指令和插值表达式

    js实现vue

  5. 双向绑定v-model 指令实现了双向数据绑定,将输入框的值与数据进行关联

功能扩展方向

  1. 计算属性:可以添加 computed 选项,通过缓存计算结果优化性能

  2. 方法处理:添加 methods 选项,处理用户定义的方法

    js实现vue

  3. 生命周期:实现 created、mounted 等生命周期钩子

  4. 组件系统:支持组件化开发,实现组件注册和嵌套

  5. 虚拟DOM:引入虚拟DOM提高渲染性能,实现更高效的DOM更新

这个实现展示了 Vue 的核心原理,实际 Vue 源码更为复杂,包含更多优化和功能。

标签: jsvue
分享给朋友:

相关文章

vue 实现菜单

vue 实现菜单

Vue 实现菜单的方法 使用 Vue 实现菜单可以通过多种方式,以下是几种常见的方法: 使用 Vue Router 实现动态路由菜单 通过 Vue Router 可以动态生成菜单,根据路由配置自动渲…

vue插槽实现

vue插槽实现

插槽的基本概念 Vue插槽(Slot)是一种内容分发机制,允许父组件向子组件传递模板片段,子组件通过<slot>标签定义接收位置。插槽的核心作用是增强组件的灵活性和复用性。 默认插槽 子…

vue实现grid

vue实现grid

Vue 实现 Grid 布局的方法 使用 CSS Grid 布局 Vue 可以结合 CSS Grid 布局实现灵活的网格系统。CSS Grid 是现代浏览器原生支持的布局方案,无需额外依赖库。 &l…

分页实现vue

分页实现vue

分页实现(Vue) 在Vue中实现分页功能通常需要结合前端分页逻辑和后端API支持。以下是两种常见的实现方式: 前端分页实现 适用于数据量较小的情况,直接在客户端完成分页逻辑。 <templ…

vue实现复制

vue实现复制

Vue 实现复制功能 在 Vue 中实现复制功能可以通过多种方式完成,以下是几种常见的方法: 方法一:使用 Clipboard API Clipboard API 是现代浏览器提供的一种原生 AP…

vue实现加载

vue实现加载

Vue 实现加载功能的方法 使用 v-if 或 v-show 控制加载状态 通过数据绑定控制加载动画的显示与隐藏。v-if 会完全移除 DOM 元素,v-show 只是切换 display 属性。…