Vue3框架设计思想
# 权衡的艺术
# 命令式和声明式
命令式:关注过程,详细的告诉计算机或者说浏览器,每一步需要做什么。
典型的命令式代码:
const div = document.getElementbyId("#box")
div.innnerText = "hello world"
div.addEventListener('click', () => alert('ok'))
声明式:关注结果,声明需要的结果,由框架执行具体内容。
<div @click="() => alert('ok')">hello world</div>
声明式的代码内部依旧是命令式的,只是这不需要使用者来关心。声明式是对命令式的封装,它的性能一定不会高于命令式。但是声明式的代码大大提高了可维护性,减少了使用者的心智负担。
# 虚拟DOM的性能
原生JavaScript
的性能一定是最高的,但是为了保证这个高性能,需要花费巨大的心智负担。
虚拟DOM
的心智负担小,性能不如原生但是也还可以接受,因为基于diff
算法它只会更新必要的DOM
。
innerHTML
的方式心智负担中等,但是性能最差。因为每次更新都会删除所有旧DOM
然后创建新的,页面越大性能消耗就越大。
# 运行时和编译时
运行时:用户提供树形结构的对象,直接给框架使用。缺点是不能分析用户输入。
编译时:用户提供HTML
模板,框架将模板编译为命令式代码,然后执行。
Vue
是编译器 + 运行时框架,即用户可以直接提供树形结构,也可以提供模板,Vue
都可以执行。无非就是需不需要先进行编译而已。Svelte
是纯编译时框架,纯编译时框架必须将用户输入进行编译后才能运行,性能还有待商榷。
# 框架设计核心要素
# 良好的用户体验
使用Vue
进行开发的时候,如果编写了错误的代码Vue
一般都会在浏览器控制台输出一些警告和报错信息。并且这些报错信息并不是JS
层面的信息,而是框架本身提供的,能帮助用户快速定位问题所在的信息。
这是提升用户体验直观重要的一环。
# 代码体积和Tree-Shaking
为了提升用户体验,需要编写大量的错误提示代码,但是Vue
的打包产物并没有因为这些提示代码而体积巨大。主要是采用了类似
if(__DEV__) {
warn('提示信息')
}
错误提示信息只会在开发阶段出现。生产环境下,__DEV__
被置为false
,内部代码永远不会执行,Tree-Shaking
会擦除掉这段代码。
Tree-Shaking
的依赖于ESM
的静态结构。主要判断依据是代码是否有副作用,即是否会对外部产生影响。
正是这种代码编写方式和Tree-Shaking
,才让Vue
拥有良好的提示功能的同时还能控制打包产物体积。
# 声明式UI框架
# 灵活的使用方式
Vue
的使用方式是声明式的,用户无需关系具体的过程即可得到需要的结果。
使用Vue
时既可以提供虚拟DOM
也可以直接使用模板,使用虚拟DOM
时,渲染器会直接执行。
//虚拟DOM就是利用JS对象对真实DOM的一种描述
const vnode = {
tag: 'div',
props: {
onClick: () => console.log('Hello Vue')
},
children: 'click me'
}
//渲染器
function renderer(vnode, container) {
//1.创建元素
let el = document.createElement(vnode.tag)
//2.遍历元素属性
for(let key in vnode.props) {
if(/^on/.test(key)) {
let event = key.substring(2).toLowerCase()
el.addEventListener(event, vnode.props[key])
}
}
//3.遍历子元素
if(typeof vnode.children === 'string') {
el.appendChild(document.createTextNode(vnode.children))
}else (Array.isArray(vnode.children)){
vnode.children.forEach(child => renderer(child, el))
}
//4.挂载
container.appendChild(el)
}
如果是使用模板的话,编译器会将模板编译成虚拟DOM
之后再调用渲染器渲染真实DOM
。
# 组件的本质
组件本质就是一系列真实DOM
元素的封装。