Vue 中 组件以及Prop数据流向

  1. 对组件以及props的理解
    组件相当于定义一个函数,使用组件的(如父组件)相当于是调用函数,这时候如果需要传值的话,要从父组件传递;而props就是将父组件通过props 向下传递给子组件;子组件通过 events 给父组件发送消息。
    需要保证每个组件可以在相对隔离的环境中书写,这样能提高组件的可维护性。父组件向子组件传递数据分为两种方式:动态和静态;

  2. 组件使用:

//子组件代码如下:
// const data = { text: 123 }
 const component = {
    
    
  template: `
    <div>
      <span>This is component {
     
     {text}}</span>
      <input type="text" v-model.number="text" >
    </div>
    `,
  // data:{ text: 123 } 直接写data 写法错误
  // data () {
    
    
  //   return data 这样写会导致使用组件的所有data都一样
  // }
  data () {
    
    
    return {
    
    
      text: 123
    }
  }
}
//父组件
// Vue.component('CompOne', component) 使用组件的另一种方式
new Vue({
    
    
  components: {
    
    
    CompOne: component
  },
  el: '#root',
  template: `
    <div>
      <comp-one></comp-one>
      <comp-one></comp-one>
    </div>  
  `
})
  1. props的命名规范
    对于 props 声明的属性,在父组件的 template 模板中,属性名需要使用中划线写法;
    子组件 props 属性声明时,使用小驼峰或者中划线写法都可以;而子组件的模板使用从父组件传来的变量时,需要使用对应的小驼峰写法。Vue 能够正确识别出小驼峰和下划线命名法混用的变量。
  2. 静态props
    组件实例的作用域是孤立的,这意味着不能在子组件的模板中直接引用父组件的数据。要让子组件使用父组件的数据,需要通过子组件的 props 选项。
const component = {
    
    
  props: {
    
    
    propOne: String
  },
  template: `
    <div>
      <span>This is component {
     
     {text}}</span>
      <span>{
     
     {propOne}}</span>
    </div>
    `,
  data () {
    
    
    return {
    
    
      text: 123
    }
  }
}
new Vue({
    
    
  components: {
    
    
    CompOne: component
  },
  el: '#root',
  template: `
    <div>
      <comp-one prop-one="prop1"></comp-one>
      <comp-one prop-one="prop2"></comp-one>
    </div>  
  `
})

在这里插入图片描述

  1. 动态props

    在模板中,要动态地绑定父组件的数据到子组件模板的 props,和绑定 Html 标签特性一样,使用v-bind绑定;

const component = {
    
    
  props: {
    
    
    propOne: String,
    active: Boolean
  },
  template: `
    <div v-show="active">
      <span>This is component {
     
     {text}}</span>
      <span>{
     
     {propOne}}</span>
    </div>
    `,
  data () {
    
    
    return {
    
    
      text: 123
    }
  }
}
new Vue({
    
    
  components: {
    
    
    CompOne: component
  },
  el: '#root',
  template: `
    <div>
      <comp-one :prop-one="p1" :active="true"></comp-one>
      <comp-one :prop-one="p2" :active="false"></comp-one>
    </div>  
  `,
   data: {
    
    
    p1: "prop1",
    p2: "prop2"
  },
})

父组件的数据p1,p2,active 会传入子组件中

  1. props的验证

验证传入的 props 参数的数据规格,如果不符合数据规格,Vue 会发出警告。

Vue.component("example", {
    
    
 props: {
    
    
	 // 基础类型检测, null意味着任何类型都行
	 propA: Number,
	 // 多种类型
	 propB: [String, Number],
	 // 必传且是String
	 propC: {
    
    
	  type: String,
	  required: true
	 },
	 // 数字有默认值
	 propD: {
    
    
	  type: Number,
	  default: 101
	 },
	 // 数组、默认值是一个工厂函数返回对象
	 propE: {
    
    
	  type: Object,
	  default: function() {
    
    
	  console.log("propE default invoked.");
	  return {
    
     message: "I am from propE." };
	  }
	 },
	 // 自定义验证函数
	 propF: {
    
    
	  isValid: function(value) {
    
    
	  return value > 100;
	  }
	 }
	}
  })

还可以在 props 定义的数据中加入自定义验证函数,当函数返回 false 时,输出警告
能判断的所有种类(也就是 type 值)有:String, Number, Boolean, Function, Object, Array, Symbol

  1. props的数据流向–单向
    props 是单向绑定的:当父组件的属性变化时,将传给子组件,但是不会反过来。这是为了防止子组件错误修改父组件的状态。
    所以不应该在子组件中修改 props 中的值,Vue 会报出警告。
 let childNode = {
    
    
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{
     
     {forChildMsg}}</p>
   </div>`,
  props: {
    
    
   "for-child-msg": String
 }
};
let parentNode = {
    
    
 template: `
   <div class="parent">
   <div>
    <span>父组件数据</span>
    <input v-model="msg"/>
   </div>
   <p>{
     
     {msg}}</p>
   <child :for-child-msg="msg"></child>
   </div>
  `,
 components: {
    
    
  child: childNode
 },
 data() {
    
    
   return {
    
    
     msg: "default string."
   };
 }
};

这里我们给父组件和子组件都有一个输入框,并且显示出父组件数据和子组件的数据。当我们在父组件的输入框输入新数据时,同步的子组件数据也被修改了;这就是 props 的向子组件传递数据。而当我们修改子组件的输入框时,浏览器的控制台则报出错误警告
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “forChildMsg”
8. 修改props的数据
通常有两种原因:

prop 作为初始值传入后,子组件想把它当做局部数据来用
prop 作为初始值传入后,由子组件处理成其他数据输出

应对办法是

定义一个局部变量,并用 prop 的值初始化它
但是由于定义的 ownChildMsg 只能接受 forChildMsg 的初始值,当父组件要传递的值变化发生时,ownChildMsg 无法收到更新。

let childNode = {
    
    
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{
     
     {forChildMsg}}</p>
   <p>ownChildMsg : {
     
     {ownChildMsg}}</p>
   </div>`,
 props: {
    
    
   "for-child-msg": String
 },
 data() {
    
    
   return {
    
     ownChildMsg: this.forChildMsg };
 }
};

这里我们加了一个p标签用于查看 ownChildMsg 数据是否变化,结果发现只有默认值传递给了 ownChildMsg,父组件改变只会变化到 forChildMsg,不会修改 ownChildMsg。

定义一个计算属性,处理 prop 的值并返回
由于是计算属性,所以只能显示值,不能设置值。我们这里设置的是一旦从父组件修改了 forChildMsg 数据,我们就把 forChildMsg 加上一个字符串"—ownChildMsg",然后显示在屏幕上。这时是可以每当父组件修改了新数据,都会更新 ownChildMsg 数据的。

let childNode = {
    
    
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{
     
     {forChildMsg}}</p>
   <p>ownChildMsg : {
     
     {ownChildMsg}}</p>
   </div>`,
 props: {
    
    
   "for-child-msg": String
 },
 computed: {
    
    
   ownChildMsg() {
    
    
     return this.forChildMsg + "---ownChildMsg";
 }
 }
};

更加妥帖的方式是使用变量存储 prop 的初始值,并用 watch 来观察 prop 值得变化。发生变化时,更新变量的值。

let childNode = {
    
    
 template: `
   <div class="child">
   <div>
    <span>子组件数据</span>
    <input v-model="forChildMsg"/>
   </div>
   <p>{
     
     {forChildMsg}}</p>
   <p>ownChildMsg : {
     
     {ownChildMsg}}</p>
   </div>`,
 props: {
    
    
   "for-child-msg": String
 },
 data() {
    
    
   return {
    
    
     ownChildMsg: this.forChildMsg
   };
 },
 watch: {
    
    
   forChildMsg() {
    
    
     this.ownChildMsg = this.forChildMsg;
   }
 }
};

猜你喜欢

转载自blog.csdn.net/weixin_39854011/article/details/106209421