作用:实现祖孙组件间通信
套路:父组件有一个provide选项来提供数据,子组件有一个inject选项来开始使用这些数据
具体写法:
1.父组件中:引用provide
<template>
<div class="app">
<p>我是App组件————祖组件</p>
<p>数据:name:{{ name }}——————age:{{ age }}</p>
<Child />
</div>
</template>
<script>
import Child from "./components/Child.vue";
import { reactive, toRefs, provide } from "vue";
export default {
name: "App",
components: {
Child,
},
setup() {
let obj = reactive({
name: "张三",
age: 20,
});
// 给自己的后代组件传递数据
provide("obj", obj);
return {
// obj,
...toRefs(obj),
};
},
};
</script>
<style>
.app {
padding: 10px;
border-radius: 5px;
background-color: orange;
}
</style>
2.子组件:中间的组件
<template>
<div class="child">
<p>我是child组件————子组件</p>
<Son />
</div>
</template>
<script>
// 在这个组件也可以用inject接收父组件的数据,但是这是父子组件之间的传值,一般不用这个
import Son from "./Son.vue";
export default {
name: "child",
components: {
Son,
},
};
</script>
<style>
.child {
padding: 10px;
border-radius: 5px;
background-color: pink;
}
</style>
3.孙组件:
<template>
<div class="son">
<p>我是Son组件————孙组件</p>
</div>
</template>
<script>
import { inject } from "vue";
export default {
name: "Son",
setup() {
// 这个obj也是响应式的数据
const obj = inject("obj");
return {
obj,
};
},
};
</script>
<style>
.son {
padding: 10px;
border-radius: 5px;
background-color: skyblue;
}
</style>
1.isRef:检查一个值是否为一个ref对象(RefImpl)
2.isReactive:检查一个对象是否是由reactive创建爱你的响应式代理
3.isReadonly:检查一个对象是否是由readonly创建的只读代理
4.isProxy:检查一个对象是否由reactive或者readonly方法创建的代理
<template>
<div class="app">
<p>obj:{{ name }}——————{{ age }}</p>
<p>p:{{ p }}</p>
</div>
</template>
<script>
import {
reactive,
toRefs,
ref,
readonly,
isProxy,
isReactive,
isRef,
isReadonly,
} from "vue";
export default {
name: "App",
components: {},
setup() {
let obj = reactive({
name: "张三",
age: 20,
});
let num = ref(0);
let p = readonly(obj);
// 判断
console.log(isProxy(p)); //true
console.log(isProxy(obj)); //true
console.log(isReactive(p)); //true
console.log(isReactive(obj)); //true
console.log(isRef(num)); //true
console.log(isReadonly(p)); //true
console.log(isReadonly(obj)); //false
return {
// obj,
...toRefs(obj),
num,
p,
};
},
};
</script>
<style>
.app {
padding: 10px;
border-radius: 5px;
background-color: orange;
}
</style>
1.Options API存在的问题
使用传统Options API(vue2.0)中,新增或者修改一个需求,就需要分别在data、methods、computed里修改
2.Composition API的优势
可以更加优雅的组织代码、函数,让相关功能的代码更加有序的组织在一起(要结合hooks)
在Vue2中:组件必须有一个根标签
在Vue3中:组件可以没有根标签,内部会将多个标签包含在一个Fragment虚拟元素中
好处:减少标签层级,减少内存占比
Teleport是一种能够将我们的组件html结构移动到指定位置的技术
<template>
<div>
<button @click="isShow = !isShow">显示弹窗</button>
<!-- to:将teleport标签内的内容放到指定地方,可以写当前页面内的标签,也可以写与容器(App)平级的容器 -->
<teleport to="body">
<!-- <teleport to="#box"> -->
<!-- 遮罩层 -->
<div v-if="isShow" class="mask">
<div class="dialog">
<p>干饭了</p>
<p>下班啦</p>
<p>睡觉了</p>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Dialog",
setup() {
let isShow = ref(false);
return {
isShow,
};
},
};
</script>
<style>
.mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
}
.dialog {
/* 居中显示 */
position: absolute;
left: 50%;
top: 50%;
/* 参考自身 */
transform: translate(-50%, -50%);
width: 300px;
height: 300px;
border-radius: 10px;
color: #fff;
text-align: center;
font-weight: bold;
background-color: palevioletred;
}
</style>
等待异步组件时渲染一些额外内容,让应用有更好的用户体验
使用步骤:
异步引入组件:
import { defineAsyncComponent } from "vue";
const Child = defineAsyncComponent(() => import("./components/Child.vue"));
使用Suspense包裹组件,并配置好default与fallback
<Suspense>
<!-- 正常情况下默认显示的是这个,default是固定的,不可改 -->
<template v-slot:default>
<Child />
</template>
<!-- 网速太慢了,Child组件还未渲染出来时显示这里面的内容,fallback是内定的,不可改 -->
<template v-slot:fallback>
<p>加载中,请稍后</p>
</template>
</Suspense>