2020-10-10

Vue 里面父子间的通信


一、父组件向子组件 传参

在 vue 里面,父组件可以向子组件 传递参数,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓

Pass props

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    a {
      text-decoration: none;
    }
  </style>

</head>

<body>
  <div id="app">
    <cpn :memove="move" :memessage="message"></cpn>
  </div>


  <template id="cpn">
    <div>
      <p>{{memove}}</p>
      <h2>{{memessage}}</h2>
    </div>
  </template>

  <script src="../vue.js"></script>
  <script>
    /* 
 父子间的关系说明:
    1) 父组件 通过 props 向子组件传递数据   传参   Pass props
  */

    // 创建组件构造器
    const cpn = {
      template: '#cpn',
      // 语法: props: ['父组件传递的自定义属性名(str)'],
      // props: ['memove', 'memessage'],
      props: {
        // 1. 类型限制
        // memove: Array, // 要求 memove 需是一个 数组
        // memessage: String, // 要求 memessage 需是一个 字符串

        // 2. 提供默认值  注意默认值,不是你 父组件没有这个值,而是你子组件,没有接受这个值,也就是,子组件只接受了 memove 这个数据
        memessage: {
          type: String,
          default: '我是你爸爸',
          required: true, // 表示 memessage 是一个必须传递的参数(数据),也就是你子组件,需要传递(接受)过来,不传,就报错
        },
        memove: {
          type: Array,
          // 当类型为 数组 或者 对象的时候,默认值必须是一个函数
          default () {
            return []
          }
        }
      },
    }

    // 需求:vue 实例作为 父组件,先子组件 传递数据
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀',
        move: ['海王', '海尔兄弟', '星际跳跃', '八佰']
      },
      components: {
        cpn
      }
    });

    /* 
    父向子传参说明:
       1) 父组件将数据传递给子组件
       2) 子组件设置 动态属性,来接收父组件传递过来的数据  <cpn :memove="move" :memessage="message"></cpn>
       3) 在 子组件 模板里面,使用动态接收过来的变量,也就是 父组件传递过来的参数
       4) props 不仅仅支持数组,还可以使用 对象,当需要对传入的参数进行验证的时候,也就是对 props进行类型验证的时候,就需要使用 对象的写法了
          验证支持的数据类型:
          String
          Number
          Boolean
          Array
          Object
          Date
          Function
          Symbol
       5) props 中接收到的数据,最终会挂载到 实例上(作为实例上的属性),data中的数据,methods中的方法,computed中的计算属性,都会
          编译成 实例上的属性和方法,所以注意不要同名
    */
  </script>
</body>

</html>

父向子传参总结:

  1. 通过給 子组件设置 propsprops里面写的是 自定义属性名称,props 里面可以 限制参数类型 或者 提供参数默认值
  2. 在 子组件 上使用 v-bind:props里面自定义属性名=‘父组件传递的参数’,来实现,父组件向子组件传递参数
  3. 大致流程:
    (1) 在 子组件上 使用 props 自定义属性,用于接收 父组件 传递过来的参数 。
    (2)props 里面可以限制 (验证) 接收父组件传递过来 参数的 类型,以及 是否必须传递这个参数、参数默认值,但是需要注意 当参数类型为数组 或者对象 的时候,默认值必须是一个 函数
    (3) 在 父组件 上 使用 v-bind 绑定 自定义属性,以及父组件要传递的参数,如: v-bind:memsg=“msg” 这 memsg 就是在 子组件 props 里面 自定义的属性名称
    (4)然后你就可以 在子组件 上愉快的 使用 父组件传递过来的参数了

二、子组件向父组件通信

在 vue 里面,子组件可以向父组件 通信,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓

$emit Events

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    a {
      text-decoration: none;
    }

    #app {
      width: 500px;
      height: 200px;
      border: 1px solid black;
      margin: 150px auto;
    }
  </style>

</head>

<body>
  <!-- 父组件 -->
  <div id="app">
    <cpn @itemclick="cpnClick"></cpn>
  </div>


  <!-- 子组件 -->
  <template id="cpn">
    <div>
      <button v-for="item in classifys" @click="btnClick(item)">{{item.name}}</button>
    </div>
  </template>

  <script src="../vue.js"></script>
  <script>
    // 1. 子组件
    const cpn = {
      template: '#cpn',
      props: {
        // 数据限制,以及提供默认值
        carr: {
          type: Object,
          default () {
            return {}
          }
        }
      },
      data() {
        return {
          classifys: [{
              id: 1,
              name: '手机数码'
            },
            {
              id: 2,
              name: '家用家电'
            },
            {
              id: 3,
              name: '电脑办公'
            },
            {
              id: 4,
              name: '精品男装'
            },
          ]
        }
      },
      methods: {
        btnClick(item) {
          // console.log(data); // 点击哪一个,就打印那一条数据
          // 通过 自定义事件,发射信号给 父组件
          // 语法: this.$emit('自定义事件名称',发射过去的参数)
          this.$emit('itemclick', item);
        }
      },
    }

    // 2. 父组件
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀',
      },
      components: {
        cpn
      },
      methods: {
        cpnClick(data) {
          alert(data.name)
        }
      }
    });
    /* 
    子组件向父组件通信说明:
       1) 子组件不会处理复杂的 数据操作,会将复杂的数据操作 交予 父组件操作
       2) 子组件,通过用户触发了某个时间,以及触发哪个事件,将其返回给 父组件,让父组件处理(甩锅侠)
       3) 例如:用户点击了 '精品男装',那么 子组件,将 点击了 '精品男装' 这个 信息,传递给 父组件,让父组件处理复杂数据,然后渲染页面到 '精品男装'
       4) 组件里面没有 事件对象,在 cpnClick 函数里,html中对中函数没有 传递参数,若是在别的地方,则会将 事件对象,当参数传递给 data,但是这里 是将
          item 传递给 data,也就是,这里 是之前的 参数问题之事件对象的 特例,html里面不写参数的时候,传递的是 子组件发射过来的参数(数据)
    */
  </script>
</body>

</html>

子向父通信总结:

  1. 通过給 子组件设置 一个方法,方法内 发射一个 自定义事件和参数,如 :this.$emit(‘自定义事件’,参数)
  2. 在 父组件 上使用 v-on:自定义事件=“父组件处理传递过来的信息方法”
  3. 大致流程:
    (1) 在 子组件上 定义一个方法,方法内发射一个 自定义事件,和参数 到父组件上,如: this.$emit(‘aaa’,10) 这里 aaa 就是自定义属性名称,10就是参数
    (2)在 父组件 上面,使用 v-on 来接收 子组件 发射过来的 信息,如: v-on:aaa=“父组件处理信息的方法”
    (3) 在 父组件处理信息的方法 上,需要注意的是 ,一般我们在 某个方法上 需要使用一个参数,可是 调用的时候,没有传递的时候,vue里面会将触发该事件的 事件对象,传递过来,给 这个方法使用,但是在 vue组件里面,没有 事件对象一说法的,他会将 发射过来的参数,当做默认参数,传递过来,这就是为什么上述代码里面 我没有给 cpnClick 传递参数的原因
    (4)然后你就可以 在父组件 上愉快的 处理 子组件传递过来的信息了

三、兄弟组件间的通信

在 vue 里面,兄弟组件之间也是可以 通信的,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓

eventBus 事件中心总线

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    a {
      text-decoration: none;
    }
  </style>

</head>

<body>
  <div id="app">
    <cpn1></cpn1>
    <hr>
    <cpn2></cpn2>
  </div>

  <template id="c1">
    <div>
      <h2>{{mesaage}}</h2> <br>
      <button @click="btnClick">点击,向老二传递数据</button>
    </div>
  </template>

  <template id="c2">
    <div>
      <h2>{{mesaage}}</h2>
      <h1>{{hint}}</h1>
    </div>
  </template>

  <script src="../vue.js"></script>
  <script>
    // 3. 创建 事件中心总线 eventBus
    const bus = new Vue();

    // 1. 老大组件
    const cpn1 = {
      template: '#c1',
      data() {
        return {
          mesaage: '我是老大'
        }
      },
      methods: {
        btnClick() {
          bus.$emit('aaa', this.mesaage)
        }
      },
    }
    // 2. 老二组件
    const cpn2 = {
      template: '#c2',
      data() {
        return {
          mesaage: '我是老二',
          hint: ''
        }
      },
      mounted() {
        bus.$on('aaa', (data) => {
          this.hint = data;
        })
      }
    }

    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀'
      },
      components: {
        cpn1,
        cpn2
      }
    });

    /* 
    兄弟间通信说明:
       1) 利用第三方 实例,来实现 兄弟之间的通信
       2) 在 子组件向父组件通信的时候,是子组件 定义一个自定义事件,并通过 this.$emit 发射出信息,而父组件会接受这个信息 @自定义事件="父组件处理事件"
       3) 兄弟间组件通信,仿照子组件向父组件通信,原则上是:谁发射这个信息,就通过谁来 用 $on 来接收这个数据。只不过,这里使用第三方 实例来 发射和接收
       4) 就相当于,原生里面 有的时候,this 不可以使用,就 that=this,一个道理,原先的 子 向 父通信,是利用 this 发射的,也就是子组件自己发射的,但是在
       兄弟里面,无法在 兄弟2 里面使用 兄弟1的this,所以使用 第三方实例(事件中心总线) 来做
    */
  </script>
</body>

</html>

兄弟组件通信总结:

  1. 兄弟组件间的通信,类似于 子先父通信,但是在兄弟组件里面,无法直接发射信息到 对应兄弟组件上,这就的使用 一个第三方平台了 -------- eventBus 事件中心总线
  2. 原理就是 利用 这个 eventBus 发射信息,再去要接收这个信息的兄弟组件上用 eventBus 接收一下,就好了
  3. 大致流程
    (1) 创建 事件中心总线 eventBus 实例 bus
    (2) 用 bus.$emit(‘自定义事件’,参数) 发送要发送的信息
    (3) 用 bus.$on(‘自定义事件’,回调函数) 来接收 发送过来的数据

四、父组件访问子组件

在 vue 里面,父组件可以访问子组件上的内容,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓

方法一:$children 不建议使用

方法二:$refs

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    a {
      text-decoration: none;
    }
  </style>

</head>

<body>
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn></cpn>
    <cpn2 ref="aaa"></cpn2>
    <cpn></cpn>
    <button @click="btnClick()">点击切换内容</button>
  </div>

  <template id="cpn">
    <div>
      <h2>我是子组件1</h2>
      <h2>{{msg}}</h2>
    </div>
  </template>

  <template id="cpn2">
    <div>
      <h2>我是子组件2</h2>
      <h2>{{msg}}</h2>
    </div>
  </template>

  <script src="../vue.js"></script>
  <script>
    /* 
    父组件 访问 子组件说明:
      1) 父组件 使用 $children 访问子组件, $children 打印出来的是一个数组,若是有多个子组件,就是利用
         索引号,去拿到 所需要的的数据,如:this.$children[5].msg,但是一旦牵涉到索引号,就危险了,可能后期
         我在 第5个组件前初入另一个组件,那么索引号就改了,牵一发而动全身,下面获取 $children 的索引号也得改,所以
         不建议使用 这种方式获取 子组件的 内容
      2) 父组件 使用 $refs 访问子组件 在 子组件 上设置 ref='xxx',而后再获取的时候 this.$refs.xxx 就可以获取到 定义
         ref='xxx' 那条数据里面的内容
      3) 所谓的 访问,就是父组件,使用子组件上面的 方法、数据、计算属性等等
      4)
    */


    const cpn = {
      template: '#cpn',
      data() {
        return {
          msg: '我是你爸爸1'
        }
      },
      methods: {
        log() {
          console.log('这是子组件打印的内容');
        }
      },
    }

    const cpn2 = {
      template: '#cpn',
      data() {
        return {
          msg: '我是你爸爸2'
        }
      },
      methods: {
        log() {
          console.log('这是子组件2打印的内容');
        }
      },
    }

    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀'
      },
      components: {
        cpn,
        cpn2
      },
      methods: {
        btnClick() {
          // 1. 方法一
          // console.log(this.$children); // [VueComponent] 打印的是 子组件上所有东西,是一个数组,比如要使用 子组件的 msg 就是 this.$children[0].msg
          // console.log(this.$children[3].msg); // 我是你爸爸2

          // 1. 方法二
          // console.log(this.$refs.aaa); // aaa 上的内容
          this.$refs.aaa.log(); // 调用 aaa 子组件上面的 log 方法

        }
      },
    });
  </script>
</body>

</html>

父组件访问子组件总结:

  1. 使用 $children[index] 方法获得子组件上的内容,但是 不建议使用,以为涉及到了索引号,即在使用多个组件的时候,删除某一个组件,或者添加一个组件,都会改变索引号,不利于代码的维护
  2. 使用 $refs方法,在组件上设置, ref=‘aaa’,在父组件上 用 $refs.aaa 获得该组件上的内容,建议使用

五、子组件访问父组件/根组件

在 vue 里面,子组件也可以访问父组件上的内容,那么怎么实现 这一操作呢?欲知答案如何,请看如下代码分晓

访问父组件:$parent

访问根组件:$root

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    li {
      list-style: none;
    }

    a {
      text-decoration: none;
    }
  </style>

</head>

<body>
  <!--  父组件 -->
  <div id="app">
    <cpn>
    </cpn>
  </div>

  <!-- 子组件 -->
  <template id="cpn">
    <div>
      <h2>我是子组件</h2>
      <h2>{{msg}}</h2>
      <hr>
      <ccpn></ccpn>
    </div>


  </template>

  <!-- 子子组件 -->
  <template id="ccpn">
    <div>
      <h2>我是子子组件</h2>
      <h2>{{msg}}</h2>
      <button @click="btnClick()">点击切换内容</button>
    </div>
  </template>

  <script src="../vue.js"></script>
  <script>
    /* 
  子组件 访问 父组件说明:
      1) 子组件使用 $parent 访问 父组件上的 所有内容
      2) 注意 子组件访问 父组件上面的内容,不可以跨级访问,只能由 儿子,访问 父亲,不可以儿子访问 爷爷
      3) 实际开发过程中,不建议使用 子组件访问 父组件上的内容,因为,我们需要做到 子组件复用,打个比方说:
         你讲 子组件1 放到 父组件a里面,并且使用了 父组件a 里面的数据,但是你讲 子组件1,放到 父组件b里面,
         b 里面可是没有 a 里面的数据,你再获取不到 a 里面的数据了,不能有奶就是娘,这样耦合性太强,不利于模块间开发
      4) $root 访问的是 根组件,也就是 vue 实例
    */


    // 1. 孙子级别 组件
    const ccpn = {
      template: '#ccpn',
      data() {
        return {
          msg: '我是 vue 的孙子'
        }
      },
      methods: {
        btnClick() {
          // console.log(this.$parent.msg); // 打印的是 '我是 vue 的儿子'  只可以访问到父组件,访问不到 根组件
          console.log(this.$root.message); // 打印的是 '你好呀'  直接 访问到 根组件
        },
      }
    }

    // 2. 儿子级别 组件
    const cpn = {
      template: '#cpn',
      data() {
        return {
          msg: '我是 vue 的儿子'
        }
      },
      methods: {
        log() {
          console.log('子子');
        },
      },
      components: {
        ccpn
      }
    }


    // 3. 根组件
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好呀'
      },
      components: {
        cpn,
      },
      methods: {
        log() {
          console.log('这是父组件打印的内容');
        }
      },
    });
  </script>
</body>

</html>

子组件访问父组件/根组件总结:

  1. 使用 $parent 可以访问到 父组件上的内容,注意的是,它只可以访问到 父组件,不可以访问到父组件之外的组件
  2. 使用 $root,可以访问到 根组件上的内容,也就是 vue 实例上的内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值