一、创建项目
- 使用 cli 创建
1 2 3 4
| npm i -g @vue/cli vue create <projectName> cd projectName npm run serve
|
使用vite创建
1 2 3 4
| npm init vite-app <projectName> cd <projectName> npm i npm run dev
|
学习时,使用的是 cli 创建的工程。
二、常用 Composition API
(一)、setup()
组件中用到的:数据、方法等均要配置到 setup 中
setup()中返回一个对象,对象中属性方法在模板中可直接使用。
vue2 不要与 vue3 混用,vue2 可以访问到 vue3 中的属性方法,但 vue3 中不能读取 vue2 中的属性方法。
setup()不能是 async 函数,返回值不为 return 的对象,而为 promise。
(二)、ref 函数
xxxxxxxxxx46 1#include
import {ref} from 'vue'
通过 ref 函数可以定义响应式数据
1 2 3 4 5 6 7
| let name = ref("张三"); { { name; } } name.value;
|
(三)、reactive 函数
定义对象类型响应式数据(基本类型不可用)
reactive 函数返回值是代理对象(Proxy 实例对象,简称 proxy 对象)
基于 ES6 的 Proxy 实现
1 2 3 4
| let person = reactive({ name: "张三", age: 18, });
|
(四)、Vue3 响应式原理
vue2 中实现原理
1 2 3 4
| Object.defineProperty(person, "age", { get() {}, set(value) {}, });
|
捕获不到删除与增加属性。
vue3 中实现原理
1 2 3 4 5 6 7 8 9 10 11 12
| const p = new Proxy(person, { get(target, propName) { return target[propname]; }, set(target, propName, value) { target[propName] = value; }, deleteProperty(target, propName) { return delete target[propName]; }, });
|
其中 target 代表源数据,propName 代表调用的属性,value 代表传入的值。
1 2 3 4 5 6 7
| let obj={ a:100, b=200 } Reflect.get(obj,'a') Reflect.set(obj,'a',300) Reflect.deleteProperty(obj,'a')
|
Reflect 的函数均有返回值,代表操作是否成功。
汇总后可写为:
1 2 3 4 5 6 7 8 9 10 11
| const p = new Proxy(person, { get(target, propName) { return Reflect.get(target, propName); }, set(target, propName, value) { return Reflect.set(target, propName, value); }, deleteProperty(target, propName) { return Reflect.deleteProperty(target.propName); }, });
|
(五)、setup 注意点
执行时机比 beforeCreate 早
setup 接受参数
(六)、计算属性 computed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import {computed} from 'vue' export default{ setup(){ let fn = computed({ get(){}, set(value){} }) let fn = computed(()=>{ }) } return { fn } }
|
(七)、监视属性 watch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import {ref,reactive,watch} from 'vue' export default{ setup() { let sum=ref(0); let msg=ref(1); let person=reactive({ name:"张三", age:20 }) watch(sum,(new,old)=>{},{immediate:true}) watch([sum,msg],(new,old)=>{},{immediate:true}) watch(person,(new,old)=>{},{immediate:true}) watch(()=>person.name,(new,old)=>{}) watch([()=>person.name,()=>person.age],(new,old)=>{}) } }
|
(八)、watchEffect
1 2 3 4 5
| import {ref,reactive,watch,watchEffect} from 'vue' setup(){ watchEffect(()=>{ }) }
|
watchEffect 会监视回调函数中所有被用到的属性。
(九)、生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmounted,onUnmounted} from 'vue' setup(){ onBeforeMount(()={}) onBeforeMount(()={}) onBeforeUpdate(()={}) onUpdated(()={}) onBeforeUnmounted(()={}) onUnmounted(()={}) } beforeCreate(){} created(){} beforeMount(){} mounted(){} beforeUpdate(){} update(){} beforeUnmount(){} unmounted(){}
|
(十)、自定义 hook*
在 src 目录下创建 hooks 文件夹,文件通常命名为 usexxx.js。
1 2 3 4 5 6 7 8 9 10 11 12
| import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmounted, onUnmounted, } from "vue"; export default function () { }
|
1 2 3 4 5 6 7 8
| import usexxx.js from '../hooks/usexxx' export default{ setup(){ const u = usexxx() return {u} } }
|
hook 本质是一个函数,把 setup 函数中的 Composition API 进行封装,实现功能复用
(十一)、toRef 与 toRefs
toRef 创建一个 ref 对象,并将自身的值指向另一个对象中的某个属性
1 2 3 4 5 6 7 8 9 10 11 12 13
| let person = reactive({ name:'name', age:'age', kids:{ tom:{ age:20; } } }) const name = toRef(person,'name') return { ...toRefs(person) }
|
将响应式数据中的某个属性单独提供给外部使用。
toRefs 是 toRef 的扩展,可批量创建多个 ref。
const name = toRef(person)
详见:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=157
三、其他 Composition API
(一)、shallowReactive 与 shallowRef
shallowReactive 只处理对象最外层属性的响应式(浅响应式)
shallowRef 只处理基本数据类型响应式,不处理对象响应式
(二)、readonly 与 shallowReadonly
readonly 能让响应式数据变为只读(深只读)
shallowReadonly 让响应式数据变为只读(浅只读)
(三)、toRaw 与 markRaw
toRaw 将由reactive生成的响应式对象转为普通对象。
markRaw 将标记一个对象,使其永远不会成为响应式对象。
(四)、customRef
创建自定义 Ref。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import {customRef} from 'vue' setup(){ let word = myRef('hello') function myRef(value){ return customRef((track,trigger)=>{ return{ get(){ track() return value; }, set(new){ value = new trigger() } } }) } }
|
(五)、provide 与 inject
适用于祖与后代组件间通信
1 2 3 4 5 6 7 8 9 10 11 12
| import { provide, reactive } from "vue"; export default { setup() { let person = reactive({ name: "张三", age: 20, }); provide("person", person); return { ...toRefs(person) }; }, };
|
1 2 3 4 5 6 7
| import { inject } from "vue"; export default { setup() { let person = inject("person"); return { ...toRefs(person) }; }, };
|
(六)、响应式数据判断
isRef:判断是否为 ref 对象
isReactive:判断是否为 reactive 创建的代理对象
isReadonly:判断是否为 readonly 创建的只读代理对象
isProxy:判断是否为 reactive 或 readonly 创建的代理对象
四、新组件
(一)、Fragment
组件可以没有根标签,内部多个标签会包含在一个 Fragment 虚拟元素中。
(二)、Teleport
将组件 html 解构传送到指定解构
1 2 3 4 5
| <teleport to="移动位置"> <div v-if="show"> <div>内容</div> </div> </teleport>
|
移动位置可以是 id,class,标签名
(三)、Suspense
1 2
| import { defineAsyncComponent } from "vue"; const Child = defineAsyncComponent(() => import("./components/Child"));
|
1 2 3 4 5 6 7 8 9 10
| <Suspense> <template v-slot:default> //组件加载完成后显示 <Child></Child> </template> <template v-slot:fallback> //组件加载中显示 <h3>加载中</h3> </template> </Suspense>
|
使用异步加载后,子组件可以 setup 可以使用异步加载模式返回 Promise 对象
五、全局 API 转移
![image-20220724233205931]()
来源:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=168
Vue3 中移除 v-on.native 修饰符
取而代之是在子组件中添加emits:[]
属性来申明自定义事件,不声明默认为原生事件
1 2
| <components v-on:close="close" v-on:click="click"></components>
|
1 2 3 4
| export default { emits: ["close"], };
|
Vue3 中移除了过滤器,通过 computed 替代