Vue.js入门(6)组件间通信

序言

如果你了解过JavaScript的设计模式一一观察者模式,一定知道dispatchEvent和addEventListener这两个方法。

Vue组件也有与之类似的一套模式,子组件用$emit()来触发事件,父组件用$on()来监昕子组件的事件。

父传子

通过prop实现通信

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="../../assets/js/vue.js"></script>
</head>
<body>

    <div id="app">
        <div>{{pmsg}}</div>
        <child title='来自父组件的值'></child>
      </div>
    
      <template id="childtmpl">
        <div>
            <div>{{msg}}-{{title}}</div>
        </div>
      </template>

      <script type="text/javascript">
      //子组件
        Vue.component('child', {
          props: ['title'],
          data: function() {
            return {
              msg: '子组件本身的数据'
            }
          },
          template: '#childtmpl'
        });

        //父组件
        var vm = new Vue({
          el: '#app',
          data: {
            pmsg: '父组件',
          }
        });
      </script>
</body>
</html>
View Code

子传父

子组件用$emit()触发事件

$emit()第一个参数为自定义的事件名称第二个参数为需要传递的数据

父组件用v-on监听子组件的事件

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="../../assets/js/vue.js"></script>
</head>
<body>

    <!--父组件 -->
    <div id="app">
        <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
        <child  @father-enlarge-text='fatherfunction($event)'></child>
    </div>

    <!-- 子组件 -->
      <template id="childtmpl">
        <div>
            <button @click='sonfunction'>子传父</button>
          </div>
      </template>

      <script type="text/javascript">
      
        Vue.component('child', {
          template: '#childtmpl'
          ,
          methods: {
            sonfunction: function(val){
              this.$emit("father-enlarge-text", 5)
            }
          }
        });

        var vm = new Vue({
          el: '#app',
          data: {
            pmsg: '父组件',
            fontSize: 10
          },
          methods: {
            fatherfunction: function(val){
              this.fontSize += val;
            }
          }
        });
      </script>
    
</body>
</html>
View Code

兄弟传

在Vue.2.x中,推荐使用一个空的Vue实例作为中央事件总线(bus),也就是一个中介。

这种方法巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级,而且Vue1.x和Vue2.x都适用。


兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据

提供事件中心 var hub = new Vue()

传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)

接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名

销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="../../assets/js/vue.js"></script>
</head>
<body>
    <div id="app">
        <div>父组件</div>
        <div>
          <button @click='handle'>销毁事件</button>
        </div>
        <borther-a></borther-a>
        <borther-b></borther-b>
    </div>

    <template id="Atmpl">
        <div>
            <div>a:{{num}}</div>
            <div>
              <button @click='handle'>点击</button>
            </div>
          </div>
      </template>


      <template id="Btmpl">
        <div>
            <div>b:{{num}}</div>
            <div>
              <button @click='handle'>点击</button>
            </div>
          </div>
      </template>


      <script type="text/javascript">

        //1、 中央事件总线
        var bus = new Vue();
    
        Vue.component('borther-a', {
          data: function(){
            return {
              num: 0
            }
          },
          template: '#Atmpl',
          methods: {
            handle: function(){
              //2、传递数据方,通过一个事件触发bus.$emit(方法名,传递的数据)   触发兄弟组件的事件
              bus.$emit('b-event', 2);
            }
          },
          mounted: function() {
           // 3、接收数据方,通过mounted(){}钩子中触发bus.$on(方法名
            bus.$on('a-event', (val) => {
              this.num += val;
            });
          }
        });

     Vue.component('borther-b', {
      data: function(){
        return {
          num: 0
        }
      },
      template: '#Btmpl',
      methods: {
        handle: function(){
          //2、传递数据方,通过一个事件触发bus.$emit(方法名,传递的数据)触发兄弟组件的事件
          bus.$emit('a-event', 1);
        }
      },
      mounted: function() {
        // 3、接收数据方,通过mounted(){}钩子中触发bus.$on()方法名
        bus.$on('b-event', (val) => {
          this.num += val;
        });
      }
    });
    var vm = new Vue({
      el: '#app',
      data: {},
      methods: {
        handle: function(){
          //4、销毁事件 通过bus.$off()方法名销毁之后无法进行传递数据  
          bus.$off('a-event');
          bus.$off('b-event');
        }
      }
    });
    </script>
</body>
</html>
View Code

当你的项目比较大,有更多的小伙伴参与开发时,也可以选择更好的状态管理解决方案vuex

除了中央事件总线bus外,还有两种方法可以实现组件间通信:父链和子组件索引

父链

在子组件中,使用this.$parent可以直接访问该组件的父实例或组件,父组件也可以通过this.$children访问它所有的子组件,而且可以递归向上或向下无线访问,直到根实例或最内层的组件。

尽管Vue允许这样操作,但在业务中,子组件应该尽可能地避免依赖父组件的数据,更不应该去主动修改它的数据,因为这样使得父子组件紧藕合,只看父组件,很难理解父组件的状态,因为它可能被任意组件修改,理想情况下,只有组件自己能修改它的状态。父子组件最好还是通过props和$emit来通信。

子组件索引

当子组件较多时,通过this.$children来一一遍历出我们需要的一个组件实例是比较困难的,尤其是组件动态渲染时,它们的序列是不固定的。Vue提供了子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称。

在父组件模板中,子组件标签上使用ref指定一个名称,井在父组件内通过this.$refs来访问指定名称的子组件。

$refs只有渲染完成后才填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用础。

资料

https://www.jb51.net/article/140581.htm

原文地址:https://www.cnblogs.com/cnki/p/13233808.html