vue组件之间的通信方式(二)

data 和props

  • props常用于数据传递,子组件中不可以直接修改,这也是vue 单向数据流的特性
  • data在任何情况下改变,都能同步反应的view层

怎么在子组件中改动props传递过来的数据呢?

    1. 利用data的动态性,将props数据存在data中,通过修改data数据更新视图
props: ['msg'],
data() {
  return { 
    myMsg: this.msg 
  }
}
    1. 将props转存到计算属性computed中
props:['msg']
computed : {
   myMsg () {
       return this.msg;
   }
}

不过因为对象和数组是引用类型,指向同一个内存空间,所以不要通过computed来对父组件传递来的引用类型数据进行计算过滤,改变数据会影响到父组件的状态。

$emit、$on 和 v-on

子组件更新父组件数据

  • $on(eventName, callback) 监听事件, 第二个参数是回调函数,回调函数的参数为$emit传递的数据内容
  • $emit(eventName, [...arg]) 触发事件, 第二个参数会传递给on监听器的回调函数
  • v-on则是使用在父组件标签中的,可以对其子组件的$emit监听

.sync 双向绑定

v-model也是用于双向绑定的,上一节已经讲到。

  • .sync的功能是:子组件改变了 prop,会同步到父组件中所绑定。
  • 使用方式: <comp :foo.sync="bar"></comp>; 相当于:<comp :foo="bar" @update:foo="val => bar = val"></comp>
  • 当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
    this.$emit('update:foo', newValue)

举个栗子:

  • 父组件代码
<template>
 <div>
   <certificate-input :p_model.sync='pname'>
   </certificate-input>
</div>
</template>
import CertificateInput from '../common/CertificateInput.vue'
export default {
    name: 'fathor',
    components: {
        CertificateInput 
    },
    data() {
      return {
            pname:""
    }     
}
  • 子组件代码
<template>
    <div>
      <input
            title="姓名"  
            v-model="name" 
            ></input>
      <span>{{address}}</span>
    </div>
</template>
<script>
    export default{
        name:'certificateInput',
        props:["p_model"],

        data(){
            return{
                name:this.p_model,
                address: ""
            }
        },
        watch:{
            p_model(val) { 
                this.address = val;
            },
            name(val){
                //设置监听,如果改变就更新 p_model
                this.$emit('update:p_model', val)
            }
        }
    }
</script>

其它栗子:

<!--常见的如饿了么组件中的:current-page.sync-->
<el-pagination 
layout="prev, pager, next" 
:total="meta.total" 
@current-change="load" 
:current-page.sync="meta.current_page" 
background>
</el-pagination>
    
<!--js部分:-->
props: {
    meta: {
      type: Object,
      required: true,
    },
  },

再如,饿了么组件Dialog:

<el-dialog
  title="提示"
  :visible.sync="dialogVisible"
  width="30%"
  :before-close="handleClose">
  <span>这是一段信息</span>
  <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
  </span>
</el-dialog>

与通过自定义事件(emit)从子组件向父组件中传递数据的区别?

  1. 在我们讲解sync的这一小节里, 自定义事件发生时候运行的响应表达式是:
    <son :foo="bar" v-on:update="val => bar = val"></son> 中的 "val => bar = val"
  2. 在二中的“通过自定义事件从子组件向父组件中传递数据” 里,自定义事件发生时候运行的响应表达式是:
    <Son v-on: eventYouDefined = "arg => functionYours(arg)" /> 中的 "arg => functionYours(arg)"

对前者,表达式 val => bar = val意味着强制让父组件的数据等于子组件传递过来的数据, 这个时候,我们发现父子组件的地位是平等的。 父可以改变子(数据), 子也可以改变父(数据)

对后者,你的functionYours是在父组件中定义的, 在这个函数里, 你可以对从子组件接受来的arg数据做任意的操作或处理, 决定权完全落在父组件中, 也就是: 父可以改变子(数据), 但子不能直接改变父(数据)!, 父中数据的变动只能由它自己决定