• Vue父子组件和非父子组件间的通信


    在学习幕课网"饿了么"程序时,遇到了一个组件通信的问题:

    在food详情页面只能通过点击“购物”

    1.goods.vue(食品列表组件),2.food.vue(食品详情组件),3.cartcontrol.vue(数量控制组件),4.shopcart.vue(购物车组件)

    1.goods.vue组件内容: 

     1 <template>
     2     <div class="goods">
     3         <cartcontrol @cart-add-cartcontrol="addCart" :food="food"></cartcontrol>
     4         <shopcart ref="shopcart" :select-foods="selectFoods" :delivery-price="seller.deliveryPrice" :min-price="seller.minPrice"></shopcart>
     5         <food ref="food" :food="selectedFood" @cart-add-food="addCart"></food>
     6     </div>
     7 </template>
     8 <script type="text/ecmascript-6">
     9     import cartcontrol from "./cartcontrol";
    10     import shopcart from "./shopcart";
    11     import food from "./food";
    12     export default {
    13         components: {
    14             shopcart,
    15             cartcontrol,
    16             food
    17         },
    18         methods: {
    19             addCart(target) {
    20                 // 通过refs调用shopcart中的drop方法
    21                 // 体验优化,异步执行下落动画
    22                 this.$nextTick(() => {
    23                     this.$refs.shopcart.drop(target);
    24                 });
    25             },
    26         }
    27     }
    28 </script>
    29 <style lang="stylus" rel="stylesheet/stylus">
    30 </style>
    View Code

    食品列表页面包含食品列表,购物车组件(shopcart.vue),每个食品(food.vue)后都有数量控制组件(cartcontrol.vue)

    2.food.vue组件的内容:

     1 <template>
     2     <div class="food">
     3         <cartcontrol :food="food"></cartcontrol>
     4         <transition name="fade">
     5             <div class="buy" v-show="!food.count || food.count===0" @click.stop.prevent="addFirst($event)">加入购物车</div>
     6         </transition>    
     7     </div>
     8     
     9 </template>
    10 <script type="text/ecmascript-6">
    11     import cartcontrol from './cartcontrol';
    12     export default {
    13         components: {
    14             cartcontrol
    15         }
    16         methods: {
    17             addFirst(event) {
    18                 // console.log(event.target);
    19                 // $emit调用的自定义事件v-on:cart-add(或者:cart-add)
    20                 // this.$parent._drop(event.target);
    21                 this.$emit("cart-add-food", event.target);
    22                 Vue.set(this.food, "count", 1);
    23             }            
    24         }
    25     }
    26 </script>
    27 <style lang="stylus" rel="stylesheet/stylus">
    28 </style>
    View Code

    食品详情页面包含"加入购物车"按钮和数量控制组件(cartcontrol.vue)

    3.cartcontrol.vue组件内容:

     1 <template>
     2     <div class="cartcontrol">
     3         <div class="cart-add icon-add_circle" @click.stop.prevent="addCart($event)">数量控制组件</div>
     4     </div>
     5 </template>
     6 <script type="text/ecmascript-6">
     7     import Vue from 'vue';
     8     export default {
     9         props: {
    10             food: {
    11                 type: Object
    12             }
    13         },
    14         methods:{
    15             //增加event是为了阻止PC端点击会出现两次增加,实际我这里没有出现该种情况
    16             addCart(event) {
    17                 // console.log('调用到cartcontrol.vue中的addCart方法并分发cartAdd');
    18                 this.$emit('cart-add-cartcontrol', event.target);
    19             }
    20         }
    21     }
    22 </script>
    View Code

    4.shopcart.vue组件内容:

     1 <template>
     2         <div class="shopcart">
     3             <cartcontrol :food="food"></cartcontrol>
     4         </div>
     5 </template>
     6 <script type="text/ecmascript-6">
     7   import cartcontrol from './cartcontrol'
     8     export default {
     9         components: {
    10             cartcontrol
    11         },
    12         methods: {
    13             drop (el) {
    14                 console.log("我是小球下落方法");                
    15             }
    16         }
    17     };
    18 </script>
    View Code

     

    问题:

    当点击食品列表页(goods.vue)中的“+”按钮时会出现小球进入购物车的效果:

    实现过程:

    1.cartcontrol.vue中@click.stop.prevent="addCart($event)"调用addCart($event)并传入$event

    2.addCart()中this.$emit('cart-add-cartcontrol', event.target);通过@cart-add-cartcontrol="addCart"触发父组件goods.vue中addCart(target)方法并传入target

    3.addCart(target)中this.$refs.shopcart.drop(target);通过ref="food"调用shopcart.vue中的drop(target)方法并传入target

    4.最终实现小球从“+”按钮滚落到购物车的效果

    同理:在食品详情页面中点击“加入购物车”按钮时会出现小球进入购物车的效果

    实现过程:

    1.food.vue中@click.stop.prevent="addFirst($event)"调用addFirst($event)并传入$event

    2.addFirst()中this.$emit('cart-add-food', event.target);通过@cart-add-food="addCart"触发父组件goods.vue中addCart(target)方法并传入target

    3.addCart(target)中this.$refs.shopcart.drop(target);通过ref="food"调用shopcart.vue中的drop(target)方法并传入target

    4.最终实现小球从“+”按钮滚落到购物车的效果

    但是

    1.在食品详情页面food.vue的“+”按钮无法通过cartcontrol.vue中this.$emit调用祖父组件addCart方法(包含关系:goods.vue包含shopcart.vue,food.vue包含cartcontrol.vue)

    2.购物车shopcart.vue中的“+”无法无法通过cartcontrol.vue中this.$emit调用祖父组件addCart方法(包含关系:goods.vue包含shopcart.vue,shopcart.vue包含cartcontrol.vue)

    当然也可以通过方法传递,但是那样太麻烦了,需要在cartcontrol.vue中区分不同的操作,那么可以通过$root.eventhub来实现这样的效果:

     第一步,在vue2.5中在初始化根Vue之前,给data添加一个 名字为eventhub 的空vue对象(main.js文件中)

    new Vue({
      el: '#app',
      router,
      data: {
          eventhub: new Vue()
      },
      components: { App },
      template: '<App/>'
    })

    第二步:在各组件中使用vue的实例属性$root来访问我们当前组件树的根 Vue 实例,并使用vm.$root.eventHub来访问我们定义的事件发射器eventHub

    修改cartcontrol.vue中的addCart(event)方法

    addCart(event) {
        // console.log('调用到cartcontrol.vue中的addCart方法并分发cartAdd');
        // this.$emit('cart-add-cartcontrol', event.target);
        this.$root.eventHub.$emit('cart.add', event.target); // 传输点击的目标元素
    }

    修改food.vue中的addFirst(event)方法

    addFirst(event) {
        // console.log(event.target);
        // $emit调用的自定义事件v-on:cart-add(或者:cart-add)
        // this.$parent._drop(event.target);
        this.$root.eventHub.$emit('cart.add', event.target); // 传输点击的目标元素
        Vue.set(this.food, "count", 1);
    }

    在shopcart.vue中添加监听方法 :

    created() {
      // 获取按钮组件的点击的元素,用在drop方法里
      this.$root.eventHub.$on('cart.add', this.drop);
    },
    beforeDestroy() {
      this.$root.eventHub.$off('cart.add', this.drop);
    }

    这样之后,非父子组件的通信就完成了,官方对于非父子组件通信也推荐了一个专用的状态管理层:Vuex

  • 相关阅读:
    为php5.6安装memched扩展
    关于OAM Webgate的最大链接数
    linux下tomcat-6的安装使用
    FastDFS_V5.0分布式存储(介绍、安装与使用)
    回忆过去,展望未来——写在2017年春节到来之际
    Linux下如何不停止服务,清空nohup.out文件
    Linux下LVM
    TCP/IP 三次握手-四次挥手
    weblogic.security.SecurityInitializationException: Authentication for user weblogic denied(详见下面具体报错信息)
    后台启动weblogic成功后,在web浏览器上无法访问
  • 原文地址:https://www.cnblogs.com/smartsmile-yxh/p/11398201.html
Copyright © 2020-2023  润新知