大家好,我ssh,又跟大家见面啦!
前言
在最近的Vue Fes大会上,Vue Vapor的作者智子大佬宣布,如果能够得到资金支持,那么Vue Vapor年底就能发布alpha版本了。
智子也需要赚钱养活自己
根据尤大透露,过去一年以来智子接受赞助全职在为Vue Vapor工作。现在智子虽然还有赞助,但不再是全职的了。
也就是说现在智子大佬也需要想办法赚钱养活自己
了,所以上周智子发了一个寻找赞助商的帖子。
智子的目标也很简单,能够养活他就行了
。并且表示为赞助商服务,开始虽然是封闭开发,最终还是会开源的。
如果不寻求赞助,为了能够养活自己智子就只能去找一份工作了。如果这样Vapor的开发进度可能就会延缓,所以目前来说赞助计划是目前最好的方式了。
目前智子收到的赞助总额不到1000美元(包括尤大的)。
强如智子大佬,做开源也很难养活自己。欧阳也只能略尽绵薄之力(因为我最近也被通知12月底走人了,我们团队将会只剩下leader了)
现在的Vue Vapor
现在的Vue Vapor主要有三个特点:没有虚拟DOM、高性能、更小的包体积。
没有虚拟DOM
:意思很简单,就是在Vue Vapor中已经将虚拟DOM给干掉了。
高性能
:因为干掉了虚拟DOM,瓶颈得以突破,所以性能相对提高了很多。
更小的包体积
:包体积大小减少了53.3%。
并且Vue Vapor是目前大家所使用的Vue版本的子集
相比目前的Vue功能要少点,支持Composition API以及<script setup>
。
因为Vapor是目前Vue版本的子集,所以无虚拟DOM的Vapor模式和有虚拟DOM的vDom模式之间是互相兼容的。
在Vapor组件中支持使用vDom模式的组件。同样在vDom组件中也支持使用Vapor模式的组件。并且还支持只使用Vapor模式的情况。
并且Vue生态中的VueUse
、Vue Router
、Pinia
、Nuxt
、组件库
等都会支持Vapor。
同样也支持jsx,不过需要引入unplugin-vue-jsx-vapor
。
Vapor的机制
先看一个普通的操作DOM的例子:
// Initialize
const container = document.createElement('div')
const label = document.createElement('h1')
const button = document.createElement('button')
button.textContent = 'Increase'
button.addEventListener('click', increase)
let count = 0
const render = () => {
label.textContent = `Count: ${count}`
}
function increase() {
count++
render() // Re-render
}
render() // Initial render
document.body.append(container)
container.append(label, button)
在这个例子中主要有两个元素:h1
标签和button
按钮。
h1
标签中渲染了count
变量的值。
点击button
按钮触发click事件执行increase
函数,在函数中首先会执行count++
,然后再去执行render
函数。
在render
函数中将h1
标签中的值更新为最新值。
上面这个方案有个弊端,每次在click事件的回调中除了常规的执行count++
之外,还去手动调用了render
函数。
设想一下,如果我们的业务代码里面也这样写,那代码中将会到处都在调用render
函数了,这样的代码光想想都头疼。
还好Vue的设计中有个优秀的响应式机制,并且还将响应式的功能抽取成一个单独的包:@vue/reactivity
。
而Vue Vapor就是基于@vue/reactivity
进行开发的,藉此实现当响应式数据改变后会自动更新DOM,无需去手动执行render函数。
使用@vue/reactivity
改造后的代码如下:
import { effect, ref } from '@vue/reactivity'
// Initialize
const container = document.createElement('div')
const label = document.createElement('h1')
const button = document.createElement('button')
button.textContent = 'Increase'
button.addEventListener('click', increase)
const count = ref(0)
effect(() => {
label.textContent = `Count: ${count.value}`
})
function increase() {
count.value++
}
document.body.append(container)
container.append(label, button)
改造后的代码和原来的代码主要有三个不同:
之前是直接使用
let count = 0
定义的变量,而改造后使用const count = ref(0)
定义的响应式变量。之前的
increase
函数中除了执行count++
之外,还需要去手动调用render()
函数。而在新的代码中只会执行count.value++
。移除了render函数,替代他的是
effect
函数。在effect
的回调函数中同样是进行DOM操作更新h1
标签中的值。effect
函数和watchEffect
很相似,当回调中的响应式变量改变后就会重新执行回调函数。这里就是当响应式变量count
改变后会重新执行回调函数,在回调函数中进行DOM操作更新h1
标签中的值。
这也就是Vapor基于@vue/reactivity
实现的响应式原理,在这个过程中完全没有虚拟DOM的介入。当响应式变量改变后会执行对应的effect
回调函数,在回调函数中直接去更新DOM即可。
看到这里有的小伙伴会有疑问,这个effect
函数以及里面操作DOM的代码需要我们自己手写吗?
当然不需要手动去写!!在编译时Vapor会自动生成一个effect
回调函数,以及回调函数里面更新DOM的代码。
这个是上面的例子在Vue Vapor SFC Playground
上面经过编译后的js代码,如下图:
从上图中可以看到Vapor模式下经过编译后会自动生成一个effect回调函数,并且在回调函数中会去直接操作DOM。
至于编译时是如何生成effect回调函数,需要等Vapor稳定后欧阳会继续写文章讲解。
总结
无虚拟DOM
的Vapor模式是有虚拟DOM
的vDom模式的子集,并且他们之间支持component组件混用。抛弃了虚拟DOM,Vapor轻装上阵后,性能以及包体积相比传统的vDom模式有了很大的提升。最后就是智子现在在寻求赞助商,让他能够全职开发Vue Vapor的同时能够养活自己。