2-2-vue框架-组件-vue-component组件化开发-组件的传值(父传子)

背景

如果我们正在构建一个博客,我们可能需要一个表示博客文章的组件。我们希望所有的博客文章分享相同的视觉布局,但有不同的内容。要实现这样的效果自然必须向组件中传递数据,例如每篇文章标题和内容,这就会使用到 props。

定义一个含props的组件

Props 是一种特别的 attributes,你可以在组件上声明注册。要传递给博客文章组件一个标题,我们必须在组件的 props 列表上声明它。这里要用到 props 选项

<!-- BlogPost.vue -->
<template>
  <h4>{{ title }}</h4>
</template>

<script>
export default {
  props: ['title']
}
</script>
  • 所以props必须要在组件中声明,这样 Vue 才能知道外部传入的哪些是 props,
  • 当一个值被传递给 prop 时,它将成为该组件实例上的一个属性。该属性的值可以像其他组件属性一样,在模板和组件的 this 上下文中访问。
    -一个组件可以有任意多的 props,默认情况下,所有 prop 都接受任意类型的值。

除了使用字符串数组来声明 prop 外,还可以使用对象的形式:

export default {
  props: {
    title: String,
    likes: Number
  }
}
  • 对于以对象形式声明中的每个属性,key 是 prop 的名称,而值则是该 prop 预期类型的构造函数。比如,如果要求一个 prop 的值是 number 类型,则可使用 Number 构造函数作为其声明的值。

  • 对象形式的 props 声明不仅可以一定程度上作为组件的文档,而且如果其他开发者在使用你的组件时传递了错误的类型,也会在浏览器控制台中抛出警告。

使用一个props的组件

静态传props


<template>
<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
</template>

<script>
  import BlogPost from "./components/demo1.vue"

  export default {
    components:{
      BlogPost
      },
  }

</script>

动态传props

在实际应用中,更可能是这样写

<template>
<BlogPost
  v-for="post in posts"
  :key="post.id"
  :title="post.title"
 />
</template>

<script>
  import BlogPost from "./components/demo1.vue"

  export default {
    components:{
      BlogPost
      },
   data() {
    return {
      posts: [
        { id: 1, title: 'My journey with Vue' },
        { id: 2, title: 'Blogging with Vue' },
        { id: 3, title: 'Why Vue is so fun' }
      ]
    }
  }
  }

</script>
  • 留意我们是如何使用 v-bind 来传递动态 prop 值的。当事先不知道要渲染的确切内容时,这一点特别有用。
  • 传入的值可以是任意类型,比如数字,字符串,列表,对象,都可以,

单向数据流

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

不允许子组件修改prop,会报异常

另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。
若你这么做了,Vue 会在控制台上向你抛出警告

情况1:prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性

新定义一个局部数据属性,从 props 上获取初始值即可

情况2:需要对传入的 prop 值做进一步的转换。

在这种情况中,最好是基于该 prop 值定义一个计算属性

更改对象 / 数组类型的 props​

  • 可以改
    子组件可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,

  • 但是禁止改
    而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。

危害:会让代码变得混乱,而且难以理解

  • 缺陷是它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解。在最佳实践中,你应该尽可能避免这样的更改,除非父子组件在设计上本来就需要紧密耦合。在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变。

组件内对Prop 校验​

如果在组件内,我想要让这个属性必传,或者对属性进行校验怎么办?

要声明对 props 的校验,你可以向 props 选项提供一个带有 props 校验选项的对象,例如:

export default {
  props: {
    // 基础类型检查
    //(给出 `null` 和 `undefined` 值则会跳过任何类型检查)
    propA: Number,
    // 多种可能的类型
    propB: [String, Number],
    // 必传,且为 String 类型
    propC: {
      type: String,
      required: true
    },
    // Number 类型的默认值
    propD: {
      type: Number,
      default: 100
    },
    // 对象类型的默认值
    propE: {
      type: Object,
      // 对象或者数组应当用工厂函数返回。
      // 工厂函数会收到组件所接收的原始 props
      // 作为参数
      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'
      }
    }
  }
}

一些补充细节:

  • 可以使用列表,让属性支持传递多种数据类型,
  • 所有 prop 默认都是可选的,除非声明了 required: true。
  • 除 Boolean 外的未传递的可选 prop 将会有一个默认值 undefined。
  • Boolean 类型的未传递 prop 将被转换为 false。这可以通过为它设置 default 来更改——例如:设置为 default: undefined 将与非布尔类型的 prop 的行为保持一致。
  • 如果声明了 default 值,那么在 prop 的值被解析为 undefined 时,无论 prop 是未被传递还是显式指明的 undefined,都会改为 default 值。

当 prop 的校验失败后,Vue 会抛出一个控制台警告

这是类型的种类:

String
Number
Boolean
Array
Object
Date
Function
Symbol
posted @ 2021-07-29 12:56  技术改变命运Andy  阅读(145)  评论(0编辑  收藏  举报