迟到的 Vue3.0 与 Vite 的体验学习总结
尤大的 Vue3.0 已经发布有一阵子了, 已经很成熟了。今天想起来,是时候该上手体验一波了。
Vue3.0 亮点
- Performance:性能更比Vue 2.0强;
- Tree shaking support:可以将无用模块“剪辑”,仅打包需要的;
- Composition API:组合式API;
- Fragment, Teleport, Suspense:“碎片”,Teleport 即 Protal 传送门,“悬念”;
- Better TypeScript support:更优秀的Ts支持;
- Custom Renderer API:暴露了自定义渲染API;
Vue3.0 项目初始化
1. 安装 vue-cli 脚手架
$ npm install -g @vue/cli
安装成功后,使用 vue -V
命令,查看是否安装成功:
$ vue -V
@vue/cli 4.5.9
如果没有安装成功或者是还是2.0版本的,那么我们要将他升级到 3.0。
先将已有的 vue-cli
卸载,然后重新安装即可。
$ npm uninstall vue-cli -g
2. 创建 vue3.0 项目
$ vue create vue3-demo
在出现的命令交互窗口选择 Manually select features:
然后勾选:Router、Vuex、CSS Pre-processors 和 Linter / Formatter等内容。
回车后根据自己的习惯选择好,就开始创建项目。
选择vue版本:
安装完成之后就可以直接创建 vue3.0 的项目了,通过命令进行后续操作了。
通过下面两个命令就可以启动 vue3.0 的项目了。
$ cd vue3-demo
$ npm run serve
成功运行项目:
下面就开始干我们的正事了。。。
Vue3.0 新特性
1. 创建实例
在 Vue3 中每个 Vue 应用都是通过用 createApp
函数创建一个新的实例,不在通过 new
的方式进行创建:
Vue3创建实例的方式:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
Vue2 通过函数式创建实例:、
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
2. 创建路由
现在创建路由实例需要手动引入 createRouter
方法,创建 history
模式路由也需要手动引入 createWebHistory
方法,这达到 Tree-Shaking
的目的,即不会把所有的 api
都打包进来,只会打包你用到的 api
,vue3 将都会使用这种形式。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
3. 响应式数据和事件绑定
Vue 3.0 中初始化状态通过 setup()
方法,定义状态需要调用 ref()
方法。
这就跟在 vue2 中有很大的不同,vue2 中我们是使用选项的方式来创建 data
、methods
、watch
和 computed
的。
<template>
<div>
{{count}}
{{str}}
<button @click="add">add</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0); // 声明count,初始值为 0
const str = ref('hello'); // 声明str,初始值为 'hello'
const add = () => { // 定义一个事件,用来更新count状态
count.value ++; // 更新count值的时候不能直接使用count++,而应使用 count.value++
}
return {
count,
str,
add
}
},
}
</script>
4. 使用 reactive
声明响应式数据
使用 reactive
来一次声明多个变量
import { reactive } from 'vue'
export default {
setup () {
// 引入 reactive,同时定义多个变量
const state = reactive({
count: 0,
str: 'hello'
})
// 现在访问变量,不能使用 .value 方式访问了
const add = () => {
// state.count.value++ // 错误
state.count++
}
return {
state,
add
}
}
}
reactive
和 ref
比较
-
reactive
是接收一个普通对象,返回该对象的响应式代理,它等同于 2.x 中的Vue.observable()
。const obj = reactive({ count: 0 }) // obj 此时是一个响应式的对象 // 访问或修改,直接基于 obj.count
-
ref
也是接收一个参数并返回一个响应式且可改变的ref
对象,一般参数是基础类型。
如果传入的参数是一个对象,将会调用 reactive 方法进行深层响应转换。ref 对象拥有一个指向内部值的单一属性 .value,即当你要访问它的值时,需要 .value 拿到它的值。但是如果是在 setup 中返回且用到模板中时,在 {{}} 里不需要加 .value 访问,在返回时已经自动解套。setup() { return { count: ref(0), // 这里返回,在模板中无需 .value 访问值 } },
5. watch
和 computed
在 Vue3 中使用监听器和计算属性,也需要手动引入,且 watch
和 computed
都需要在 setup
中进行。
import { ref, watch, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const add = () => {
count.value ++;
}
// 监听器 watch 同样是一个方法,它包含 2 个参数,2 个参数都是 function
// 第一个参数是监听的值,count.value 表示当 count.value 发生变化就会触发监听器的回调函数,即第二个参数,第二个参数可以执行监听时候的回调
watch(
() => count.value,
(val, oldVal) => {
console.log(`new count: ${val},old count: ${oldVal}`);
}
);
// 计算属性 computed 是一个方法,里面需要包含一个回调函数,当我们访问计算属性返回结果时,会自动获取回调函数的值:
const doubleCount = computed(() => {
return count.value * 2;
});
return {
count,
add,
doubleCount
}
},
}
如果是 2 个以上的监听属性:
watch(
[refA, () => refB.value],
([a, b], [prevA, prevB]) => {
console.log(`a is: ${a}`)
console.log(`b is: ${b}`)
}
)
6. 获取路由信息
vue3.0 中使用 getCurrentInstance
方法获取当前组件实例,然后通过 ctx
属性获取当前上下文,ctx.$router
是路由实例,而 ctx.$router.currentRoute
就包含当前路由信息。
import { getCurrentInstance } from 'vue'
export default {
setup () {
const { ctx } = getCurrentInstance()
console.log(ctx.$router.currentRoute.value)
}
}
7. Vuex
在学习 Vue3 的 Vuex 4 之前,先来看一下 Vue2 的 Vuex 3:
可以发现创建 store
实例的方式改变了,vue2 中是使用 new 的方式进行创建的
export default new Vuex.Store({
// ...
})
看完 Vue2 的 Vuex 3,那么继续回到我们 Vue3 的使用。
-
定义 Vuex 状态
在
state
中创建了一个状态,在mutations
中添加修改该状态的方法,在actions
中提交mutation
的方法,而不是直接变更状态。import { createStore } from 'vuex' export default createStore({ state: { count: 0 }, mutations: { ADD(state) { state.count++; } }, actions: { add({ commit }){ commit('ADD') } }, modules: { } })
-
更新 Vuex 状态
方式一:
在 xx.vue 页面中,通过计算属性使用Vuex
状态;
在具体事件中通过store.dispatch
方法触发 Action。<template> <div> <div>state from vuex {{count}}</div> <button @click="add">add</button> </div> </template> <script> import { computed } from "vue"; import { useStore } from 'vuex'; // 引入 useStore 方法返回 store 实例 export default { setup() { const store = useStore() const count = computed(() => store.state.count) const add = () => { store.dispatch('add') } return { count, add, }; }, }; </script>
方式二:
通过获取当前组件实例ctx
,使用ctx.$store.commit
直接分发mutations
,但是mutation
有个限制:必须同步执行,而Action
就不受约束,可以在action
内部执行异步操作。<template> <div> <div>state from vuex {{count}}</div> <button @click="add">add</button> </div> </template> <script> import { computed, getCurrentInstance } from "vue"; export default { setup() { const { ctx } = getCurrentInstance() const count = computed(() => ctx.$store.state.count) const add = () => { ctx.$store.commit('ADD') } return { count, add, }; }, }; </script>
值得注意的新特性:
Vue 3 中需要关注的一些新功能包括:
- 组合式 API
- Teleport
- 片段
- 触发组件选项
- createRenderer API 来自 @vue/runtime-core 创建自定义渲染器
-
单文件组件组合式 API 语法糖 (
<script setup>
) 实验性 -
单文件组件状态驱动的 CSS 变量 (
<style vars>
) 实验性 - 单文件组件 <
style scoped
> 现在可以包含全局规则或只针对插槽内容的规则
非兼容的变更:
Global API
- 全局 Vue API 已更改为使用应用程序实例
- 全局和内部 API 已经被重构为可 tree-shakable
模板指令
- 组件上
v-model
用法已更改 -
<template v-for>
和非v-for
节点上key
用法已更改 - 在同一元素上使用的
v-if
和v-for
优先级已更改 -
v-bind="object"
现在排序敏感 -
v-for
中的ref
不再注册ref
数组
组件
- 只能使用普通函数创建功能组件
-
functional
属性在单文件组件 (SFC)<template>
和functional
组件选项被抛弃 - 异步组件现在需要
defineAsyncComponent
方法来创建
渲染函数
-
渲染函数 API 改变
-
$scopedSlots property
已删除,所有插槽都通过$slots
作为函数暴露 -
自定义指令 API 已更改为与组件生命周期一致
-
一些转换
class
被重命名了:-
v-enter
->v-enter-from
-
v-leave
->v-leave-from
-
-
组件
watch
选项和实例方法$watch
不再支持点分隔字符串路径,请改用计算函数作为参数 -
在 Vue 2.x 中,应用根容器的
outerHTML
将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。VUE3.x 现在使用应用程序容器的innerHTML
其他小改变
-
destroyed
生命周期选项被重命名为unmounted
-
beforeDestroy
生命周期选项被重命名为beforeUnmount
-
prop
default
工厂函数不再有权访问this
是上下文 - 自定义指令 API 已更改为与组件生命周期一致
-
data
应始终声明为函数 - 来自
mixin
的data
选项现在可简单地合并 -
attribute
强制策略已更改 - 一些过渡
class
被重命名 - 组建
watch
选项和实例方法$watch
不再支持以点分隔的字符串路径。请改用计算属性函数作为参数。 -
<template>
没有特殊指令的标记 (v-if
/else-if
/else
、v-for
或v-slot
) 现在被视为普通元素,并 将生成原生的 元素,而不是渲染其内部内容。 - 在 Vue 2.x 中,应用根容器的
outerHTML
将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。Vue 3.x 现在使用应用容器的innerHTML
,这意味着容器本身不再被视为模板的一部分。
以上内容如果想要详细了解,请移步至 v3 迁移指南。
项目总结:
今天做一个小项目,想要使用Vue3 + Element-ui,发现Element-ui并不支持 Vue3中使用。查看源码发现,Vue3 在插件install
函数的入参从Vue原型(类)
改成了app(Vue的实例e)
,所以导致 element-ui中的Vue.prototype.*
,这样的代码已经全部失效了。所以目前看来,element-ui是不能兼容Vue3的了。
但是 AntD2.0 测试版 支持 Vue 3.0 已发布。可以尝试一下。
Vue3.0 比较常见的新特性基本就是这些,后面还会不断学习补充,大家一起进步。加油!
本文地址:https://blog.csdn.net/XH_jing/article/details/111687106