vue3 组件的二次封装(保留其属性和事件,插槽,方法)

vue3 组件的二次封装

基础组件

模拟封装一个基础组件,包含
一个 base 事件,一个 title 属性,
默认插槽和 foote r插槽
暴漏 close open 方法
x-base

<script lang="ts" setup>
defineProps<{ title: string }>();
const emit = defineEmits<{
	base: [];
}>();
function close() {
	console.log("close");
}
function open() {
	console.log("open");
}
defineExpose({ close, open });
</script>

<template>
	<div>
		<h2 @click="emit('base')">{{ title }}</h2>
		<div class="default"><slot></slot></div>
		<div class="footer"><slot name="footer" msg="base组件 footer 插槽内容"></slot></div>
	</div>
</template>

<style lang="scss" scoped></style>

二次封装

基于 x-base 组件二次封装演示
x-test

<script lang="ts">
import { useSlots, onMounted, ref, defineComponent } from "vue";
import xBase from "../x-base/index.vue";
export default defineComponent({
	mounted() {
		for (const key in this.$refs.baseRef) {
			this[key] = this.$refs.baseRef[key];
		}
	},
});
</script>

<template>
	<div>
		<x-base v-bind="$attrs" ref="baseRef">
			<!-- <template></template> -->
			<!-- <template #footer="scope"></template> -->
			<template v-for="(value, key) in $slots" :key="key" #[key]="scope">
				<slot :name="key" v-bind="scope"></slot>
			</template>
		</x-base>
	</div>
</template>

<style lang="scss" scoped></style>

app.vue 使用

<script lang="ts" setup>
import { ref } from "vue";
import xTest from "./components/x-test/index.vue";
const xTestRef = ref<InstanceType<typeof xTest> | null>(null);

function close() {
	xTestRef.value?.close();
}
</script>
<template>
	<x-test title="base" @base="console.log(123)" ref="xTestRef">
		<template #default>default</template>
		<template #footer="scope">footer--{{ scope }}</template>
	</x-test>
	<button @click="close">关闭</button>
</template>

<style lang="scss" scoped></style>

解决属性和事件

$attrs 一个包含了组件所有透传 attributes 的对象。
透传 Attributes 是指由父组件传入,且没有被子组件声明为 props 或是组件自定义事件的 attributes 和事件处理函数。

<x-base v-bind="$attrs"></x-base>

解决插槽

$slots 一个表示父组件所传入插槽的对象。
对象 key 即是插槽名称

<x-base v-bind="$attrs">
	<!-- <template #default></template> -->
	<!-- <template #footer="scope"></template> -->
	// 参照上面写法容易理解
	<template v-for="(value, key) in $slots" :key="key" #[key]>
		<slot :name="key"></slot>
	</template>
</x-base>

作用域插槽

<x-base v-bind="$attrs">
	<template v-for="(value, key) in $slots" :key="key" #[key]="scope">
		<slot :name="key" v-bind="scope"></slot>
	</template>
</x-base>

ref 方法使用

<x-base v-bind="$attrs" ref="baseRef"></x-base>
export default defineComponent({
	mounted() {
		for (const key in this.$refs.baseRef) {
			this[key] = this.$refs.baseRef[key];
		}
	},
});

使用

<script lang="ts" setup>
import { ref } from "vue";
import xTest from "./components/x-test/index.vue";
const xTestRef = ref<InstanceType<typeof xTest> | null>(null);

function close() {
	xTestRef.value?.close();
}
</script>
<template>
	<x-test title="base" @base="console.log(123)" ref="xTestRef">
		<template #default>default</template>
		<template #footer="scope">footer--{{ scope }}</template>
	</x-test>
	<button @click="close">关闭</button>
</template>

<style lang="scss" scoped></style>

你可能感兴趣的:(vue,vue.js,前端)