引言
“框架设计里到处都体现了权衡的艺术。”
在深入讨论 Vue.js 3 各个模块的实现思路和细节之前,我认为有必要先来讨论视图层框架设计方面的内容。 为什么呢?这是因为当我们设计一个框架的时候,框架本身的各个模块之间并不是相互独立的,而是相互关联、相互制约的。 因此作为框架设计者,一定要对框架的定位和方向拥有全局的把控,这样才能做好后续的模块设计和拆分。 同样,作为学习者,我们在学习框架的时候,也应该从全局的角度对框架的设计拥有清晰的认知,否则很容易被细节困住,看不清全貌。
另外,从范式的角度来看,我们的框架应该设计成命令式的还是声明式的呢?这两种范式有何优缺点?我们能否汲取两者的优点? 除此之外,我们的框架要设计成纯运行时的还是纯编译时的,甚至是运行时+编译时的呢?它们之间又有何差异? 优缺点分别是什么?这里面都体现了“权衡”的艺术。
从范式上来看,视图层框架通常分为命令式和声明式,它们各有优缺点。 作为框架设计者,应该对两种范式都有足够的认知,这样才能做出正确的选择,甚至想办法汲取两者的优点并将其捏合。
接下来,我们先来看看命令式框架和声明式框架的概念。早年间流行的 jQuery 就是典型的命令式框架。命令式框架的一大特点就是关注过程。 例如,我们把下面这段话翻译成对应的代码:
- 获取 id 为 app 的 div 标签
- 它的文本内容为 hello world
- 为其绑定点击事件
- 当点击时弹出提示:ok
对应的代码为:
$('#app') // 获取 div
.text('hello world') // 设置文本内容
.on('click', () => { alert('ok') }) // 绑定点击事件
以上就是 jQuery 的代码示例,考虑到有些读者可能没有用过 jQuery,因此我们再用原生 JavaScript 来实现同样的功能:
const div = document.querySelector('#app') // 获取 div
div.innerText = 'hello world' // 设置文本内容
div.addEventListener('click', () => { alert('ok') }) // 绑定点击事件
可以看到,自然语言描述能够与代码产生一一对应的关系,代码本身描述的是“做事的过程”,这符合我们的逻辑直觉。
那么,什么是声明式框架呢?与命令式框架更加关注过程不同,声明式框架更加关注结果。结合 Vue.js,我们来看看如何实现上面自然语言描述的功能:
<div @click="() => alert('ok')">hello world</div>
这段类 HTML 的模板就是 Vue.js 实现如上功能的方式。可以看到,我们提供的是一个“结果”, 至于如何实现这个“结果”,我们并不关心,这就像我们在告诉Vue.js:“嘿,Vue.js,看到没,我要的就是一个 div, 文本内容是 hello world,它有个事件绑定,你帮我搞定吧。”至于实现该“结果”的过程,则是由 Vue.js 帮我们完成的。 换句话说,Vue.js 帮我们封装了过程。因此,我们能够猜到 Vue.js 的内部实现一定是命令式的,而暴露给用户的却更加声明式。