Skip to content

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>

Released Under The MIT License.