一、定义属性
有时候我们定义一个组件后,需要让调用者传入参数,那么就可以将参数定义成属性。示例代码如下:
1、Person组件代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <script setup name="Person"> // Person组件 import {defineProps} from "vue";
// 1. 使用数组的形式 //const props = defineProps(['username']) // 2. 使用对象的形式 const props = defineProps({ gender: { type: String, default: '男' }, username: String, age: Number, body: { height: Number, weight: Number } })
</script>
<template> <p> 用户名:{{ props.username }}, 年龄:{{ props.age }}, 身高:{{ props.body.height }}, 体重:{{ props.body.weight }} </p> </template>
|
2、App.vue组件代码
1 2 3 4 5 6 7
| <script setup> import Person from "./components/Person.vue" </script>
<template> <Person :age="18" username="张三" :body="{height: 180, weight: 140}"></Person> </template>
|
子组件不能修改父组件传过来的props ,否则会引起错误。
二、自定义事件
子组件可以自定义事件,然后父组件可以实现发生这个事件的处理函数。示例代码如下:
1. Person.vue组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script setup name="Person"> import {defineEmits, ref} from "vue";
let steps = ref(0);
const emit = defineEmits(['change']);
const onUpdate = () => { steps.value += 10 emit('change', steps.value); }
</script>
<template> <button @click="onUpdate">行走10步</button> </template>
|
2. App.vue组件
1 2 3 4 5 6 7 8 9 10 11
| <script setup> import Person from "./components/Person.vue"
const onPersonChange = (steps) => { console.log("步行了:", steps); } </script>
<template> <Person @change="onPersonChange"></Person> </template>
|
三、定义v-model
使用v-model 可以定义一个在父组件和子组件中双向绑定的对象。示例代码如下:
1. Person.vue组件代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup name="Person"> import {defineModel, watch} from "vue";
let steps = defineModel(); const onUpdate = () => { steps.value += 10; } watch(steps, (newValue, oldValue) => { console.log("Person中监听到steps:", newValue); })
</script>
<template> <button @click="onUpdate">行走10步</button> </template>
|
- App.vue组件代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <script setup> import {ref, watch} from "vue"; import Person from "./components/Person.vue"
let steps = ref(0); watch(steps, (newValue, oldValue) => { console.log("App中监听到的:", newValue); }) </script>
<template> <Person v-model="steps"></Person> </template>
|
四、插槽
插槽(Slots)在Vue中是一种非常重要的内容组织方式,它能够让你在子组件中留下预先定义的位置,然后在父组件中填充这些位置。
1. 基本使用:
示例代码如下:
1 2 3 4 5
| <template> <button type="submit"> <slot></slot> </button> </template>
|
App.vue代码:
1 2 3
| <template> <SubmitButton>登录</SubmitButton> </template>
|
“登录”这个文本就会填充在SubmitButton的slot标签处。或者也可以在定义插槽的时候指定默认值,比如:
1 2 3 4 5 6
| // SubmitButton.vue代码 <template> <button type="submit"> <slot>提交</slot> </button> </template>
|
那么以后在使用SubmitButton组件的时候,使用<SubmitButton></SubmitButton> 也会有提交两个文字。
1.2. 具名插槽:
如果在一个组件中想要定义多个插槽,则可以使用“具名”插槽,就是给每个插槽指定一个名称,父组件使用的时候,也要指明相应代码要放到哪个插槽下,比如我们定义一个BaseLayout 组件:
1 2 3 4 5 6 7 8 9 10 11
| <div class="container"> <header> <!-- 标题内容放这里 --> </header> <main> <!-- 主要内容放这里 --> </main> <footer> <!-- 底部内容放这里 --> </footer> </div>
|
其中header 、main 、footer 是由父组件自由指定的,那么组件的代码可以修改为:
1 2 3 4 5 6 7 8 9 10 11
| <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
|
其中有三个插槽,分别是header、默认的插槽、以及footer插槽。那么在父组件中可以按照如下方式使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <BaseLayout> <template <h1>Here might be a page title</h1> </template>
<template <p>A paragraph for the main content.</p> <p>And another one.</p> </template>
<template <p>Here's some contact info</p> </template> </BaseLayout>
|
对于default插槽,可以不用指明名称,因此也可以如下使用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <BaseLayout> <template <h1>Here might be a page title</h1> </template>
<!-- 隐式的默认插槽 --> <p>A paragraph for the main content.</p> <p>And another one.</p>
<template <p>Here's some contact info</p> </template> </BaseLayout>
|
1.3. 插槽作用域:
在父组件中,如果使用插槽,则插槽中的代码是无法访问子组件中的变量的。如果想要访问,那么必须在定义插槽的时候显示指定。示例代码如下:
BaseLayout.vue组件代码:
1 2 3 4 5 6 7 8 9 10 11
| <div class="container"> <header> <slot name="header" :tab="1"></slot> </header> <main> <slot :card="2"></slot> </main> <footer> <slot name="footer" :box="3"></slot> </footer> </div>
|
App.vue组件代码:以后在父组件中,可以通过以下方式,获取到子组件中传递过来的插槽信息:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <BaseLayout> <template {{ headerProps }} </template>
<template {{ defaultProps }} </template>
<template {{ footerProps }} </template> </BaseLayout>
|