vue props

Props

This chapter assumes that you have looked at Component Fundamentals . If you don't know what a component is yet, please read this chapter first.

Props declaration

A component needs to explicitly declare the props it accepts, so that Vue can know which props are passed in from the outside and which are transparent attributes (we will discuss transparent attributes in a special chapter ) .

In single-file components used  <script setup> , props can be  defineProps() declared using macros:

vue

<script setup>
const props = defineProps(['foo'])

console.log(props.foo)
</script>

In unused  <script setup> components, props can   be declared using the props option:

js

export default {
  props: ['foo'],
  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.foo)
  }
}

Note that the parameters passed to  defineProps() and the value provided to  props the option are the same, and the prop option is actually used behind the two declaration methods.

In addition to using an array of strings to declare props, you can also use the form of objects:

js

// 使用 <script setup>
defineProps({
  title: String,
  likes: Number
})

js

// 非 <script setup>
export default {
  props: {
    title: String,
    likes: Number
  }
}

For each property in an object declaration, the key is the name of the prop, and the value is the constructor function for that prop's expected type. For example, if a prop's value is required to be  number a type, use  Number a constructor as its declared value.

The props declaration in the form of an object can not only serve as a component's documentation to some extent, but also throw a warning in the browser console if other developers pass the wrong type when using your component. We'll discuss more details about prop validation further down in this chapter  .

If you're using TypeScript  <script setup>, you can also use type annotations to declare props:

vue

<script setup lang="ts">
defineProps<{
  title?: string
  likes?: number
}>()
</script>

See Component props type annotations for more details on type-based declarations .

Passing prop details

Prop name format

If the name of a prop is very long, camelCase should be used, because they are legal JavaScript identifiers, can be used directly in template expressions, and can also avoid having to add quotes when used as property key names.

js

defineProps({
  greetingMessage: String
})

template

<span>{
   
   { greetingMessage }}</span>

Although in theory you can also use camelCase when passing props to child components (except when using  DOM templates ), in practice, in order to align with HTML attributes, we usually write it as kebab-case:

template

<MyComponent greeting-message="hello" />

We recommend using PascalCase for component names  , because it improves the readability of the template and helps us distinguish Vue components from native HTML elements. However, for passing props, there is not much advantage to using camelCase, so we recommend a writing style closer to HTML.

Static vs. Dynamic Props

By now, you've seen a lot of props with static values ​​like this:

template

<BlogPost title="My journey with Vue" />

Correspondingly, there are props that use  v-bind or abbreviate  : for dynamic binding:

template

<!-- 根据一个变量的值动态传入 -->
<BlogPost :title="post.title" />

<!-- 根据一个更复杂表达式的值动态传入 -->
<BlogPost :title="post.title + ' by ' + post.author.name" />

Pass different value types

In the above two examples, we only passed string values, but in fact any type of value can be passed as the value of props.

Number

template

<!-- 虽然 `42` 是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :likes="42" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :likes="post.likes" />

Boolean

template

<!-- 仅写上 prop 但不传值,会隐式转换为 `true` -->
<BlogPost is-published />

<!-- 虽然 `false` 是静态的值,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :is-published="false" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :is-published="post.isPublished" />

Array

template

<!-- 虽然这个数组是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost :comment-ids="[234, 266, 273]" />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :comment-ids="post.commentIds" />

Object

template

<!-- 虽然这个对象字面量是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<BlogPost
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
 />

<!-- 根据一个变量的值动态传入 -->
<BlogPost :author="post.author" />

Use one object to bind multiple props

If you want to pass in all properties of an object as props, you can use v-bind with no parameters , that is, only use  v-bind not  :prop-name. For example, here is an  post object:

js

const post = {
  id: 1,
  title: 'My Journey with Vue'
}

and the following template:

template

<BlogPost v-bind="post" />

And this is actually equivalent to:

template

<BlogPost :id="post.id" :title="post.title" />

unidirectional data flow

All props follow the principle of one-way binding . Props change due to the update of the parent component, and naturally flow the new state down to the child component without passing it backwards. This prevents child components from accidentally modifying the state of the parent component, otherwise the data flow of the application can easily become confusing and difficult to understand.

In addition, every time the parent component is updated, all props in the child components will be updated to the latest values, which means that you should not change a prop in the child component. If you do, Vue will throw you a warning on the console:

js

const props = defineProps(['foo'])

// ❌ 警告!prop 是只读的!
props.foo = 'bar'

The need to change a prop usually comes from two scenarios:

  1. prop is used to pass in the initial value; the child component wants to use it later as a local data property . In this case, it is best to define a new local data property and get the initial value from props:

    js
    const props = defineProps(['initialCounter'])
    
    // 计数器只是将 props.initialCounter 作为初始值
    // 像下面这样做就使 prop 和后续更新无关了
    const counter = ref(props.initialCounter)
    
  2. Further transformations are required on the passed in prop values . In this case, it is better to define a computed property based on the prop value:

    js
    const props = defineProps(['size'])
    
    // 该 prop 变更时计算属性也会自动更新
    const normalizedSize = computed(() => props.size.trim().toLowerCase())
    

Change props

When an object or array is passed in as props, although subcomponents cannot change the props binding, they can still change the value inside the object or array. This is because JavaScript objects and arrays are passed by reference. For Vue, such changes are prohibited. Although it may take effect, it will cause a large performance loss, which is not worth the candle.

The main drawback of this change is that it allows child components to affect the state of the parent component in some non-obvious way, possibly making the data flow more difficult to understand in the future. In best practice, you should avoid such changes as much as possible, unless the parent-child components are tightly coupled by design. In most scenarios, child components should throw an event to notify the parent component of changes.

Prop Validation

Vue components can declare validation requirements for incoming props in more detail. For example, the type declaration we have seen above, if the incoming value does not meet the type requirements, Vue will throw a warning in the browser console to remind the user. This is useful when developing components for use by other developers.

To declare validations for props, you can  defineProps() provide the macro with an object with props validation options, for example:

js

defineProps({
  // 基础类型检查
  // (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
  propA: Number,
  // 多种可能的类型
  propB: [String, Number],
  // 必传,且为 String 类型
  propC: {
    type: String,
    required: true
  },
  // Number 类型的默认值
  propD: {
    type: Number,
    default: 100
  },
  // 对象类型的默认值
  propE: {
    type: Object,
    // 对象或数组的默认值
    // 必须从一个工厂函数返回。
    // 该函数接收组件所接收到的原始 prop 作为参数。
    default(rawProps) {
      return { message: 'hello' }
    }
  },
  // 自定义类型校验函数
  propF: {
    validator(value) {
      // The value must match one of these strings
      return ['success', 'warning', 'danger'].includes(value)
    }
  },
  // 函数类型的默认值
  propG: {
    type: Function,
    // 不像对象或数组的默认,这不是一个
    // 工厂函数。这会是一个用来作为默认值的函数
    default() {
      return 'Default function'
    }
  }
})

TIP

defineProps() Parameters in the macro cannot access  <script setup> other variables defined in the macro, because the entire expression will be moved to the outer function at compile time.

Some additional details:

  • All props are optional by default unless declared otherwise  required: true.

  • Boolean Optional props that are not  undefined.

  • Boolean Unpassed props of type will be converted to  false. This can be changed by setting it  default - eg: set to  default: undefined will behave the same as props of non-boolean type.

  • If a value is declared  , it will be changed to  the value  when default the prop's value is resolved to  , regardless of whether the prop was not passed or explicitly specified  .undefinedundefineddefault

Vue throws a console warning (in development mode) when the prop validation fails.

If a type-based prop declaration is used  , Vue will do its best to compile according to the prop's type annotation at runtime. For example, defineProps<{ msg: string }> would be compiled as  { msg: { type: String, required: true }}.

Runtime type checking

Validation options  type can be the following native constructors:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol

In addition, type it can also be a custom class or constructor, and Vue will  instanceof check whether the type matches. For example the following class:

js

class Person {
  constructor(firstName, lastName) {
    this.firstName = firstName
    this.lastName = lastName
  }
}

You can use it as a prop type:

js

defineProps({
  author: Person
})

Vue will  instanceof Person check  author whether the value of the prop is  Person an instance of the class.

Boolean type conversion

In order to be closer to the behavior of native boolean attributes,  Boolean props declared as types have special type conversion rules. Take  <MyComponent> for example a component with the following declaration:

js

defineProps({
  disabled: Boolean
})

This component can be used like this:

template

<!-- 等同于传入 :disabled="true" -->
<MyComponent disabled />

<!-- 等同于传入 :disabled="false" -->
<MyComponent />

When a prop is declared to allow multiple types, for example:

js

defineProps({
  disabled: [Boolean, Number]
})

Boolean The special conversion rules for the types are applied regardless of the order in which the types are declared .

Guess you like

Origin blog.csdn.net/m0_74433188/article/details/130314647