模拟真实DOM转换成虚拟DOM(省略了AST语法树过程);
VNode数据替换过程;
VNode转换为真实DOM,更新到视图过程。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title></head><body><div id="root"><div class="c1"><div title="tt1" id="id">233</div><div title="tt2">{{ age }}</div><div title="tt3">{{ gender }}</div><ul><li>111{{name.firstName}}-{{age}}</li><li>{{name.lastName}}</li><li>3</li></ul></div></div><script>/***  #0.* 属于重要辅助函数*/// 如何得到虚拟dom// 即:将真实的DOM元素转换成js对象// 构建虚拟dom对象class VNode {constructor(tag, data, value, type) {this.tag = tag && tag.toLowerCase() // 标签名this.data = data // 属性this.value = value // 标签内容this.type = type // 节点类型this.children = [] // 子节点}// 添加虚拟dom子节点appendChild(vnode) {this.children.push(vnode)}}// TODO:#0.1 将真实dom转换成虚拟dom,这个函数当做 compiler 函数function getVNode(node) {const type = node.nodeTypelet _vnode = nullif (type === 1) {// 标签节点const tag = node.nodeName // 标签名const attrs = node.attributes // attributes 真实dom里存放标签属性 数组对象const data = {} // 虚拟dom中 属性就只是对象for (let i = 0; i < attrs.length; i++) {data[attrs[i].nodeName] = attrs[i].nodeValue // 数组每一项}const value = undefined_vnode = new VNode(tag, data, value, type)const children = node.childNodes// 子节点for (let i = 0; i < children.length; i++) {_vnode.appendChild(getVNode(children[i]))}} else if (type === 3) {// 文本节点_vnode = new VNode(undefined, undefined, node.nodeValue, type)}// 将每一个虚拟节点返回return _vnode}// TODO:#0.2 将虚拟 DOM 转换成真正的 DOMfunction parseVNode(vnode) {let oDom = null// 标签节点if (vnode.type === 1) {oDom = document.createElement(vnode.tag)const data = vnode.data// 属性节点Object.keys(data).forEach((key) => {let attrName = keylet attrValue = data[key]oDom.setAttribute(attrName, attrValue)})// 子节点for (let i = 0; i < vnode.children.length; i++) {oDom.appendChild(parseVNode(vnode.children[i]))}} else if (vnode.type === 3) {// 创建文本节点oDom = document.createTextNode(vnode.value)}return oDom}// 对象解析函数 a.b.c.d这种格式function getValueByKey(obj, str) {const arr = str.split('.')let prop = nullwhile ((prop = arr.shift())) {obj = obj[prop]}return obj}const reg = /\{\{(.+?)\}\}/g// TODO:#0.3 将 带有 坑的 Vnode 与数据 data 结合, 得到 填充数据的 VNode: 模拟 AST -> VNodefunction combine(vnode, data) {let _type = vnode.typelet _data = vnode.datalet _value = vnode.valuelet _tag = vnode.taglet _children = vnode.childrenlet _vnode = nullif (_type === 3) {// 文本节点// 对文本处理_value = _value.replace(reg, function (_, g) {return getValueByKey(data, g.trim())})// 重新创建虚拟dom对象_vnode = new VNode(_tag, _data, _value, _type)} else if (_type === 1) {// 元素节点// 重新创建虚拟dom对象_vnode = new VNode(_tag, _data, _value, _type)_children.forEach((_subvnode) => _vnode.appendChild(combine(_subvnode, data)))}return _vnode}function MyVue(obj) {// 习惯: 内部的数据使用下划线 开头, 只读数据使用 $ 开头// 数据this._data = obj.data// 根元素let el = document.querySelector(obj.el) // vue 是字符串, 这里是 DOM// 根模板this._template = el// 为什么要拿父节点this._parent = this._template.parentNode// TODO:#1this.mount()}MyVue.prototype.mount = function () {// TODO:#2 需要提供一个 render 方法: 生成 虚拟 DOM// 这里得到了一个未执行的函数  该函数执行后的结果是合并数据后的VNodethis.render = this.createRenderFunction()// 视图更新this.mountComponent()}MyVue.prototype.mountComponent = function () {let mount = () => {// TODO:#4// this.render() 会得到数据合并后的VNode// 更新函数执行得到真实DOM并渲染到页面this.update(this.render())}// TODO:#3mount.call(this) // 本质应该交给 watcher 来调用}// 渲染函数MyVue.prototype.createRenderFunction = function () {// #0.1  VNode 模拟 AST   获得VNode// 函数柯里化 缓存 astconst ast = getVNode(this._template)return function () {// #0.3 将 带有 坑的 VNode 转换为 待数据的 VNodereturn combine(ast, this._data)}}// 更新视图MyVue.prototype.update = function (vnode) {// 转换成真实DOMlet node = parseVNode(vnode)this._parent.replaceChild(node, document.querySelector('#root'))}// 创建实例new MyVue({el: '#root',data: {name: { firstName: 'wang', lastName: 'wu' },age: 18,gender: '男'}})</script></body>
</html>

简易 Vue 构建--篇三相关推荐

  1. 简易 Vue 构建--篇四

    data数据响应式.数据代理 <!DOCTYPE html> <html lang="en"><head><meta charset=&q ...

  2. 简易 Vue 构建--篇二

    1.将 HTML DOM 转换成 js 对象 2.将 js 对象转换成 HTML DOM <!DOCTYPE html> <html lang="en">& ...

  3. 简易 Vue 构建--篇一

    真实 DOM 中的模板数据替换 <!DOCTYPE html> <!DOCTYPE html> <html lang="en"><head ...

  4. Vue实战篇三十:实现一个简易版的头条新闻

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

  5. Vue实战篇三十三:实现新闻的浏览历史

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

  6. Vue实战篇三十一:实现一个改进版的头条新闻

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

  7. 简易 Vue 构建--终

    简易 Dep/Watcher <!DOCTYPE html> <html lang="en"><head><meta charset=&q ...

  8. Vue实战篇二十九:模拟一个简易留言板

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

  9. Vue实战篇一: 使用Vue搭建注册登录界面

    系列文章目录 Vue基础篇一:编写第一个Vue程序 Vue基础篇二:Vue组件的核心概念 Vue基础篇三:Vue的计算属性与侦听器 Vue基础篇四:Vue的生命周期(秒杀案例实战) Vue基础篇五:V ...

最新文章

  1. js 正则表达式奇偶字符串替换_Python中的正则表达式及其常用匹配函数用法简介...
  2. ubuntu 系统相关有用的配置
  3. Python中使用turtle绘制棋盘详解
  4. 二值化_处理连续型特征:二值化与分段
  5. CMSIS-DAP和J-Link、ST-Link是什么关系?
  6. es统计有多少个分组_ES 24 - 如何通过Elasticsearch进行聚合检索 (分组统计)
  7. AI 人工智能与半导体论坛:
  8. 蔡工RK系列Android驱动开发入门视频课程
  9. sap erp 消息服务器,九慧信息|SAP_SAP ERP_SAP系统_SAP s/4hana
  10. C语言中取值符(*)与取地址符()
  11. 爱老虎油和你探索flash中的对象
  12. simi.city forum.php,simicitybuildit欧米伽建筑代号什么意思
  13. 数学笔记:FFT(快速傅里叶变换)
  14. Yolov5部署训练及代码解读
  15. QLocale 获取系统语言简写
  16. 诺基亚S40第3版 (j2me的天堂)
  17. 发疯之后创业能更成功吗 leo看赢在中国第三季 5
  18. mac idea 常用快捷键总结
  19. 《人人都是产品经理》思考
  20. 计算机自带音乐怎么放,怎么使用win10自带音乐播放器?windows10系统Xbox Music的使用方法...

热门文章

  1. 留住用户的APP弹窗设计素材模板
  2. linux7配网卡,CentOS 7 配置网卡
  3. linux系统冒号模式map怎么用,shell中冒号 : 用途说明
  4. FeatureLayer.FeatureClass.Feature --以及图层最容易理解的讲解;如有巧合,一定是别人抄袭(Arcgis辅助理解)
  5. OpenGL学习笔记:画点、直线和多边形(第一讲)
  6. python开启新代码块_20课零基础快速学python完成简单邮件完整邮件代码块
  7. vmware+centeros7安装JavaJDK
  8. mysql并发插入死锁_MySQL: 并发replace into的死锁问题分析-阿里云开发者社区
  9. java ssl 加密传输_java线程之四 SSL加密传输
  10. java json 修改字段_我们如何使用Java中的Jackson来更改JSON中的字段名称?