作为开发人员,我们经常听到两种编程范式:
- 命令式编程
- 声明式编程
命令式编程
命令式 过程、步骤清晰。
javascript
// 1. 获取到指定的 div
const divEle = document.querySelector('#app')
// 2. 为该 div 设置 innerHTML 为 hello world
divEle.innerHTML = 'hello world'
声明式编程
声明式 看不到 具体步骤,只关注结果。
javascript
<div id="app">
<p>{{ msg }}</p>
</div>
明白了什么是命令式和声明式编程,那么对于一个完整的功能来说,使用哪种编程方式比较好呢?在开发过程中,我们需要考虑代码的性能
和可维护性
,通过分析对比可知:
- 性能:命令式 > 声明式
- 可维护性:命令式 < 声明式
因此,Vue实质上将两种编程方式结合,用命令式编程
封装内部逻辑,暴露出声明式
接口供大家使用。对于Vue 而言,它的设计原则就是:在保证可维护性的基础上,尽可能的减少性能的损耗 。
什么是runtime运行时
vue3源码中存在一个render
渲染函数,运行时可以利用render
函数把vnode
渲染成真实 dom
节点。实现逻辑如下:
javascript
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://unpkg.com/vue@3.2.36/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { render, h } = Vue
// 生成 VNode
const vnode = h('div', {
class: 'test'
}, 'hello render')
// 承载的容器
const container = document.querySelector('#app')
// 渲染函数
render(vnode, container)
</script>
什么是h函数
h函数
用来生成一个vnode
,打印vnode
,精简结构如下:
javascript
{
// 是否是一个 VNode 对象
"__v_isVNode": true,
// 当前节点类型
"type": "div",
// 当前节点的属性
"props": { "class": "test" }
// 它的子节点
"children": "hello render"
}
到这里,就可以通过render函数
结合h函数
完成渲染了。那么 HTML标签结构
如何实现渲染呢?那就需要 complier
编译时了。
什么是编译时
编译时就是解析html节点,将其编译成render函数,请看如下案例:
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://unpkg.com/vue@3.2.36/dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
</body>
<script>
const { compile, createApp } = Vue
// 创建一个 html 结构
const html = `
<div class="test">hello compiler</div>
`
// 利用 compile 函数,生成 render 函数
const renderFn = compile(html)
// 创建实例
const app = createApp({
// 利用 render 函数进行渲染
render: renderFn
})
// 挂载
app.mount('#app')
</script>
</html>
vue
通过 compiler
解析 html
模板,生成 render
函数,然后通过 runtime
解析 render
,从而挂载真实 dom
。
到这里,估计有人疑惑了,既然compiler
可以解析 html
模板,为什么还要生成render函数再去渲染呢?
那就涉及到初次渲染和更新渲染的逻辑了,内容比较多,也比较重要,下一篇详细说明,欢迎大家指正。