一、推荐的插件
1. Volar : Vue3 多个根节点不会报错; 编辑器隔离。
1. Vue 3 Sinppets: 代码自动补全
二、创建 Vue 3 项目
-
vue create <project> : 选择 Vue 3 项目
-
npm init vite-app <project> : 使用 Vite 创建 Vue 3 项目
-
项目中
// main.ts : import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app') // App.vue // 1. 不需要根标签; 2. 使用 defineComponent 定义组件 //Vue2组件中的html模板中必须要有一对根标签,Vue3组件的html模板中可以没有根标签 <template> <img alt="Vue logo" src="./assets/logo.png"> <!-- 使用子级组件 --> <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" /> </template> <script lang="ts"> // 这里可以书写TS代码 // defineComponent函数,目的是定义一个组件 内部可以传入一个配置对象 import { defineComponent } from 'vue'; //引入子级组件 import HelloWorld from './components/HelloWorld.vue'; // 暴露出去一个定义好的组件 export default defineComponent({ // 当前组件的名字 name: 'App', // 注册组件 components: { // 注册一个子级组件 HelloWorld, }, }); </script>
-
Composition API : 将原分散在 Options API (data/computed/methods/props等) 中的数据组合起来。
三、 Vue 3 的基本使用
-
setup(): Composition API 的入口函数,生命周期(= (beforeCreate + created)),此时实例还未创建,没有this。
setup
函数如果返回对象, 对象中的 属性 或 方法 , 模板 中可以直接使用。//templete <div>{{number}}</div> //JS setup() { const number = 18; return { number, }; },
setup(props, {attrs, slots, emit }) : 参数
-
ref : 定义一个响应式的数据(一般用来定义一个基本类型的响应式数据
Undefined
、Null
、Boolean
、Number
和String
)。 script中操作数据需要使用
xxx.value的形式,而模板中不需要添加
.value -
reactive: 定义多个数据的响应式,接收一个普通对象然后返回该普通对象的响应式代理器对象
(Proxy)
,响应式转换是“深层的”:会影响对象内部所有嵌套的属性,所有的数据都是响应式的。 -
computed() : 计算属性,返回一个
ref
类型的对象 -
toRefs: 把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个
ref
-
provide 与 inject: 实现跨层级组件(祖孙)间通信
// 父组件 setup () { const color = ref('red') provide('color', color) return { color } } // 跨级子组件 setup () { const color = inject('color') return { color } }
四、其他特性
-
Teleport(瞬移): 可以把子组件或者 DOM节点 插入到任何你想插入到的地方去。
<teleport to="body"></teleport>
-
Suspense(不确定的): 在等待异步组件时渲染一些后备内容。
<Suspense> <template v-slot:default> <!-- 异步组件 --> <AsyncComp /> </template> <template v-slot:fallback> <!-- 后备内容 --> <h1>Loading...</h1> </template> </Suspense> // 异步组件 const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
-
响应式数据的判断:
- isRef: 检查一个值是否为一个 ref 对象;
- isReactive: 检查一个对象是否是由 reactive 创建的响应式代理;
- isReadonly: 检查一个对象是否是由 readonly 创建的只读代理;
- isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理。
五、script setup 语法糖
-
组件只需引入无需再注册;
-
属性和方法也不用再 return 返回;
-
不需要 export default {} ;
-
不需要 setup()
-
props / emit / attrs ,使用语法糖提供的新API: defineProps, defineEmit, useContext;
<script setup> import Child from './child.vue' const handleClick = (ctx) => { console.log(ctx) } </script>
注意:如果在父组件中通过 ref='xxx' 的方法来获取子组件实例,子组件使用了script setup 语法糖,那么子组件的数据需要用 expose 的方式导出,否则会因为获取不到数据而报错。
// 子组件 <script setup> import { ref, defineOptions } from 'vue' const { expose } = defineOptions() const count = ref(0) expose({ count }) </script>
-
Emit 派发事件可以对参数进行验证
export default { name: '', emits: { sonClick: (value) => { if (value === 1) { return true } else { return false } }, }, setup(props, { emit }) { const msg = ref('hello') const handleClick = (value) => { emit('sonClick', value) } return { msg, handleClick, } },
-
跨组件通讯 mitt.js 【event bus】
// 安装 npm i mitt -s // 封装 hook, mitt.js import mitt from 'mitt' const emitter = mitt() export default emitter
emitter.on() / emitter.off() / emitter.emit()
-
其他:
Vue3 移除了 filter ; 获取组件实例方法 getCurrentInstance();
六、Vuex
-
Vue 3 使用 Vuex 4.x
yarn add vuex@next --save
-
关于vuex的基本使用:
import Vuex from 'vuex' const store = Vuex.createStore({ state: { // ... } }) export default store // main.ts import store from './store' createApp(App).use(store).mount('#app') // vuex 的使用 import { useStore } from 'vuex' setup () { const store = useStore() // == this.$store store.dispatch() // 模板中使用 {{ store.state.xxx }} }
七、Vue Router
-
关于Vue Router
import { createRouter } from 'vue-router' const router = createRouter({ // ... })
-
使用 history 配置取代 mode 选项
每一个模式都由从 vue-router 导出的函数一一对应:
- history ——> createWebHistory
- hash ——> createWebHash
- abstract ——> createMemoryHistory
import { createRouter, createWebHistory } from 'vue-router' export const router = createRouter({ history: createWebHash(), routes }) export default router
-
使用 router
// main.ts import router from './router' import store from './store' createApp(App) .use(router) .use(store) .mount('#app')
-
取消(*) 通配符路由
// 不再适用 { path: "*" } // 改为必须使用自定义的 regexp 参数来定义所有路由(*, /*) { path: '/:pathMatch(.*)' }
-
<keep-alive>写法变更
// 原写法 <keep-alive v-if="$route.meta.keepAlive"> <router-view></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> // 新写法 :is 用来绑定指定的组件,与路由对应的页面绑定 <router-view v-slot="{ Component }"> <keep-alive> <component :is="Component" v-if="$route.meta.keepAlive"> </keep-alive> <component :is="Component" v-if="$route.meta.keepAlive"/> </router-view>
-
新增 useRoute , useRouter
// 获取路由中的 id import { useRoute, useRouter } from 'vue-router' setup () { const { params: { id }} = useRoute() // == this.$route const router = useRouter() // == this.$router router.push('/login') return { id } }