vue3学习笔记之组件
组件
src/views/ad/Comp.vue
<script setup>
import { ref, provide, readonly, defineAsyncComponent } from "vue";
import DemoComp from "../../components/simple/DemoComp.vue";
import ErrorComponent from "../../components/simple/ErrorComp.vue";
import LoadingComponent from "../../components/simple/LoadingComp.vue";
const count = ref(5);
const isActive = ref(true);
const postFontSize = ref(1);
const dynamicSlotName = "slot4";
// 组件后代提供数据,避免“prop 逐级透传”
provide("module_name", "ad");
const location = ref("North Pole");
function updateLocation() {
location.value = "South Pole";
}
//允许组件后代修改数据
provide("location", {
location,
updateLocation,
});
//不允许组件后代修改数据
provide("read_only_count", readonly(count));
//异步组件
const HelloComp = defineAsyncComponent(() => import("../../components/simple/HelloComp.vue")); //简单用法
// 定义一个耗时执行的函数,t 表示延迟的时间, callback 表示需要执行的函数,可选
const time = (t, callback = () => {}) => {
return new Promise((resolve) => {
setTimeout(() => {
callback();
resolve();
}, t);
});
};
const Hello = defineAsyncComponent({
// 加载函数
loader: () => {
return new Promise((resolve, reject) => {
(async function () {
await time(2000);
const res = await import("../../components/simple/HelloComp.vue");
resolve(res);
})();
});
},
loadingComponent: LoadingComponent, // 加载异步组件时使用的组件
delay: 1000, // 展示加载组件前的延迟时间,默认为 200ms
errorComponent: ErrorComponent, // 加载失败后展示的组件
timeout: 3000,
});
</script>
<template>
<div>
<div :style="{ fontSize: postFontSize + 'rem' }">
<el-row :gutter="5">
<el-col :span="12">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>组件</span>
</div>
</template>
<demo-comp
:class="{ active: isActive }"
title="Vue3"
greeting-message="hi"
:likes="42"
:is-published="false"
:comments="[
{ id: 234, content: 'ok' },
{ id: 266, content: 'nice' },
{ id: 273, content: 'not good' },
]"
:author="{ name: 'Veronica', company: 'Veridian Dynamics' }"
@enlarge-text="postFontSize += 0.1"
>渲染default slot
<template #slot2>
<span>渲染slot2</span>
</template>
<template v-slot:slot3>
<span>渲染slot3</span>
</template>
<template v-slot:[dynamicSlotName]>
<span>渲染slot4</span>
</template>
<!-- 作用域插槽,父组件接收子组件传过来的值itemProps,父组件可以根据子组件传过来的值决定插槽的内容 -->
<template #item="itemProps">
{{ itemProps.id + "|" + itemProps.content }}
</template>
</demo-comp>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>组件</span>
</div>
</template>
<demo-comp
:class="{ active: isActive }"
title="test"
greeting-message="test"
:likes="30"
:is-published="true"
:comments="[
{ id: 234, label: 'ok', num: 10 },
{ id: 266, label: 'nice', num: 5 },
{ id: 273, label: 'not good', num: 18 },
]"
:author="{ name: 'Veronica', company: 'Veridian Dynamics' }"
@enlarge-text="postFontSize += 0.1"
>
<!-- 作用域插槽,父组件接收子组件传过来的值itemProps,父组件可以根据子组件传过来的值决定插槽的内容 -->
<template #item="itemProps">
{{ itemProps.id + "|" + itemProps.label + "|" + itemProps.num }}
</template>
</demo-comp>
</el-card>
</el-col>
</el-row>
</div>
<div>
<p>异步组件</p>
<hello-comp></hello-comp>
<p>延时3s渲染</p>
<hello></hello>
</div>
</div>
</template>
<style scoped>
span {
margin-left: 1rem;
}
</style>
src/components/simple/DemoComp.vue
<script setup>
import { ref, inject } from "vue";
defineOptions({
inheritAttrs: false, //禁用 Attributes 继承
});
const props = defineProps({
title: String,
greetingMessage: String,
likes: Number,
isPublished: Boolean,
author: Object,
comments: Array,
});
const emits = defineEmits(["enlargeText"]);
const count = ref(0);
// 注入上层组件提供的数据
const api_url = inject("api_url");
const module_name = inject("module_name");
const { location, updateLocation } = inject("location");
let read_only_count = inject("read_only_count");
function updateCount() {
read_only_count.value++;
alert("read_only_count的值为:" + read_only_count.value);
}
</script>
<template>
<div>
<p :class="$attrs.class">
<span>msg:{{ title }}</span>
<span>greetingMessage:{{ greetingMessage }}</span>
<span>likes:{{ likes }}</span>
<span>is-published:{{ isPublished ? "是" : "否" }}</span>
<span>author:{{ author.name + "|" + author.company }}</span>
</p>
<button type="button" @click="count++">count is {{ count }}</button>
<button @click="$emit('enlargeText')">Enlarge text</button>
<p>
<slot><span>default slot </span></slot>
<slot name="slot2"><span>slot2</span></slot>
<slot name="slot3"><span>slot3</span></slot>
<slot name="slot4">
<span>slot4</span>
</slot>
</p>
<!-- 作用域插槽,子组件传值item给父组件 -->
<p>
comments:
<span v-for="(item, index) in comments" :key="index">
<slot name="item" v-bind="item"></slot>
</span>
</p>
<p>
App.vue注入:
<span>{{ api_url }}</span>
</p>
<p>
父级组件注入(允许修改):
<span>{{ module_name }}</span>
<button @click="updateLocation">{{ location }}</button>
</p>
<p>
父级组件注入(不允许修改):
<span>{{ read_only_count }}</span>
<button @click="updateCount">update count</button>
</p>
</div>
</template>
<style scoped>
span {
margin-left: 1rem;
}
button,
a {
border: 1px solid blue;
margin-left: 1rem;
}
</style>

浙公网安备 33010602011771号