Vue源码分析(虚拟DOM与优化)
2020-08-26 16:00
731 查看
概念
使用步骤 1.编写 页面 模板 1.直接在HTML标签中写 2.使用template 3.使用单文件(<template>) 2.创建Vue实例 1.在Vue 的构造函数中:data,methods,computer,watcher,props,... 3.将Vue挂载到页面中(mount) 数据驱动模型 Vue执行流程 1.获得模板:模板中有‘坑’ 2.利用Vue构造函数提供的数据来‘填坑’,就可以得到页面显示的'标签'了 3.替换原来有坑的标签 Vue 利用 我们提供的数据 和 页面的 模板 生成了一个新的HTML标签(node元素),替换到了 页面中 放置模板的位置 虚拟DOM 目标: 1. 怎么将真正的DOM转换为虚拟DOM 2.怎么将虚拟DOM转换为真正的DOM 思路与深拷贝类似 概念 1.柯里化: 一个函数原本有多个参数 只传入一个参数生成一个新函数 ,由新函数接受到新的参数运行得到的结构 2.偏函数: 参考柯里化, 传入一部分参数 3.高阶函数: 一个函数参数是一个函数,该函数对参数这个函数进行加工,得到一个函数,这个加工用的函数就是高阶函数 为什么要使用柯里化 为了提升性能 使用柯里化可以缓存一部分能力 使用两个例子说明 1.判断元素 Vue 本质上是使用HTML的字符串作为模板,将字符串的 模板 转换为AST 再转换为VNode 1.模板-AST 2.AST-VNode 3.VNode-DOM 最消耗性能的 是模板-AST 例子 字符串 1 + 2 * ( 3 + 4 ) 解析该表达式,得到结果 一般将此转换为 ‘波兰式’ 表达式 然后用栈进行运算 在Vue中每一个标签可以是真正的HTML标签,也可以是自定义组件,怎么区分 在vue源码中,将所有可用的HTML标签 已经存起来, 假设这里只考虑 几个标签 ```js let tags = 'div,p,a,img'.split(',') ``` 一个函数,判断标签名是否为 内置标签 ```js function isHTML( tagName ){ tagName = tagName.toLowerCase() //tags.indexOf(tagName) >-1 return true for(let i=0;i<...){ if(tagName === tags[i])return true } return false }//也可以用indexOf判断 ``` 模板是任意编写的,可以写的很简单,也可以写的很复杂,indexOf内部也要循环 如果有6个内置标签 模板有10个,就得循环60次 使用柯里化 ```js let tags = 'div,p,a,img'.split(',') function makeMap( keys ) { let set = {} keys.forEach(key => { set[key] = true }); return function ( tagName ) { //!!改为boolean return !!set[ tagName.toLowerCase() ] } } let isHTML = makeMap( tags ) //不用再做循环 ``` 2.虚拟DOM 的render vue 项目 模板 转换为AST 转换几次? 1.页面加载渲染 一次 2.每一个属性(响应式)数据发生变化 要渲染 3.watch computed 等等 render的作用是将 虚拟DOM 转换为 真正的DOM 加载到页面中 //虚拟DOM 可以降级为AST 一个项目运行时 模板不会变 抽象语法树不会变 我们可以将代码优化 将虚拟DOM 缓存起来 生成函数 函数只需要传入数据 得到真正的DOM
源码模拟与分析
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="app"> <div> <div>h1</div> <div>h2</div> <div>h3</div> </div> <div> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> </div> </div> </body> <script> //为什么使用虚拟DOM ? 性能 //<div> => {tag: 'div' } //文本节点 => {tag : undefined , value: '文本节点' } //<div title='1' class='c'> => {tag : 'div' data: {title: 1, class : 'c'}} //<div><div></div></div> {tag: 'div', children: [ {{tag: 'div'}]} class VNode{ constructor(tag, data, value, type,){ this.tag = tag && tag.toLowerCase() this.data = data this.value = value this.type = type this.children = [] } appendChild( vnode ){ this.children.push(vnode) } } //递归 来遍历DOM 生成虚拟DOM //Vue 中的源码使用 栈结构 ,使用栈存储 父元素 来实现递归生成 function getVNode( node ) { let nodeType = node.nodeType let _vnode = null if(nodeType === 1 ){ //元素 let nodeName = node.nodeName let attrs = node.attributes let _attrObj = {} //遍历属性节点 nodeType=2 for (let i = 0; i < attrs.length; i++) { _attrObj[ attrs[i].nodeName ] = attrs[i].nodeValue } _vnode = new VNode(nodeName, _attrObj, undefined, nodeType) //考虑 node的子元素 //递归 let childNodes = node.childNodes for (let i = 0; i < childNodes.length; i++) { _vnode.appendChild( getVNode(childNodes[i] ) ) } }else if(nodeType === 3 ){ _vnode = new VNode(undefined, undefined, node.nodeValue, nodeType) } return _vnode } let app = document.querySelector('#app') let vapp = getVNode(app) console.log( vapp ) //将VNode 转换为真正的dom function parseVNode( vnode) { let type = vnode.type let _node = null if( type === 3){ return document.createTextNode( vnode.value ) }else if( type === 1 ){ _node = document.createElement( vnode.tag ) //属性 //data 键值对 let data = vnode.data Object.keys(data).forEach( (key) => { let attrName = key let attrValue = data[key] _node.setAttribute( attrName, attrValue) }) //子元素 //递归转换子元素 (虚拟dom) let children = vnode.children children.forEach( subvnode => { _node.appendChild(parseVNode(subvnode)) }) } return _node } //在真正的vue也是使用 递归+加栈 let dom = parseVNode(vapp) console.log(dom) </script> </html>
vue源码 虚拟dom对象
相关文章推荐
- vue 虚拟dom的patch源码分析
- Vue学习之源码分析--从template到DOM(Vue.js源码角度看内部运行机制)(九)
- vue2.0的虚拟DOM渲染思路分析
- vue源码学习一之响应式原理及虚拟DOM
- vue.js源码剖析——虚拟 DOM
- vue 源码解析之虚拟Dom-render
- Vue学习之源码分析--Vue.js异步更新DOM策略及nextTick(八)
- jQuery源码分析-12 DOM操作-Manipulation-核心函数jQuery.buildFragment()
- Vue 2.3.4源码分析之视图渲染
- vue 虚拟字段,DOM及时更新,双向绑定等问题
- jQuery-1.9.1源码分析系列(十一)DOM操作续之克隆节点
- jQuery-1.9.1源码分析系列(十一) DOM操作续——克隆节点
- Android应用层View绘制流程与源码分析,性能优化
- 深入Vue-Router源码分析路由实现原理
- Vue虚拟DOM和Diff算法
- 浅谈vue中的虚拟dom
- jQuery("dom").get()的源码分析
- VUE系列: 源码分析-逻辑层
- 【Vue源码】Vue中DOM的异步更新策略以及nextTick机制
- VUE、React中虚拟DOM(virtual DOM)技术 VNode及diff算法介绍