Appearance
Props
props
props 是组件的自定义属性,组件的使用者可以通过 props 把数据传递到子组件内部,供子组件内部进行使用。 在使用<script setup>的组件中,props 可以通过 defineProps 函数来定义。
vue
<script setup>
defineProps({
name: String,
age: Number,
isStudent: Boolean,
});
</script>在子组件中,可以通过 props 对象来访问传递过来的 props 数据。
vue
<template>
<div>
<p>Name: {{ name }}</p>
<p>Age: {{ age }}</p>
<p>Is Student: {{ isStudent }}</p>
</div>
</template>在父组件中,可以通过子组件的标签属性来传递 props 数据。
vue
<!-- 虽然 `20, true` 是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<MyComponent name="John" :age="20" :is-student="true" />在子组件中,可以通过 props 对象来访问传递过来的 props 数据。
vue
<script setup>
const props = defineProps({
name: String,
age: Number,
isStudent: Boolean,
});
console.log(props.name); // 输出: John
console.log(props.age); // 输出: 20
console.log(props.isStudent); // 输出: true
</script>
<template>
<div>
<p>Name: {{ props.name }}</p>
<p>Age: {{ props.age }}</p>
<p>Is Student: {{ props.isStudent }}</p>
</div>
</template>props命名
prop 的名字很长,应使用 camelCase 形式,它们是合法的 JavaScript 标识符。在为其绑定属性值,可以绑定 camelCase 的形式,也可以绑定 kebab-case 的形式。推荐使用 kebab-case 形式,更贴近 HTML 的书写风格。
组件 v-model
v-model可以实现双向绑定
vue
<!-- 子组件 -->
<template>
<input :value="message" @input="$emit('update:message', $event.target.value)" />
<p>Message: {{ message }}</p>
</template>
<script setup>
defineProps(['message']);
defineEmits(['update:message']);
</script>vue
<!-- 父组件 -->
<template>
<MyComponent v-model:message="message" />
<p>Message: {{ message }}</p>
</template>
<script setup>
import { ref } from 'vue';
const message = ref('Hello');
</script>v-model可以创建多个,但要注意的是,v-model的值必须与props的值相匹配。
v-model 修饰符
组件也支持v-model的内置修饰符,例如 .trim、.number 和 .capitalize等。还可以自定义组件的 v-model 修饰符。 组件添加的所有修饰符,可以通过在 prop 内声明 modelModifiers 在组件内访问,它默认是一个空对象。
vue
<MyComponent v-model.capitalize="message" />vue
<script setup>
const props = defineProps({
message: String,
modelModifiers: { default: () => {} },
});
defineEmits(['update:message']);
console.log(props.modelModifiers); // { capitalize: true }
</script>我们还可以直接对传入参数带上修饰符,prop 内会自动添加对应的修饰符,对应名将是 arg + "Modifiers"。
vue
<MyComponent v-model:message.capitalize="message" v-model:name.uppercase="name" />vue
<script setup>
const props = defineProps({
message: String,
name: String,
messageModifiers: { default: () => {} },
nameModifiers: { default: () => {} },
});
defineEmits(['update:message', 'update:name']);
console.log(props.messageModifiers); // { capitalize: true }
console.log(props.nameModifiers); // { uppercase: true}
</script>如果你显式的使用了 setup 函数而不是 <script setup> 标签,那么参数需要通过 props 选项来声明:
vue
<script>
export default {
props: {
modelValue: String,
modelModifiers: { default: () => {} },
},
setup(props) {
return { props };
},
};
</script>组件事件监听器
事件触发和监听
在组件的模板表达式中,可以直接使用 $emit 方法触发自定义事件 (例如:在 v-on 的处理函数中):
vue
<button @click="$emit('myEvent')">Click me</button>父组件可以通过 v-on 监听子组件触发的自定义事件:
vue
<MyComponent @my-event="handleMyEvent" />组件事件监听器也支持 .once 修饰符
vue
<MyComponent @my-event.once="handleMyEvent" />事件的命名和 prop 的的命名形式一样,即使用 camelCase 命名的事件名,在监听器中使用 kebab-case 命名。
事件参数
有时候在触发事件时,需要传递一些参数。
vue
<button @click="$emit('myEvent', 123)">Click me</button>vue
<template>
<MyComponent @my-event="handleMyEvent($event)" />
</template>
<script setup>
function handleMyEvent(value) {
console.log(value); // 123
}
</script>传递的参数可以是任意类型,包括对象。并且不限制传递参数的数量。
vue
<button @click="$emit('myEvent', { foo: 'bar' }, 123, 'message')">Click me</button>vue
<template>
<MyComponent @my-event="handleMyEvent($event)" />
</template>
<script setup>
function handleMyEvent(event, value, msg) {
console.log(event, value, msg); // { foo: 'bar' } 123 message
}
</script>在 <script setup> 中不能使用 $emit 方法,但是 defineEmits() 会返回一个相同作用的函数供我们使用。
vue
<script setup>
const emit = defineEmits(['myEvent']);
function handleMyEvent() {
emit('my-event', 'message');
}
</script>如果你显式的使用了 setup 函数而不是 <script setup> 标签,那么事件需要通过 emits 选项来声明:
vue
<script>
export default {
emits: ['myEvent'],
setup(props, { emit }) {
function handleMyEvent() {
emit('my-event', 'message');
}
return { handleMyEvent };
},
};
</script>事件校验
事件同样可以添加校验,校验规则需要通过 defineEmits 函数来定义:
vue
<script setup>
const emit = defineEmits({
// 没有校验
myEvent: null,
// 校验参数类型 必须为字符串
myEvent2: playload => {
if (typeof playload !== 'string') {
return true;
} else {
console.warn('payload must be a string');
return false;
}
},
});
function handleMyEvent() {
myEvent('message');
myEvent2('message');
myEvent2(123); // 控制台输出警告信息
}
</script>