手写MVVM框架-收集依赖
响应式数据完成之后我们需要根据数据进行动态更新dom,但是更新之前我们需要MVVM进行动态更新的时候,需要知道data里面的某一个属性,都哪些dom用到了,这样才能根据真实节点进行准确更新。
所以这一章我们来实现这个功能。
首先我们需要进行渲染之前的准备工作(收集依赖)
收集的过程中,我们主要是对于文本节点(nodeType=3)的节点进行收集,如果是元素节点,则重新调用方法,如果是文本节点的话则获取模板(去掉{ {}})的名称,创建两个Map 一个通过VNode关联模板、一个通过模板关联VNode,这样如果某一个模板值发生改变就可以轻易的获取关联的节点从而修改dom
//创建render.js 位置在src/core/render.js
const vnodeToTemplate = new Map()
const templateToVNode = new Map()
/**
* 预备渲染
* @param {*} vm
* @param {*} vnode
* @returns
*/
export function prepareRender(vm, vnode) {
if(!vnode) return
if(vnode.nodeType === 1) { // 元素节点
vnode.children.forEach(childVNode => {
prepareRender(vm, childVNode)
})
}
if(vnode.nodeType === 3) { // 文本节点()
analysisTemplateString(vnode)
}
}
/**
* 函数analysisTemplateString用于分析模板字符串
* @param {*} vnode
*/
function analysisTemplateString(vnode) {
// 获取文本里面的模板
const templateString = vnode.text.match(/{
{[a-zA-Z0-9_.]+}}/g)
if(templateString) {
// 遍历获取到的模板
templateString.forEach(template => {
// 设置VNode到模板的映射关系
setVnodeToTemplate(template, vnode)
// 设置模板到VNode的映射关系
setTemplateToVnode(template, vnode)
})
}
}
function setVnodeToTemplate(template, vnode) {
template = getTemplateName(template)
// 如果存在VNode
if(vnodeToTemplate.has(vnode)) {
vnodeToTemplate.get(vnode).push(template)
} else { // 如果不存在VNode
vnodeToTemplate.set(vnode, [template])
}
}
function setTemplateToVnode(template, vnode) {
template = getTemplateName(template)
// 如果存在VNode
if(templateToVNode.has(template)) {
templateToVNode.get(template).push(vnode)
} else { // 如果不存在VNode
templateToVNode.set(template, [vnode])
}
}
function getTemplateName(template) {
return template.replace(/{
{|}}/g, '');
}
export function getVnodeByTemplate() {
return templateToVNode
}
export function getTemplateToVnode() {
return vnodeToTemplate
}
然后我们在mount中调用该方法
我们在浏览器上可以看到两个map都已经添加上依赖了
本章总结:
1.在上一节构建完虚拟dom后,通过传入虚拟dom来收集依赖
2.对虚拟dom进行分析,如果是元素节点则重新调用方法,如果是文本节点则进行分析
3.在分析的过程中获取文本节点的内容通过正则获取出来模板,然后把当前的依赖添加到map中(VNodeToTemplate以及TempalteToVNode)