视觉层框架主要分为命令式和声明式。
vue.js的内部实现一定是命令式的,而暴露给用户的却更加声明式
命令式代码的性能是一定优于声明式代码的! 因为命令式代码是直接去更改差异,而声明式代码需要先找到差异,然后再去修改。所以命令式的性能是一定大于命令式的。并且在理论上命令式代码是可以做到极致的性能优化的,因为我们明确的知道哪些发生了改变,我们只需要去做必要的修改就可以。
但是为什么vue.js要使用声明式而不是选择命令式呢???
框架的设计者为了让框架保持可维护性,并且性能损失最小化!vue就出现了下一章的虚拟dom!
声明式代码比命令式代码多出一个找出差异的性能损耗,所以我们为了最小化这一差异化。出现了虚拟dom
接下来来对比一下innerHtml和虚拟dom创建页面的性能:
在创建页面的时候,我认为两者的差异并不大,因为他们都需要新建所有的DOM元素。
我们来对比一下innerHTML和虚拟dom更新页面时候的性能:
虚拟dom,它是声明式的,因此心智负担小,可维护性强,性能虽然比不上极致优化的js对象,但是在 保证可维护性 和 保证心智负担 的前提下想当不错。
渲染器的作用就是把虚拟dom转化为真实dom!
手写一个简单渲染器,将虚拟dom转化为真实dom
const vnode = {
tag: 'div',
props: {
onclick: () => alert('hello')
},
children: 'click me'
}
// 手写一个渲染器,用来渲染上面的代码,把上面的代码渲染为真实dom
function renderer(vnode, container) {
// 使用vnode.tag作为标签名创建DOM元素
const el = document.createElement(vnode.tag)
// 遍历vnode.props属性,将属性和事件添加到dom元素中
for (const key in vnode.props) {
// 如果开头以on结尾的key,说明是事件
if (/^on/.test(key)) {
el.addEventListener(
//
key.substr(2).toLowerCase(), // 事件名称 onClick ---> click
vnode.props[key] // 事件处理函数
)
}
}
if (typeof vnode.children === 'string'){
// 如果是字符串,说明它是元素的文本子节点
el.appendChild(document.createTextNode(vnode.children))
}else if(Array.isArray(vnode.children)){
vnode.children.forEach(v=>render(v,el))
}
container.appendChild(el)
}
// body作为挂载点
renderer(vnode,document.body)
虚拟dom其实就是用来描述真是的dom的普通js对象。
组件就是一组dom元素的封装!
编译器的作用:将模板编译为渲染函数!
其实在template标签里的内容就是模板内容,编译器会把模板内容编译成渲染函数并添加到
例如:
click me
浏览器运行的代码为:
export default{
methods:{
handler(){
}
},
render(){
return h('div',{onClick:handler},'click me')
}
}
渲染的内容最终都是通过渲染函数产生的,然后渲染器再把渲染函数返回的虚拟dom渲染为真实dom,这就是模板的工作原理。也是vue渲染页面的流程。
组件的编译依赖于编译器,并且编译后生成的代码是根据渲染器和虚拟dom的设计决定的。