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>

Par 纳兰风来, Catégorie : 25-003

Tags :