我本来今天想写一篇文章跟大家介绍一下 React Native for Windows + macOS。之前没有用过,所以这两天花时间调研了一下,也写了一些基础的 Demo,不过由于下午的 Vue Conf 中,我惊讶的发现了一个非常棒的东西,想迫不及待的分享给大家,他就是 Vue Vine一个更为彻底拥抱函数式的新开发方式。

从下面这张代码截图中,你就能感受到 Vue 团队拥抱函数式的决心。这是我新写的一段代码。大家先感受一下

图片

反正我不知道大家看到了这段代码是什么感受,但是我是非常激动的,因为对于 React 的深度掌握,我太知道这样的模式搞好之后最佳实践有多爽了。

所以我立马打开电脑就迫不及待的想要感受一下这种开发方式是否已经成熟可用了。


# 初步感受

通过搜索,我找到了 vue-vine 的官方网站,

https://vue-vine.netlify.app/zh/

图片

然后我就开始难受了。

官方文档写得太简陋了,找遍了文档和仓库代码,连个 demo 都没有。有点顶不住啊。项目如何创建,如何运行,都没说清楚。

然后我就去找到他们的代码仓库,发现这居然是一个酝量已久的项目。并且最近几个月更新比较频繁。

图片

但是我都没找到一个可以运行的 demo。

难顶。

该不会,压根跑不起来吧?但是我一想,这也不对,毕竟都是在发布会上正式与粉丝见面的,应该不会那么草率,于是,我就想着自己通过已有的信息尝试一下,看看能不能搞出来一个案例运行跑起来。

不过还好,折腾了一会儿,一个案例,就搞定了。按照我下面这个教程,你就能马上体验到纯正函数式的 Vue 开发体验!

起飞!走起!


# 如何把演示案例跑起来

首先,使用 vite 创建一个正常的 Vue + Typescript 项目。在终端中输入以下指令

vue-vine 仅支持 Vite + Vue3.0 + TypeScript,一定要注意这个细节,不满足条件既有可能跑不起来

npm create vite@latest

终端的执行演示图如下。

图片

然后进入到项目目录,安装项目默认模板的依赖,并添加 vue-vine

cd vuevinedemo
yarn i
yarn add vue-vine -D

修改 vite.config.ts 的配置如下。

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VineVitePlugin } from 'vue-vine/vite'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    VineVitePlugin()
  ],
})

最后在 vscode 中安装一下这个插件。目前暂时不支持其他编辑器。

图片

Vine 提供了一个 typescript 声明文件,以帮助你使用宏时获得智能提示。在 ts.config.json 的配置中,新增如下配置

{
  "compilerOptions": {
    "types": ["vue-vine/macros"]
  }
}

准备工作准备就绪。接下来就是重头戏了。由于目前 vite 还没有提供默认的 vine 模板,因此新创建的项目还是 App.vue 。所以此时新的组件应该是一个 App.vine.ts 。当然,最开始我也不确定直接修改是否是正确的使用方式,不管了,先调整一下再说

修改修改 main.ts 内容如下

import { createApp } from 'vue'
import './style.css'
- import App from './App.vue'
+ import App from './App.vine'
createApp(App).mount('#app')

然后创建一个 App.vine.ts 文件。写入如下代码最基础的代码

function App() {
  return vine`
    <div>hello Vue Vine.</div>
  `
}
export default App

我们发现在页面中成功跑起来了,nice

图片

那么接下来就比较简单了,学习的思路就是主要聚焦在如何引入组件,如何传参,如何接收参数即可。这里一个比较重要的改进就来了。我们注意看,他可以不需要 defineProps 来接收参数了。

我定义了一个自定义组件,使用方式如下所示,该组件支持传入一个参数 :value

<HelloWorld :value="number" />

在 HelloWorld 组件内部,我们可以直接按照和 React 函数组件几乎一样的方式接收参数。就问你,惊喜不惊喜,意外不意外?

import {ref} from 'vue'
function HelloWorld(props: {value: number}) {
  const {value} = props
  const count = ref(value)
  function clickhandler() {
    count.value++
  }
  return vine`
    <button @click="clickhandler">counter++</button>
    <div class="xxx"></div>
  `
}
export default HelloWorld

我们来看一下演示效果

图片

运行成功,非常 Nice。

有了这个基础之后,其他的能力理论上来说,支持起来都不会很难。因此由于时间有限,我暂时只是先把这个基础的案例跑起来了,至于更复杂的案例,等我用一段时间再来谈谈在完整项目中的使用感受。


# 注意点与坑点

需要注意的是,vine 组件组件中,最终返回的代码,他不是一个 JS 正统的模板字符串。因此如果你试图使用 ${xxx} 去插入变量,就会出问题,这里支持完整的 template 语法

return vine`
  <div>请把我当成 template 来使用</div>
`

目前主要的坑点是这个插件很容易 crash ,导致有的能力时灵时不灵,非常难受。

图片

然后不知道是什么原因, .vine.ts 后缀名的文件在工具上的支持还有点不那么完善,比如代码自动补全感觉能力不是很强,这一方面可能还需要再发展发展。


# 一个很有意思的回旋镖

前几天,我发了一篇文章吐槽 Vue3 的语法设计比较复杂,我发这篇文章的原因是因为由于我一直在发文字写 React 相关的内容,所以我对 React 的喜爱引来了一些人的不满,经常有人发私信劝我不要沉迷在一个过时的技术里自娱自乐,对我是各种嘲讽...

所以呢,我就吐槽一下 Vue3 在语法设计上的问题,当然,从评论区里就看得出来,肯定还是有人不服气啊,这不回旋镖不就来了吗?新的 Vue-vine 的改动,刚好正中我吐槽的其中两个重要的点

一个是对于 Props 设计比较复杂的改动。前面我们已经说过了, Vue-vine 支持与 React 几乎一致的方式接收自定义的 Props,在理解上的成本降低了许多

另外一个点就是彻底拥抱了函数式。扔掉了 scripttemplate 的枷锁。

除此之外,还有一个点,就是这样做的一个点就是有人在评论区提出的,希望 Vue 可以支持声明多个函数组件。这个不就可以了吗?

还有一个重要的改动。看下图

图片

我们探讨这个问题,在 Vue 里面已经被人在 issue 里反复提及了很多次。这一次,在新的 Vue-vine 中也得到了完美的解决。

我专门写了一个案例来验证这个事情。

图片

父组件中,传入的是 undefined,那么在子组件中,接收到的就是 undefined,而不是会被默认转换成 false。

图片

可以看出,我那篇文章中的许多讨论,其中失去响应性这个问题在函数式中是无法解决的,另外一个是传参类型由于指令系统的存在也没办法解决,其他能解决的复杂度的问题,基本上都解决掉了。

很显然, vue-vine 的诚意非常足。 他们确实有很认真的在对待这种新的开发模式。虽然可能长得跟 React 有点像,但是我还是非常看好 Vue-vine 的长远发展,这必将会得到一部分人的热捧,并最终有机会成为 Vue 开发的主流方式。


# 总结

一个坏的消息就是,Vue 的开发方式,总体上变得更加复杂了。这对于入门新手来说,有点难受。必然会有很多人会支持和喜欢 vue-vine ,因为这确实变得更加舒服了,他也非常有利于 React 开发者顺利转向 Vue。甚至有可能 Vue4 将会采用这种新的开发方式。

可是截止到目前为止,依然有大量的项目仍然在使用 Vue2 的开发模式。Vue3 也正在被许多人所熟悉,又新出一个开发方式,这个时候,就会存在三种开发方式并存的现象,新手可就遭了殃了啊。老手就无所谓,切换成本很低。

一个好的消息是,Nuxt.js,Vue mini,uniapp-x 等相继在 Vue Conf 亮相,uniapp 也明确表示将会支持兼容鸿蒙应用, Vue 的生态进一步成熟了。但是他的跨端方案具体体验如何,还有待进一步验证。只能说,要处理好,工作量有点大,还需要时间...

最后不得不说, vue-vine 出来之后,我这篇文章的含金量还在继续提高。