手写MVVM框架-模板渲染1
虚拟dom创建好了,依赖也收集好了,这个时候就该去渲染dom了,把页面上的 { {name}} 渲染成具体的值。
渲染之前我们给原型上添加一个render方法
//代码在src/core/render.js
export function renderMixin(MiniVue) {
MiniVue.prototype.$render = function() {
renderNode(this, this._vnode)
}
}
接下来实现renderNode方法
实现的原理是:
1.传入根节点VNode, 如果当前节点是元素节点则重新调用该方法
2.如果是文本节点,则获取出来该节点依赖的模板
3.获取该模板对应的值 然后将值替换为模板
// 代码在src/core/render.js
import { getObjectValue } from '../utils/ObjectUtils'
export function renderMixin(MiniVue) {
MiniVue.prototype.$render = function() {
renderNode(this, this._vnode)
}
}
/**
* 渲染Node
* @param {MiniVue} vm
* @param {*} vnode
* @returns
*/
function renderNode(vm, vnode) {
// 如果是文本节点
if(vnode.nodeType === 3) {
// 获取当前节点关联的模板
const templateArray = vnodeToTemplate.get(vnode)
// 如果当前节点里面有模板
if(templateArray) {
// 获取文本内容
let result = vnode.text
// 遍历模板
templateArray.forEach(template => {
let templateValue = getTemplateValue([vm._data, vnode.env], template)
result = result.replace(`{
{${template}}}`, templateValue)
})
vnode.ele.nodeValue = result
}
} else { // 继续调用renderNode
vnode.children.forEach(childVNode => {
renderNode(vm, childVNode)
})
}
}
// 获取文本中的模板
function getTemplateValue(objs, template) {
for(let i = 0; i < objs.length; i++) {
let templateValue = getObjectValue(objs[i], template);
if(templateValue != null) {
return templateValue;
}
}
return null;
}
其中getObjectValue 的实现为:
/**
* 在一个Object里面取出来key的值
* @param {Object} obj
* @param {String} key a, obj.a
*/
export function getObjectValue(obj, keys) {
if(!obj) return obj
let keyList = keys.split('.')
let temp = undefined;
keyList.forEach((item)=> {
if(obj[item] != null) {
temp = obj[item]
}
})
return temp
}
然后把render 方法挂载到原型上并调用
现在再查看页面上的效果发现,模板已经被替换成了具体的值