微型Vue框架构建Part4——Render渲染前
【微型Vue框架构建Part4——Render渲染前】微型Vue框架构建Part1——基本目录结构
微型Vue框架实现Part2——数据代理实现
微型Vue框架构建Part3——$Mount方法实现
概述
- 在上文 $Mount方法实现中,我们根据入口点分析了分析了HTML结构,且为每一个HTML节点构建了虚拟DOM(vnode)。本文将在此基础上实现Render渲染前的一些准备工作,为Render渲染数据打下基础。
- 后面渲染数据时,我们就能根据模板语法和vnode的关系,找到对应的数据变量,通过虚拟DOM渲染到页面中
- 目标概览
文章图片
- HTML代码
文本内容: {{content}} {{info.school}}
- 根据上文,为每一个节点构建的虚拟DOM(vnode),如下图
- 我们能看到打印出的vnode节点中,text属性值就是页面中用到模板语法
文章图片
入口方法——parpaerRender
/** * mount方法的具体实现 * @param {*} vm * @param {*} el 挂载节点对应的真实DOM */ function mount(vm, el) { // 第一步:构建虚拟DOM const rootDom = getDom(el); vm._vnode = contrucVNode(vm, rootDom, null); // 第二步:收集DOM节点和模板语法的映射关系——待实现 parpaerRender(vm, vm._vnode); }
解析vnode和模板愈发的关系
- 我们不仅需要知道页面中哪些地方用到了模板语法,还需要知道他们之间映射关系。后期我们修改数据时能够同步页面中的展示内容。
- 什么样的映射关系?:
- 单个的vnode节点中,用到了哪些模板语法
- 单个的模板语法,有哪些vnode节点用到了。
- 使用ES6中 Map对象
- nodeType为3,表示是以一个文本节点
- analysisTemplteString:分析模板
/** * 分析虚拟DOM中的模板语法和文本 * @param {*} vm * @param {*} vnode */ export function parpaerRender(vm, vnode) { if (vnode.nodeType === 3) { analysisTemplteString(vnode); }for (let i = 0; i < vnode.children.length; i++) { parpaerRender(vm, vnode.children[i]); } }
### 代码实现——analysisTemplteString()
- 用正则表达式找到单个vnode中有哪些模板语法,形如{{xxx}}
- 有使用到模板语法的,就拿去生成对应的映射关系
/** * 分析文本类型的虚拟DOM * @param {*} vnode */ function analysisTemplteString(vnode) { console.log("-vnode--", vnode); const template = vnode.text.match(/{{[\s|a-zA-Z0-9_.|\s]+}}/g); if (template && template.length) { for (let i = 0; i < template.length; i++) { // 收集依赖 setTemplateToVNode(template[i], vnode); setVNodeToTemplate(template[i], vnode); } } }
- 下图是我们得到的映射关系,templateToVNode打印结果,可以看出使用到
contnet变量
的,只用一个vnode节点;VNodeToTemplat打印的结果,可以看出单个vnode节点
下,使用到的模板语法
文章图片
- 代码实现
const templateToVNode = new Map(); const VNodeToTemplate = new Map(); /** * * @param {*} template * @returns 模板语法内容,形如{{xxx}},返回xxx */ function getTemplate(template) { if (typeof template !== "string") return; if (template.startsWith("{{") && template.endsWith("}}")) { return template.substring(2, template.length - 2); } return ""; }/** * 收集依赖:形如{{xxx}}的语法模板,那些vnode使用到了 * @param {*} template * @param {*} vnode */ function setTemplateToVNode(template, vnode) { const templateName = getTemplate(template); const setVNode = templateToVNode.get(templateName); if (setVNode) { setVNode.push(vnode); } else { templateToVNode.set(templateName, [vnode]); } }/** *收集依赖:单一的vnode节点, 用到了哪些形如{{xxx}}的语法模板 * @param {*} template * @param {*} vnode */ function setVNodeToTemplate(template, vnode) { const setTemplate = VNodeToTemplate.get(vnode); if (setTemplate) { setTemplate.push(template); } else { VNodeToTemplate.set(vnode, [template]); } }
推荐阅读
- android第三方框架(五)ButterKnife
- vue-cli|vue-cli 3.x vue.config.js 配置
- 2020-04-07vue中Axios的封装和API接口的管理
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- VueX--VUE核心插件
- vue组件中为何data必须是一个函数()
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- 用npm发布一个包的教程并编写一个vue的插件发布
- vuex|vuex 基础结构
- Vue源码分析—响应式原理(二)