找回密码
 立即注册
首页 业界区 业界 手撸一个Vue(看不懂可以举报)

手撸一个Vue(看不懂可以举报)

庞悦 2025-8-7 09:31:58
手撸一个Vue

背景

vue是啥,有哪些基本功能,模板,script, style, 双向绑定一大堆,太多东西了,太难了,直接开始动手吧
仓库

https://github.com/listen80/two-way-binding
体验一下(pc上使用)

https://listen80.github.io/two-way-binding/public/
单文件

通过ajax获取类似.vue .html .tpl文件
  1. const parser = new DOMParser();
  2. export default (template) => {
  3.     const doc = parser.parseFromString(`<body>${template}</body>`, 'text/html');
  4.     const body = doc.querySelector('body')
  5.     return {
  6.         template: body.querySelector('template')?.content,
  7.         script: body.querySelector('script'),
  8.         style: body.querySelector('style'),
  9.     }
  10. };
复制代码
构建vue实例


  • 把script文本变成script运行
  • 把原始data变成reactive的形式,增加依赖收集
  • 解析template,扣出来指令,属性,方法,子组件等为了区分指令前缀使用@而不是v-
  • 挂载style样式增加
  • 替换当前实例挂载的元素,目前为止所有的元素(html, script, style)都已经使用上来了
  1.   // ...上面还有
  2.   /**
  3.    * 创建组件,加载组件脚本、样式和模板,并进行渲染
  4.    */
  5.   create() {
  6.     // 从配置选项中解构出目标元素和属性
  7.     const { el, props = {} } = this.options
  8.     // 从组件属性中解构出脚本、模板和样式
  9.     const { script, template, style } = this.componentProperties
  10.     // 1. 获取的ES6代码是模
  11.     // 获取脚本标签中的 ES6 模块代码
  12.     const es6ModuleCode = script.textContent;
  13.     // 2. 将代码转为blob URL(模拟模块文件)
  14.     // 创建一个包含 ES6 模块代码的 Blob 对象
  15.     const blob = new Blob([es6ModuleCode], { type: 'text/javascript' });
  16.     // 为 Blob 对象创建一个 URL
  17.     const url = URL.createObjectURL(blob);
  18.     // 3. 用动态import()加载该模块
  19.     // 动态导入模块
  20.     import(url).then(module => {
  21.       // 将样式添加到文档中
  22.       document.head.append(style)
  23.       // console.log(module.default); // 输出 'ES6 Module'
  24.       // 获取模块中的数据,若不存在则使用空对象
  25.       const data = module.default.data || {};
  26.       // 获取模块中的方法,若不存在则使用空对象
  27.       const methods = module.default.methods || {};
  28.       // 获取模块中的子组件,若不存在则使用空对象
  29.       const components = module.default.components || {};
  30.       // 将属性和数据合并到当前实例
  31.       Object.assign(this, props, data);
  32.       // 对当前实例进行数据观测
  33.       observe(this);
  34.       // this.data = data
  35.       // 编译模板并渲染
  36.       compile(template, this, methods, components);
  37.       // 终于明白这里为什么是replace
  38.       // 用模板替换目标元素
  39.       el.replaceWith(template)
  40.     }).catch(err => {
  41.       // 捕获模块加载失败的错误并打印
  42.       console.error('加载模块失败', err);
  43.     });
  44.   }
复制代码
总结

就这么结束了,是不是很简单,当然其中的细节很多,上文主要是描述核心思想点
本demo是没有使用虚拟dom,是dom跟数据直接绑定的,跟进vue3.6 vapor
水平有限,本文只是为了学习分享简单的示例,目的是为了了解运作机制,如果有纰漏请联系我

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册