vue 都发布新版本 vue3 了,不跟上时代怎么可以
本文结合 ts,且根据笔者自己的使用体验
目录大致如下
- 构建
- 路由
- 构造选项
- ref
- 钩子函数
- 标签属性
- teleport
- 总结
- 参考文章
构建
与 vue2 使用 webpack 不同,vue3 可以使用 vite 进行构建
Vite,一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。同时不仅有 Vue 文件支持,还搞定了热更新,而且热更新的速度不会随着模块增多而变慢。针对生产环境则可以把同一份代码用 rollup 打。虽然现在还比较粗糙,但这个方向我觉得是有潜力的,做得好可以彻底解决改一行代码等半天热更新的问题。
简单说就是,在生产环境使用模块,省略打包步骤,开发环境可以秒级启动
安装 vite,只需要执行以下命令
1 | npm i -g create-vite-app |
安装成功后,可以通过两个命令来构建
1 | create-vite-app [projectName] |
即可在当前目录下构建一个基于 vite 的 vue3 新项目
之后通过命令行 cd
进入该项目目录,执行
1 | npm install |
初始化 node_modules
之后,再运行
1 | npm run dev |
即可启动项目预览了,通常会启动在 3000 端口
但是,当在项目中使用 ts 时,ts 无法识别 vue 后缀的文件,这时候可以在项目的 src
目录下新建一个文件 shims.d.ts
来处理识别问题
1 | // shims.d.ts |
当静态报错为”无法识别 vue 后缀的文件”时,打开该 ts,再返回原代码,即可解决红线报错
路由
先来看一个 vue2 的路由示例
1 | import Vue from 'vue' |
可见,vue2 中声明一个路由,是使用 new 操作符来新建一个 Router
对象,并向其构造函数中传入 options 来达成的
现在再给出一个 vue3 的路由示例
1 | import { createWebHistory, createRouter } from 'vue-router' |
细节上,vue3 采用了 createRouter
函数来创建一个 Router
对象,对用户隐藏了内部细节,但仍然要求用户传入一个 options,且该 options 也主要包括 mode
和 routes
两个选项
同时,在 vue3 中,声明一个路由模式,由字符串改为了函数返回值,具体对应如下
vue2 写法 | vue3 写法 |
---|---|
mode 字段 | history 字段 |
mode: ‘hash’ | history: createWebHashHistory() |
mode: ‘history’ | history: createWebHistory() |
mode: ‘memory’ | history: createMemoryHistory() |
整体上大同小异,使用时注意细节即可
构造选项
一个 vue2 的 script 标签写法,大致有如下格式
1 | export default { |
诸如此类
但是在 vue3 中,除 props
写法照旧之外,其余均可以通过 setup
方法进行处理
1 | export default { |
在 setup
方法中,所有通过 return
暴露出的变量,都等效于 vue2 中 data
暴露的变量;所有通过 return
暴露出的函数,都等效于 vue2 中 methods
暴露的函数
而生命周期钩子,也可以直接写在 setup
中,如 mounted
1 | // vue2 |
一种类似于 DOM 事件中 click -> onClick
的转化,将 mounted
转化为了 onMounted
,此时 onMounted
接受一个函数作为参数
除此之外,要在 setup
中使用传递到组件上的参数,在 vue2 中只需要使用 this.xxx
就可以访问到,而在 vue3 中必须要在 setup
的形参列表中声明后才可以使用
setup
接受两个参数,第一个是绑定参数 props,第二个是上下文 context
1 | setup(props, context){ |
等效于 vue2 中的
1 | export default { |
那么,在 props 中未声明的绑定参数,都去哪了呢?
在 vue2 中,可以通过 this.$attrs
来访问到其余的参数
而在 vue3 中,要通过 context.attrs
来访问
注意:
- 在父组件中绑定到子组件的事件,不会出现在 props 里
- props不支持事件,支持其余属性,不在props里的都会到attrs里,但 props 要先声明
- props里有多种类型,attrs只有字符串
如果不希望子组件继承父组件给出的参数,也可以显式指定不继承
1 | export default { |
注意 inheritAttrs: false
选项不会影响 style
和 class
的绑定
综上,假如有一个需求是,父组件会向子组件中传入若干参数,而只希望绑定变量名为 xxx
以外的其余变量,那么可以有如下写法
1 | setup(props, context){ |
然后在模板中,要绑定的地方,写入 v-bind="rest"
即可绑定所有参数
ref
细心的朋友应该已经注意到了,上面出现一个名为 ref
的用法,且用法形似一个函数
熟悉 ES6 的 proxy 的话,可以看出 ref
其实就是返回一个对传入数据的代理,这个代理拦截了 get 和 set 操作,并在 set 的时候通知视图更新
熟悉 react 的朋友,是不是感觉和 useState
很像?其实就是把 getter/setter 返回到同一个对象身上而已,2333
设在以下代码段中使用 ref
1 | const visible = ref([true,true]) |
则有以下特点
可以使用 const 声明代理对象,反正是这个对象不能变,不是里面的代理内容不能变
在 script 标签中读取数组内容时,必须使用
visible.value
才能取得数组,直接访问visible
取得的是代理对象尽可能不要直接修改代理内容
在 template 标签(模板)中读取数组内容时,直接访问
visible
即可得到数组内容当模板中引用的代理对象的 set 代理,发现代理内容被更新时,会自动通知视图进行更新
ref
代理自带 vue2 的 data 做不到的深度监听,比如修改数组项、或对象的字段
钩子函数
vue3 新增了一个重要的钩子函数 watchEffect
当然,同时可以使用 vue2 的 watch 属性,不赘述了
watchEffect
的主要效果是,注册一个侦听,该侦听会在声明时立刻执行,并在之后所有生命周期函数被调用前,或 setup
函数被调用时执行
一般写法如下
1 | watchEffect(onInvalidate => { |
watchEffect
接受两个参数,其中第一个参数必选,第二个参数可选
第一个参数是每次执行时的执行函数,该函数会提供一个入参,表示侦听执行失败时的善后函数,类似于 catch
语句块中的 finally
。此处的入参 onInvalidate
也接受一个函数,表示善后时执行的内容
第二个参数表示 watchEffect
的配置,一般用于配置 watchEffect
执行的时机
例如以下代码
1 | watchEffect(()=>{ |
options
中的字段 flush
,默认值是 'pre'
,表示在钩子函数执行之前就执行侦听,所以如果想在之后执行,就要手动设置为 'post'
注意,会在所有生命周期函数被调用后执行,意味着它有可能在 beforeCreate
生命周期之前,或 created
之前就被执行,所以请注意控制其执行时机
标签属性
也许有人觉得,写一个 setup
函数,和 vue2 好像没有什么本质差别
但是,vue3 可以在 script 标签上另加一个新属性: setup
当写一个 script 标签的时候,可以写作如下形式
1 | <script lang="ts" setup> |
此时 script 标签内部的所有内容,都被视为运行在 setup
函数中
那 setup
的两个参数怎么办呢?直接写在属性上就好
1 | <script lang="ts" setup="props,context"> |
这样就可以在 script 标签中正常使用 props
和 context
了
那原来在 setup
中的 return 导出怎么办呢?答案是可以直接 export
例如原来有如下 setup
1 | setup(){ |
现在可以直接写作如下模样
1 | <script lang="ts" setup="props,context"> |
之后的使用与上例相同,直接在模板中引用即可
但是,虽然看起来很装逼,不过该写法尚未得到广泛支持,反正到2021年2月16日为止,我在我的编辑器里是用不了,2333
teleport
vue3 还有一个重要的新组件: teleport
它用来将新建的渲染挂载到页面上的某个目标,而不是原定位置
考虑以下情况:我们需要制作一个弹窗功能,希望弹窗弹出后,其在 DOM 树的位置是 body 的直接子级
那么可以得到如下代码
1 | <template> |
那么,上述模板在检测到 visible
变为 true 之后,要渲染内部的内容
内部第一层是 teleport
,其 to
属性为 body
,那么会将 teleport
内部的所有内容,挂载到 body
上,成为其最后一个子结点
发现了吧?其实 teleport
最重要的就是 to
属性,该属性接受一个 CSS 选择器,指定要挂载的位置
选择器重复怎么办?自己看看 JQuery 吧(
总结
vue3 还是搞出来一些很好玩的东西,有空多研究一下
而且和 ts 相性很好,又吸收了 react 的优点,未来超过 react 不是没有可能
但是!!!太新的特性,使用的时候要先检查一下有没有得到支持了,不要改完代码才发现没支持,又要改回去
这里我要点名表扬 git reset --hard [version]
,存档合理的话,这简直是神技,2333
参考文章
如何看待 Web 开发构建工具 Vite? - 阿里巴巴淘系技术
感谢阅读