Vue 3中制作自己的组件
Le Sat 22 February 2025
组件是可以多次重复使用的Vue代码。制作好自己的组件后,遇到相同的功能时,调用组件即可,不需要再重复组件的代码内容。
组件属性
在vue 3中制作自己的组件,需要用到下列这些东西。
- props 组件的属性。用以将数据传递给组件,供组件使用。
- events 事件。
- slots 槽。用于内容整体替换。
- expose 对外展示数据。
- v-model 数据的双向绑定。
- provide 可以自动传递给子孙后代组件的属性。用以传递数据。
- inject 子组件或者孙组件获取父组件传入的值。
JavaScript组合式制作新组件
用组合式风格时,script标签写上setup属性。
<script setup>
const props = defineProps({
foo: String
})
const emit = defineEmits(['change', 'delete'])
// setup code
</script>
用 defineProps 和 defineEmits 声明 props 和 emits。
defineProps 和 defineEmits 是vue转译工具预先定义的东西。<script setup>中内容会被转译。
TypeScript组合式制作新组件
声明Props接口,并使用defineProps语法。
interface Props {
foo: string
bar?: number
}
const props = defineProps<Props>();
如果需要初始值,则用withDefaults语法。
interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
props和emit的使用
<template>
<div class="itxst">
<p :style="{ color: color, fontSize: fontSize + 'px' }">我是子组件</p>
<input class="btn" @click="update" type="button" value="修改颜色" />
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
/*
* 定义组件的属性
* type 表示属性类型
* default 表示默认值
*/
const props = defineProps({
fontSize: {
type: Number,
default: 14,
},
color: {
type: String,
default: "#000",
},
});
/*
也可以通过数组方式定义属性,缺点是不能定义类型和默认值
const props = defineProps(['msg','color']);
*/
//修改属性的值,定义emits可修改color属性
const emits = defineEmits(["update:color", "update:fontSize"]);
// <demo v-model:color="parentColor" :fontSize="15"/>
const update = () => {
//把颜色改成黑色
emits("update:color", "red");
//父组件fontSize没有使用v-model,所以下面代码无法修改fontSize值
emits("update:fontSize", 20);
};
</script>
<style scoped>
</style>
使用做好的组件。
<template>
<!-- 注意使用了 v-model和 parentColor变量 -->
<demo v-model:color="parentColor" :fontSize="15" />
</template>
<script>
import demo from "./components/sku.vue";
export default {
name: "app",
//注册组件
components: {
demo,
},
data() {
return {
parentColor: "#666",
};
},
};
</script>
Slots的使用
在模板中我们可以通过$slots来访问所有的默认插槽以及具名插槽
比如:Auth组件校验不通过时,隐藏slots的内容
<Auth auth="commit">
<button>提交<button>
</Auth>
// components
<template>
<slot v-if="condition" />
</template>
再比如:组件内部有多个插槽及具名插槽的时候 form表单中的form-item组件是可以自定义插槽来覆盖默认的input内容的,在模板中就可以通过$slots来访问具体的插槽对象
<form-item>
<template #input>
自定义form input内容
</template>
</form-item>
// components
<template>
<slot v-if="$slots.input" name="input" />
<input v-else />
</template>
在setup中操作Slots,但是它依然提供了useSlots方法来帮我们操作组件的Slots
<script setup>
import { useSlots } from 'vue'
const slots = useSlots()
</script>
Expose的使用
使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。
有些状态外部或许需要在适当时候操作或访问的时候,我们就需要考虑那些属性和方法是可以暴露给外部的
可以使用defineExpose来声明绑定
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
当父组件通过模板 ref 的方式获取到当前组件的实例,获取到的实例会像这样 { a: number, b: number }(ref 会和在普通实例中一样被自动解包)
v-model
它代表声明了一个modelValue的属性以及一个update:modelValue的事件
Vue 3 中可以通过 propsName + update:propsName 来自定义v-model
一个组件里可以定义多个v-model
<cmp v-model:foo="xxx" v-model:bar="xxxx" />
// components
<script setup>
interface Props {
foo: string
bar: string
}
const props = defineProps<Props>();
const emits = defineEmits(["update:foo", "update:bar"]);
</script>
provide 与 inject的使用
父组件:
<script setup>
import { provide } from "vue";
const userObj = ref<User>(...);
provide("user", userObj);
const fn = () => {
...
}
provide("change", fn);
</script>
子组件:
<script setup>
import { inject } from "vue";
const injectUserObj = inject("user");
const injectFn = inject("change");
</script>