vue的学习笔记(6)之组件化开发中

1、父子组件的通信

在前面的学习中,我们提到了子组件是不能引用父组件或者Vue实例的数据的。但是,在开发中,往往一些数据确实需要从上层传递到下层:
比如在一个页面中,我们从服务器请求到了很多的数据。其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示。这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。

那么如何进行父子组件间的通信呢?其实是通过以下两种方法实现的:

  • 通过props向子组件传递数据
  • 通过事件向父组件发送消息
    在这里插入图片描述

2、父级向子级传送

(1) props的基本用法

在组件中,是通过选项props来声明需要从父级接收到的数据。

props的值有两种方式:

  • 方式一:字符串数组,数组中的字符串就是传递时的名称。
  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等。

我们先来看一个最简单的props传递:

<div id="app">
  <cpn v-bind:cmovies="movies"></cpn>
  //cpn里面的v-bind是绑定父传子的信息,cmovies为子组件中props需要接受
  //父组件数据的名称,而movies则是父组件data中要传送的数据的一个属性。
  <hr>
  <cpn cmovies="movies" cmessage="message"></cpn>
  <hr>
  <cpn :cmessage="message" :cmovies="movies"></cpn>
</div>



<template id="cpn">
  <div>
    <ul>
      <li v-for="item in cmovies">{{item}}</li>
    </ul>
    <h2>{{cmessage}}</h2>
  </div>
</template>

<script src="../js/vue.min.js"></script>
<script>
  // 父传子: props
  const cpn = {
    template: '#cpn',
    // props: ['cmovies', 'cmessage'],
    props: {
      // 1.类型限制
      // cmovies: Array,
      // cmessage: String,

      // 2.提供一些默认值, 以及必传值
      cmessage: {
        type: String,
        default: 'aaaaaaaa',
        required: true
      },
      // 类型是对象或者数组时, 默认值必须是一个函数
      cmovies: {
        type: Array,
        default() {
          return []
        }
      }
    },
    data() {
      return {}
    },
    methods: {

    }
  }

  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊vue',
      movies: ['美国队长', '复仇者联盟', '雷神']
    },
    components: {
      cpn
    }
  })
</script>

在这里插入图片描述根据结果我们可以看到,若没有使用v-bind(div中的第二个cpn),我们可以看到,他是直接将movie,message当成字符串来处理的。

(2) props的数据验证

在前面的案例中,我们的props选项使用的是一个数组。其实,除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要使用对象的写法了。

那么类型验证都支持哪些数据类型呢?有如下几种数据类型:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
    在这里插入图片描述
    当我们有自定义构造函数时,类型验证同样也支持自定义的类型(如下图所示):

在这里插入图片描述

3、子级向父级传送

在前面的学习中,我们知道props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中。

(1)子级向父级传送数据应该如何处理呢?
答:这里是通过自定义事件来完成的。

(2)什么时候需要自定义事件呢?

  • 当子组件需要向父组件传递数据时,就要用到自定义事件了。
  • 我们之前学习的v-on不仅仅可以用于监听DOM事件,也可以用于组件间的自定义事件。

(3)自定义事件的流程:

  • 在子组件中,通过$emit()来触发事件。
  • 在父组件中,通过v-on来监听子组件事件。

来看一个简单的例子:
之前做过一个两个按钮+1和-1,点击后修改counter的计数案例。现在需求变为:在整个操作的过程还是在子组件中完成,但是之后的展示交给父组件。这样,就需要将子组件中的counter,传给父组件的某个属性,比如total。
在这里插入图片描述

4、父子组件的访问

(1) 父子组件的访问方式: $children

有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件(vue实例中绑定子组件,该vue实例是父组件的同时,也是根组件)。

父子组件之间的访问方式:
父组件访问子组件:使用$children或$refs(refs是reference的缩写,是访问的意思。)
子组件访问父组件:使用$parent
我们先来看下$children的访问
this.$children是一个数组类型,它包含所有子组件对象。
我们这里通过一个遍历,取出所有子组件的message状态。

在这里插入图片描述

(2) 父子组件的访问方式: $refs

$children的缺陷:
通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
但是当子组件过多时,或者需要中间插入一些其他组件时。这时我们需要拿到其中一个时,往往就不能确定它的索引值是什么(索引值可能会发生变化)。

有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs.

$refs的使用:
$refs和ref指令通常是一起使用的。
首先,我们通过ref给某一个子组件绑定一个特定的ID。
其次,通过this.$refs.ID就可以访问到该组件了。

在这里插入图片描述
在这里插入图片描述
this.$refs.child1.属性:可以获取到对应的属性的值(比如上图中的message)

(3) 父子组件的访问方式: $parent

如果我们想在子组件中直接访问父组件,可以通过$parent

注意事项:
(1) 尽管在Vue开发中,我们允许通过$parent来访问父组件,但是在真实开发中尽量不要这样做。
(2) 子组件应该尽量避免直接访问父组件的数据,因为这样耦合度太高了。
(3) 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
(4) 另外,更不好做的是通过$parent直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于我的调试和维护。

在这里插入图片描述
上代码:

<div id="app">
  <cpn></cpn>
</div>
<!--组件里面使用子组件,这里必须加根标签-->
<template id="cpn">
  <div>
    <h2>我是cpn组件</h2>
    <ccpn></ccpn>
  </div>
</template>

<template id="ccpn">
  <div>
    <h2>我是子组件</h2>
    <button @click="btnClick">按钮</button>
  </div>
</template>

<script src="../js/vue.min.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊,vue'
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: '我是cpn组件的name'
          }
        },
        components: {
          ccpn: {
            template: '#ccpn',
            methods: {
              btnClick() {
                // 1.访问父组件$parent
                // console.log(this.$parent);
                // console.log(this.$parent.name);

                // 2.访问根组件$root
                console.log(this.$root);
                console.log(this.$root.message);
              }
            }
          }
        }
      }
    }
  })
</script>

小贴士

  • 组件里面使用子组件,必须加根标签,否则不会子组件的东西。
  • 如果在组件里面又挂载一个组件进行子访问父的通信,那么这个子组件的耦合度必然高,因为很多时候组件是需要复用的。该子组件在当前父组件内能够访问的属性,在另外一个组件复用的时候,很可能是没有这个属性,那么这时使用$parent.某个属性就会出错。

(4) 非父子组件通信

  • 前面我们讨论的都是父子组件间的通信,那如果是非父子关系呢?
    • 非父子组件关系包括多个层级的组件,也包括兄弟组件的关系。
  • 在Vue1.x的时候,可以通过 d i s p a t c h 和 dispatch和 dispatchbroadcast完成
    • $dispatch用于向上级派发事件
    • $broadcast用于向下级广播事件
    • 但是在Vue2.x都被取消了
  • 在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成。
    • 但是这种方案和直接使用Vuex的状态管理方案还是逊色很多。
    • 并且Vuex提供了更多好用的功能,所以这里我们暂且不讨论这种方案,后续我们专门学习Vuex的状态管理。

下一篇:组件化高级开发-插槽slot
https://blog.csdn.net/victory_CEO/article/details/113116816

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值