• VUE——vue中组件之间的通信方式有哪些


    前言

    今天我们来说下vue组件间的通信方式

    内容

    1. 组件通信方式大体有以下8种:
        props
        $emit/$on
        $children/$parent
        $attrs/$listeners
        ref
        $root
        eventbus
        vuex
    
    根据组件之间关系大概应用如下
    1. 父子组件
        props
        $emit/$on
        $parent / $children
        ref
        $attrs / $listeners
    
    2. 兄弟组件
        $parent
        eventbus
        vuex
    
    3. 跨层级关系
        provide/inject
        $root
        eventbus
        vuex
    

    父组件向子组件传值

    1.1 props方式:可以是数组或对象,用于接收父组件的数据

    <div id="app">
      	<child-component :msg="message" :count="count"></child-component>
      	<button @click="count++">
          点击+1
      	</button>
    </div>
    <script>
      const childComponent={
    		props:{
          msg:String
          count:Number
        },
        template:`<div><p>{{msg}}</p><p>{{count}}</p><div>`
      }
    	new Vue({
        el:'#app',
        data:{
          message:'父组件的值',
          count:0
        },
        components:{
          childComponent
        }
      })
    </script>
    

    1.2 通过$parent获取父组件实例的方法或者属性

    这种方式,从严格意义上讲不是值的传递,而是一种“取”(不推荐直接通过实例进行值的获取)

    使用:

    实例属性$pareng可以获得父组件的实例,借助实例可以调用父实例中的方法,或者父实例上的属性

    <div id="app">
      	<child-component :msg="message" :count="count"></child-component>
      	<button @click="count++">
          点击+1
      	</button>
    </div>
    <script>
      //子组件
      const childComponent={
    		data:()=>({
          msg:'',
          count:null
        }),
        methods:{
          handleClick(){
            //调用父级实例的方法
            this.$parent.parentMethods();
          }
        }
        mounted(){
          // 获取父级实例中的属性
          this.msg = this.$parent.message;
          this.count = this.$parent.count;
        }
        template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
      }
      // 父级
    	new Vue({
        el:'#app',
        data:{
          message:'父组件的值',
          count:0
        },
        methods:{
          parentMethod(){
            console.log('我是父级的方法');
          }
        }
        components:{
          childComponent
        }
      })
    </script>
    

    1.3 使用修饰符 .sync

    修饰符 .sync2.3.0+ 新增,它对 props 起到了一种修饰的作用,使用 .sync 进行修饰的 props 意味子组件有修改它的意图,这种情况下它只起到一个标注性作用,有它没它都不会影响逻辑

    使用 .sync 修改上边的代码:

    // 父组件 List.vue
    <template>
      <!-- 这里不写 .sync 也不会影响结果 -->
      <List-item :title.sync="title" @update:title="updataTitle"></List-item>
    </template>
    <script>
    import ListItem from "./ListItem";
    export default {
      data() {
        return {
          title: "我是title",
        }
      },
      components: {
        ListItem
      },
      methods: {
       updataTitle(res) {
        this.title = res;
       }
      }
    }
    </script>
    
    // 子组件 ListItem.vue
    <template>
      <div>
        <button @click="handleClick">Click me</button>
        <div>{{title}}</div>
      </div>
    </template>
    <script>
    export default {
      props: {
        title: String, 
      },
      methods: {
       handleClick() {
        // 子组件向父组件传值
        this.$emit('update:title', '我要父组件更新 title');
       }
      }
    }
    </script>
    

    使用.sync 向子组件传递 多个props:

    当我们用一个对象同时设置多个 prop 的时候,也可以将这个 .sync 修饰符和 v-bind 配合使用:

    <text-document v-bind.sync="doc"></text-document>
    

    这样会把 doc 对象中的每一个属性 (如 title) 都作为一个独立的 prop 传进去,然后各自添加用于更新的 `v-on 监听器。

    子组件向父组件传值

    2.1 通过事件传值$emit

    使用:

    子组件使用$emit发送一个自定义事件

    父组件使用指令v-on监听子组件发送的事件

    <div id="app">
      	<child-component @child-event="childEvent"></child-component>
    </div>
    <script>
      //子组件
      const childComponent={
    		data:()=>({
          msg:'点击发送值到父组件',
          count:null
        }),
        methods:{
          handleClick(data){
    				this.$emit('child-event','我是子组件传过来的值');
          }
        }
        template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
      }
      // 父级
    	new Vue({
        el:'#app',
        data:{
          message:'父组件的值',
          count:0
        },
        methods:{
          childEvent(data){
    				console.log("子组件传过来的值",data);
          }
        }
        components:{
          childComponent
        }
      })
    </script>
    

    2.2通过$children获取子组件实例

    同$parent

    2.3 通过ref注册子组件引用

    虽然存在prop和事件,但是有时仍可能需要在JavaScript里直接访问一个子组件。为了实现这样的需求,可以使用ref特性为某个子组件设置一个ID引用,就是一个身份标识

    <div id="app">
      	<child-component ref="childComponent"></child-component>
      	<button @click="getRefs">
          获取子组件实例
      	</button>
    </div>
    <script>
      //子组件
      const childComponent={
    		data:()=>({
          msg:'点击发送值到父组件',
          count:null
        }),
        template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>`
      }
      // 父级
    	new Vue({
        el:'#app',
        data:{
          message:'父组件的值',
          count:0
        },
        methods:{
          getRefs(){
    				console.log("子组件传过来的值",this.$refs.childComponent.msg);
          }
        }
        components:{
          childComponent
        }
      })
    </script>
    

    兄弟组件传值

    3.1 Bus中央事件总线

    非父子组件传值,可以使用一个空的Vue实力作为中央事件总线,结合实例方法$on,$emit使用

    注意:

    注册的Bus要在组件销毁时卸载,否则会多次挂载,造成触发一次但多个响应的情况。

    beforeDestroy(){
      this.$Bus.$off('方法名',value);
    }
    

    Bus定义方式:

    1. 将Bus抽离出来,组件有需要时引入
    // bus.js
    import Vue from 'vue';
    const Bus = new Vue();
    export default Bus;
    
    1. 将Bus挂载到Vue根实例的原型上
    import Vue from 'vue';
    Vue.prototype.$bus = new Vue();
    
    1. 将bus注入到Vue根对象上
    import Vue form 'vue';
    const Bus = new Vue();
    new Vue({
      el:'#app',
      data:{
        Bus
      }
    })
    

    使用例子:

    <div id="app">
      	<child-component ></child-component>
    		<child-component-two ></child-component-two>
    </div>
    <script>
      Vue.prototype.$bus = new Vue();
      //子组件1 
      const childComponent={
    		data:()=>({
          msg:'我是子组件一',
          sendMsg:'我是子组件一发送的值'
        }),
        methods:{
          handleClick(){
            this.$Bus.$emit('sendMsg',this.sendMsg);
          }
        }
        template:`<div><p @click="handleClick">{{msg}}</p></p><div>`
      }
      //子组件2
      const childComponentTwo={
    		data:()=>({
          msg:'我是子组件二',
          brotherMsg:''
        }),
        mounted(){
          this.$Bus.$on('sendMsg',data=>{
            this.brotherMsg = data;
          })
        },
        beforeDestroy(){
          this.$Bus.$off('sendMsg');
        }
        template:`<div><p @click="handleClick">{{msg}}</p><p>{{brotherMsg}}</p><div>`
      }
      
      // 父级
    	new Vue({
        el:'#app',
        data:{},
        components:{
          childComponent,
        	childComponentTwo
        }
      })
    </script>
    

    跨组件

    4.1 $attrs$listeners

    如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A直接想传递数据给组件C那就行不通了!所以这时可以使用 $attrs 和 $listeners

    Vue 2.4 提供了 $attrs$listeners 来实现能够直接让组件A传递消息给组件C。

    // 组件A
    Vue.component('A', {
      template: `
        <div>
          <p>this is parent component!</p>
          <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B>
        </div>
      `,
      data() {
        return {
          message: 'hello',
          messagec: 'hello c' //传递给c组件的数据
        }
      },
      methods: {
        // 执行B子组件触发的事件
        getChildData(val) {
          console.log(`这是来自B组件的数据:${val}`);
        },
        
        // 执行C子组件触发的事件
        getCData(val) {
          console.log(`这是来自C组件的数据:${val}`);
        }
      }
    });
    
    // 组件B
    Vue.component('B', {
      template: `
        <div>
          <input type="text" v-model="mymessage" @input="passData(mymessage)"> 
          <!-- C组件中能直接触发 getCData 的原因在于:B组件调用 C组件时,使用 v-on 绑定了 $listeners 属性 -->
          <!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到 A组件中传递下来的 props(除了 B组件中 props声明的) -->
          <C v-bind="$attrs" v-on="$listeners"></C>
        </div>
      `,
      /**
       * 得到父组件传递过来的数据
       * 这里的定义最好是写成数据校验的形式,免得得到的数据是我们意料之外的
       *
       * props: {
       *   message: {
       *     type: String,
       *     default: ''
       *   }
       * }
       *
      */
      props: ['message'],
      data(){
        return {
          mymessage: this.message
        }
      },
      methods: {
        passData(val){
          //触发父组件中的事件
          this.$emit('getChildData', val)
        }
      }
    });
    
    // 组件C
    Vue.component('C', {
      template: `
        <div>
          <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)">
        </div>
      `,
      methods: {
        passCData(val) {
          // 触发父组件A中的事件
          this.$emit('getCData',val)
        }
      }
    });
        
    var app=new Vue({
      el:'#app',
      template: `
        <div>
          <A />
        </div>
      `
    });
    
    

    4.2 provide 和 inject

    熟悉 React 开发的同学对 Context API 肯定不会陌生吧!在 Vue 中也提供了类似的 API 用于组件之间的通信。
    在父组件中通过 provider 来提供属性,然后在子组件中通过 inject 来注入变量。不论子组件有多深,只要调用了 inject 那么就可以注入在 provider 中提供的数据,而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。这和 React 中的 Context API 有没有很相似!

    // 定义 parent 组件
    Vue.component('parent', {
      template: `
        <div>
          <p>this is parent component!</p>
          <child></child>
        </div>
      `,
      provide: {
        for:'test'
      },
      data() {
        return {
          message: 'hello'
        }
      }
    });
    
    // 定义 child 组件
    Vue.component('child', {
      template: `
        <div>
          <input type="tet" v-model="mymessage"> 
        </div>
      `,
      inject: ['for'],	// 得到父组件传递过来的数据
      data(){
        return {
          mymessage: this.for
        }
      },
    });
    
    const app = new Vue({
      el: '#app',
      template: `
        <div>
          <parent />
        </div>
      `
    });
    

    上面的实例中,定义了组件 parent 和组件 child,组件 parent 和组件 child 是父子关系。

    • 在 parent 组件中,通过 provide 属性,以对象的形式向子孙组件暴露了一些属性
    • 在 child 组件中,通过 inject 属性注入了 parent 组件提供的数据,实际这些通过 inject 注入的属性是挂载到 Vue 实例上的,所以在组件内部可以通过 this 来访问。

    ⚠️ 注意:官网文档提及 provide 和 inject 主要为高阶插件/组件库提供用例,并不推荐直接用于应用程序代码中。

    4.3 Vuex 状态管理

    Vuex 是状态管理工具,实现了项目状态的集中式管理。工具的实现借鉴了 Flux、Redux、和 The Elm Architecture 的模式和概念。当然与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。

  • 相关阅读:
    5. 详解创建Vue实例传入的options【暂时3个】
    编程的小知识点:
    4. Vue的 MVVM模式
    3. Vue做一个计数器 --新属性:methods、新的指令:@click
    8. Spring 注解开发(原始注解)
    2. 第一个Vue程序
    1.VUE 的安装
    【洛谷 3388】割点
    【洛谷 1063】能量项链
    三堆石子
  • 原文地址:https://www.cnblogs.com/wangyang0210/p/13824042.html
Copyright © 2020-2023  润新知