美文网首页
Vue组件化开发(二)——组件间的通信

Vue组件化开发(二)——组件间的通信

作者: moutory | 来源:发表于2021-07-25 20:16 被阅读0次

前言

使用Vue进行前端项目开发,项目中必然会使用和封装各种组件来保障代码的可复用性,但组件化开发也带来了一个问题,就是组件间的数据通信,本篇文章将围绕组件通信的问题,根据组件间的关系(父子组件以及非父子组件)来介绍常用的通信方式。

一、父子组件的通信

(一)父组件传递数据给子组件

父组件给子组件传递数据时,子组件可以使用props关键字来接收父组件的数据,定义props的值有两种方式,分别是:

  • 方式1:字符串数组,数组中的字符串就是传递时的名称。
  • 方式2:对象,对象可以设置传递时的类型,也可以设置默认值等。
    我们用的比较多的常常是第二种,因为后者可以对props参数进行约束,避免父组件传过来不符合要求的数据。下面我们就先用方式1来做一个简单的用例吧。
<div id="app">
      <div>
        <h3>我是父组件</h3>
        <child-component :cmessage="message"></child-component>
      </div>
    </div>
    <template id="child">
      <div>
        <h2>我是子组件,我接收到父组件的值是:</h2>
        <h4>{{cmessage}}</h4>
    </div>
    </template>
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    <script>
      let app = new Vue({
        el: '#app',
        data: {
          message : 'TODAY IS SUNDAY'
        },
        components:{
          'childComponent': {
            template: '#child',
            props: ['cmessage']
          }
        }
      })
    </script>
父组件传递数据给子组件演示用例
(二)子组件进行props的数据验证

除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了,Vue支持我们对String、Number等类型的数据验证之外,还支持默认值设置、字段是否为必填字段、自定义校验方式等功能。

 <div id="app">
      <div>
        <h3>我是父组件</h3>
        <child-component 
          :data1="data1"  
          :data2="data2"
          :data3="data3"
          :data6="data6"
        />
      </div>
    </div>
    <template id="child">
      <div>
        <h2>我是子组件,我接收到父组件的值是:</h2>
        <h5>{{data1}}</h5>
        <h5>{{data2}}</h5>
        <h5>{{data3}}</h5>
        <h5>{{data4}}</h5>
        <h5>{{data5}}</h5>
        <h5>{{data6}}</h5>
    </div>
    </template>
    <script src="./vue.js"></script>
    <script>
      let app = new Vue({
        el: '#app',
        data: {
          data1: 100,
          data2: '200',
          data3: '200',
          data6: '12345'
        },
        components:{
          'childComponent': {
            template: '#child',
            props:{
              // 单独定义接收参数的数据类型
              data1: Number,
              // 定义参数可接受的多种数据类型
              data2: [String,Number],
              // 定义必填字段
              data3: {
                type: String,
                required: true
              },
              // 定义带有默认值的对象
              data4: {
                type: Object,
                default: function(){
                  return {name: 'xiaoming',age: 19}
                }
              },
              // 定义带有默认值的数据
              data5: {
                type: Number,
                default: 200
              },
              // 自定义验证函数
              data6: {
                validator: function(value){
                  return value.length > 5
                }
              }
            }
          }
        }
      })
    </script>
props校验案例演示

我们可以看到,如果说存在porps参数不符合要求的情况,控制台会进行报错提醒。

(三)子组件传递数据给父组件

子组件传递数据给父组件时,可以通过自定义事件来进行实现,自定义事件的实现流程如下:

  • 在子组件中,通过$emit()来触发事件。
  • 在父组件中,通过v-on来监听子组件事件,一般用@事件名来进行简写
    具体的实现我们可以参考下面的这个例子:
<div id="app">
      <div>
        <!-- 这里需要注意,@plus相当于是使用了 v-on:plus=""来进行自定义事件的绑定 -->
        <child-component @plus="changeCount" @minus="changeCount"></child-component>
        <h3>我是父组件,子组件当前的count值为:</h3>
        <h5>{{pCount}}</h5>
      </div>
    </div>
    <template id="child">
      <div>
        <h2>我是子组件:</h2>
        <div>
          <button @click="increment">+1</button>
          <button @click="decrement">-1</button>
        </div>
     </div>
    </template>
    <script src="./vue.js"></script>
    <script>
      let app = new Vue({
        el: '#app',
        data(){
          return {pCount: 0}
        },
        methods: {
          changeCount(val){
            this.pCount = val;
          }
        },
        components:{
          'childComponent': {
            template: '#child',
            data(){
              return {
                count: 0
              }
            },
            methods:{
              increment(){
                this.count = this.count + 1;
                this.$emit('plus',this.count)
              },
              decrement(){
                this.count = this.count - 1;
                this.$emit('minus',this.count);
              }
            }
          }
        }
      })
    </script>
子组件向父组件传递数据演示用例

二、父子组件的访问方式

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

有时候我们需要父组件直接访问子组件,这里的访问指的是直接获取到子组件的实例对象,我们此时就可以通过this.$children来进行获取,this.$children可以让我们获取当前组件下的所有子组件集合

<div id="app">
      <div>
        <!-- 这里需要注意,@plus相当于是使用了 v-on:plus=""来进行自定义事件的绑定 -->
        <button @click="showChild">ShowChild</button>
        <child-component></child-component>
      </div>
    </div>
    <template id="child">
      <div>
        <h2>我是子组件:</h2>
        <div>
          <grand-child1></grand-child1>
          <grand-child2></grand-child1>
        </div>
     </div>
    </template>
    <template id="child1">
      <div>
        <h4>我是孙组件1</h4>
      </div>
    </template>
    <template id="child2">
      <div>
        <h4>我是孙组件1</h4>
      </div>
    </template>
    <script src="./vue.js"></script>
    <script>
      let app = new Vue({
        el: '#app',
        data(){
          return {pCount: 0}
        },
        methods: {
          showChild(){
            for(let i = 0; i< this.$children.length ; i++){
              console.log(this.$children[i]);
            }
          }
        },
        components:{
          'childComponent': {
            template: '#child',
            data(){
              return {
                count:0
              }
            },
            components:{
              'grand-child1':{
                template: '#child1'
              },
              'grand-child2':{
                template: '#child2'
              }
            }
          }
        }
      })
    </script>
$children的演示用例
(二)父子组件的访问方式: $refs

通过$children访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用$refs

<div id="app">
      <div>
        <!-- 这里需要注意,@plus相当于是使用了 v-on:plus=""来进行自定义事件的绑定 -->
        <button @click="showChild">ShowChild</button>
        <child-component ref="child"></child-component>
      </div>
    </div>
    <template id="child">
      <div>
        <h2>我是子组件:</h2>
        <div>
          <grand-child1></grand-child1>
          <grand-child2></grand-child1>
        </div>
     </div>
    </template>
    <template id="child1">
      <div>
        <h4>我是孙组件1</h4>
      </div>
    </template>
    <template id="child2">
      <div>
        <h4>我是孙组件1</h4>
      </div>
    </template>
    <script src="./vue.js"></script>
    <script>
      let app = new Vue({
        el: '#app',
        data(){
          return {pCount: 0}
        },
        methods: {
          showChild(){
            console.log(this.$refs.child.count);
          }
        },
        components:{
          'childComponent': {
            template: '#child',
            data(){
              return {
                count: 100
              }
            },
            components:{
              'grand-child1':{
                template: '#child1'
              },
              'grand-child2':{
                template: '#child2'
              }
            }
          }
        }
      })
    </script>
$ref的演示案例
(三)父子组件的访问方式: $parent
<div id="app">
    <div>
      <!-- 这里需要注意,@plus相当于是使用了 v-on:plus=""来进行自定义事件的绑定 -->
      <child-component></child-component>
    </div>
  </div>
  <template id="child">
    <div>
      <h2>我是子组件:</h2>
      <div>
        <button @click="showParent">showParent</button>
      </div>
    </div>
  </template>
  <script src="./vue.js"></script>
  <script>
    let app = new Vue({
      el: '#app',
      data() {
        return { pCount: 0 }
      },
      methods: {
      },
      components: {
        'childComponent': {
          template: '#child',
          data() {
            return {

            }
          },
          methods: {
            showParent() {
              console.log(this.$parent)
            }
          }
        },
      }
    })
  </script>

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

$parent的演示用例-由于父组件是Vue实例,所以这里显示的就是Vue实例对象
注意事项:

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

三、非父子组件的通信

非父子组件关系包括多个层级的组件,也包括兄弟组件的关系。
在Vue1.x的时候,可以通过$dispatch$broadcast完成

  • $dispatch用于向上级派发事件
  • $broadcast用于向下级广播事件

但是在Vue2.x都被取消了,在Vue2.x中,有一种方案是通过中央事件总线,也就是一个中介来完成。但更好的方式是使用Vuex来进行全局的状态管理,关于Vuex的使用,可以参考一下我的这篇文章:Vuex的使用

相关文章

网友评论

      本文标题:Vue组件化开发(二)——组件间的通信

      本文链接:https://www.haomeiwen.com/subject/avnmvktx.html