当前位置:首页 > JavaScript

js 实现vue模板

2026-03-01 15:01:57JavaScript

实现 Vue 模板的核心思路

Vue 模板的核心是通过数据绑定和虚拟 DOM 实现动态渲染。以下是一个简化版的实现思路:

数据劫持与响应式

通过 Object.definePropertyProxy 监听数据变化:

js 实现vue模板

function observe(data) {
  if (!data || typeof data !== 'object') return
  Object.keys(data).forEach(key => {
    let value = data[key]
    const dep = new Dep()
    observe(value)
    Object.defineProperty(data, key, {
      get() {
        Dep.target && dep.addSub(Dep.target)
        return value
      },
      set(newVal) {
        if (newVal === value) return
        value = newVal
        observe(newVal)
        dep.notify()
      }
    })
  })
}

依赖收集系统

实现一个简单的发布-订阅模式:

class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  notify() {
    this.subs.forEach(sub => sub.update())
  }
}
Dep.target = null

编译模板

将模板字符串解析为 AST 并生成渲染函数:

js 实现vue模板

function compile(template) {
  const ast = parse(template) // 简化的解析过程
  return generate(ast) // 生成渲染函数
}

function parse(template) {
  // 实现简单的标签和插值解析
  const stack = []
  let root
  let currentParent

  parseHTML(template, {
    start(tag, attrs) {
      const element = { tag, attrs, children: [] }
      if (!root) {
        root = element
      } else if (currentParent) {
        element.parent = currentParent
        currentParent.children.push(element)
      }
      stack.push(element)
      currentParent = element
    },
    end() {
      stack.pop()
      currentParent = stack[stack.length - 1]
    },
    chars(text) {
      if (!currentParent) return
      currentParent.children.push({
        type: 3,
        text
      })
    }
  })
  return root
}

虚拟 DOM 与渲染

实现一个简单的虚拟 DOM 和 patch 算法:

class VNode {
  constructor(tag, data, children, text) {
    this.tag = tag
    this.data = data
    this.children = children
    this.text = text
  }
}

function createElement(vnode) {
  if (vnode.text) return document.createTextNode(vnode.text)
  const el = document.createElement(vnode.tag)
  vnode.data.attrs.forEach(attr => {
    el.setAttribute(attr.name, attr.value)
  })
  vnode.children.forEach(child => {
    el.appendChild(createElement(child))
  })
  return el
}

function patch(oldVnode, vnode) {
  if (!oldVnode) {
    return createElement(vnode)
  }
  // 简化的 diff 算法
  if (oldVnode.tag !== vnode.tag) {
    const parent = oldVnode.el.parentNode
    parent.insertBefore(createElement(vnode), oldVnode.el)
    parent.removeChild(oldVnode.el)
    return
  }
  // 更新属性和子节点
  updateAttrs(oldVnode, vnode)
  updateChildren(oldVnode, vnode)
}

组件系统实现

实现基础的组件构造函数:

class Vue {
  constructor(options) {
    this.$options = options
    this._data = options.data
    observe(this._data)
    this.$mount(options.el)
  }

  $mount(el) {
    this.$el = document.querySelector(el)
    const updateComponent = () => {
      const vnode = this.$options.render.call(this)
      patch(this._vnode, vnode)
      this._vnode = vnode
    }
    new Watcher(this, updateComponent)
  }
}

class Watcher {
  constructor(vm, fn) {
    this.vm = vm
    this.getter = fn
    this.get()
  }

  get() {
    Dep.target = this
    this.getter()
    Dep.target = null
  }

  update() {
    this.get()
  }
}

使用示例

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  },
  render() {
    return new VNode('div', { attrs: [{ name: 'id', value: 'app' }] }, [
      new VNode(null, null, null, this._data.message)
    ])
  }
})

这个实现包含了 Vue 的核心功能:数据响应式、虚拟 DOM、模板编译和组件系统。实际 Vue 的实现更加复杂,包含更多优化和功能。

标签: 模板js
分享给朋友:

相关文章

js实现跳转

js实现跳转

使用 window.location 跳转 通过修改 window.location.href 或直接使用 window.location 实现页面跳转,适用于普通跳转或带参数的 URL。 // 方…

js实现复制功能

js实现复制功能

使用 document.execCommand 方法 这种方法适用于较旧的浏览器,但在现代浏览器中可能被逐步淘汰。通过创建一个临时的 textarea 元素,将文本内容放入其中,然后执行复制命令。…

js防抖和节流实现

js防抖和节流实现

防抖(Debounce)的实现 防抖的核心思想是在事件被触发后,延迟执行回调函数。如果在延迟时间内再次触发事件,则重新计时。适用于输入框搜索、窗口大小调整等场景。 function debounce…

js实现交换

js实现交换

交换变量的方法 在JavaScript中,交换两个变量的值有多种方法。以下是常见的几种实现方式: 使用临时变量 通过引入一个临时变量来存储其中一个变量的值,实现交换: let a = 1; le…

js实现吸色

js实现吸色

使用Canvas实现吸色功能 通过Canvas的getImageData方法获取像素颜色数据。创建一个Canvas元素,将目标图像绘制到Canvas上,通过鼠标事件获取坐标对应的颜色值。 c…

js实现下拉菜单

js实现下拉菜单

使用HTML和CSS创建基础结构 HTML部分需要包含一个触发下拉的按钮和隐藏的下拉菜单内容: <div class="dropdown"> <button class="dr…