浅谈Vue2选项--props

750 阅读3分钟

props概念

  • props 是自定义属性,合理使用 props 可以极大的提高组件的复用性
  • 作用: 接收来自父组件的数据
  • 本质: 数组(Array)|对象(Object)
  • 扩展: 对象形式允许配置高级选项,如类型检测自定义验证设置默认值

简单接收

 <!-- App.vue -->
 <Child codeFontEnd="codeFontEnd" codeBackEnd="codeBackEnd" />
 // Child.vue
 export default {
   props:['codeFontEnd','codeBackEnd']
 }
  • 在子组件的模板中就可以直接使用
 <!-- Child.vue -->
 <h1> 前端:{{codeFontEnd}}</h1>
 <h1> 后端:{{codeBackEnd}}</h1>

1667721802862.png

配置选项

  • 写成对象形式的 props,可以为每个 prop 指定值的类型
  • 传递错误的类型时,浏览器控制台会警告用户
 props: {
   title: String, // 指定类型为字符串
   likes: Number, // 指定类型为数字
   isPublished: Boolean, // 指定类型为布尔值
   commentIds: Array, // 指定类型为数组
   author: Object, // 指定类型为对象
   callback: Function, // 指定类型为函数
   contactsPromise: Promise // 指定类型为Promise
 }
  • 单个 prop 也可以写成对象形式,主要有以下配置项

    • type: 定义prop的类型可以是原生构造函数:如StringNumberBooleanArray 等、或是自定义构造函数、或上述内容组成的数组
    • default: 为该 prop 指定一个默认值,如果该 prop 没有被传入,则使用默认值
    • required: 定义该 prop 是否是必填项
    • validator: 自定义验证函数,会将该 prop 的值作为唯一的参数代入

注意:对象或数组的默认值必须从一个工厂函数返回

 // 数组
 props:{
   type:Array
   default:() => [] // 数组的默认值
 }
 ​
 // 对象
 props:{
   type:Object
   default:() => ({}) // 对象的默认值
 }
  • 示例:Child 组件中配置 props 选项,性别和姓名必须传进,年龄默认值为19,且必须为数字
 props:{
   name:{
     type:String, // name的类型是字符串
     required:true // name是必要的
   },
   sex:{
     type:String,
     required:true
   },
   age:{
     type:Number,
     default:19, // 默认值是19
     validator(age){
       return typeof age === 'number' && !Number.isNaN(age)
     }
   }
 }

注意: prop 会在组件实例创建之前进行验证,所以组件的options (如 datacomputed 等) 在 defaultvalidator 函数中是无法访问的

  • 在App组件中不传姓名和年龄,控制台会报出警告,而年龄用默认值代替

1667723244105.png

如何接收多类型?

  • type 选项可以为数组,数组中指定可以接收的类型
 props: {
   author: { type: ['Array','Object']}
 }

动态传递

  • 可以通过 v-bind 动态赋值
  • v-bind 修饰的不再是字符串,而是 JavaScript 表达式

①传入一个数字

 <Child :age="18"/>

②传入一个布尔值

 <Child :isShow="true" />
 ​
 <!-- prop没有值的情况都为true -->
 <Child isShow />

③传入一个数组

 <Child :userIdList="[234, 266, 273]" />

④传入一个对象

 <Child :userIdList="{ fontEnd:'JavaScript' }" />

⑤传入一个对象的所有属性

 <Child v-bind="user" />
 data(){
   return { 
     user: {
       name: '张三',
       age: 18
     }
   }
 }
  • 等价于下面写法
 <Child :name="user.name" :age="post.age" />

单向数据流

  • props传递的数据只能在父级更新,向下流动到子组件中,反之则会发出警告
  • 防止从子组件意外变更父级组件的状态,从而导致数据流向难以理解
  • 在子组件Child中接收父组件的数据,并尝试修改
 <h1> 姓名:{{ name }}</h1>
 <button @click="name='ls'">修改姓名</button>
 export default {
   name:'Child',
   props:['name']
 }
  • 浏览器控制台发出警告

1667726135599.png

如何更改父组件传递的数据呢?

①把 props 的值转存到 data,因为 data 中的数据可读可写

 props: ['name'],
 data() {
   return {
     userName: this.name
   }
 }

②使用计算属性进行转换

 props: ['size'],
 computed: {
   newSize() {
     return this.size.trim().toLowerCase()
   }
 }

③传入引用类型数据,对其中的属性作出更改

 props: {
   user:{
     type: Object,
     default: ()=>({})
   }
 }

注意: 对象和数组是通过引用传入的,在子组件中改变这个对象或数组本身将会影响到父组件的状态


④在传递时使用 .sync 修饰符,打破数据单向流

 <Child :name.sync="name" />
  • 在子组件通过 update 事件进行更改
 this.$emit('update:name','ls')