簡體   English   中英

Vue.js 如何在路由器視圖組件之間發出事件

[英]Vue.js How can i emit events between router-view components

我正在使用 vue.js 和 api 作為后端構建電子商務網站,我有一個名為Main.vue的根組件,它有一個router-link導航和一個router-view主體。

在一條名為Cart.vue的路線中,當用戶更新某些產品的數量時,我需要Cart.vue向根組件Main.vue $emit一個event以觸發名為getCartTotal()的 function

提示Cart.vue不是Main.vuechild component

Main.vue:

<template>
  <div>
    <div>
      <div v-on:getCartAgain="getCartTotal()" id="top-header" class="has-background-ishtari">
        <div class="container" style="padding:5px 0">
          <div class="is-hidden-mobile" style="font-size: 13px">
            <div
              class="has-text-white has-text-right"
              style="display: flex;align-items: center;justify-content: flex-end"
            >
              <i class="icon material-icons" style="margin-right: 0px;">attach_money</i>
              <span style="margin-right:15px">Best Deals</span>

              <i class="icon material-icons" style="margin-right: 5px;">low_priority</i>
              <span style="margin-right: 15px">Free & Easy Returns</span>

              <i class="icon material-icons" style="margin-right: 5px;">local_shipping</i>
              <span>Free Delivery (OVER $100)</span>
            </div>
          </div>
        </div>

        <div class="container" style="padding:10px 0">
          <div style="display: flex;justify-content: space-between;align-items: center;">
            <div id="header-logo" @click="openHomePage()">
              <img src="../assets/images/logo-ishtari.png" class width="140" />
            </div>
            <div style="flex-grow: 2;margin:0 40px">
              <p class="control is-expanded">
                <input
                  id="header-search"
                  class="input is-radiusless"
                  style="height: 35px;"
                  type="text"
                  placeholder="What are you looking for?"
                />
              </p>
            </div>
            <div
              class="has-text-white"
              style="display: flex;align-items: center;justify-content: space-between"
            >
              <div style="display: flex;align-items: center;padding-right:10px">
                <span>Login Or SignUp</span>
                <i class="icon material-icons">arrow_drop_down</i>
              </div>

              <div
                id="cart-container"
                style="display: flex;align-items: center;padding-left: 15px;border-left:1px solid rgba(255,255,255,0.5)"
                @click="openCartPage()"
              >
                <span style="margin-right:5px">Cart</span>
                <span>
                  <i class="icon material-icons">shopping_cart</i>
                  <span
                    class="has-background-ishtari-blue is-paddingless"
                    :class="this.cartCount.length == 0 ? 'button is-loading' : ''"
                    id="cart-total"
                  >{{this.cartCount}}</span>
                </span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <vue-page-transition name="fade-in-right">
      <router-view></router-view>
    </vue-page-transition>
  </div>
</template>
<script>
import VueCookies from "vue-cookies";

export default {

  data() {
    return {
      showNav: false,
      cartCount: "",
      readyToken: false
    };
  },
  created() {
    this.checkToken();
  },
  mounted() {
    this.getCartTotal();
  },

  methods: {
    openCartPage() {
      this.$router.push({ name: "cart" }).catch(err => {
        return err;
      });
    },
    openHomePage() {
      this.$router.push({ name: "home" }).catch(err => {
        return err;
      });
    },

    checkToken() {
      if (!VueCookies.isKey("token")) {
        let requestBody = {
          client_id: "shopping_oauth_client",
          client_secret: "shopping_oauth_secret"
        };
        let requestHeader = {
          "Content-Type": "application/x-www-form-urlencoded",
          Authorization:
            "Basic c2hvcHBpbmdfb2F1dGhfY2xpZW50OnNob3BwaW5nX29hdXRoX3NlY3JldA",
          "Access-Control-Allow-Origin": "*",
          "Cache-Control": null,
          "X-Requested-With": null
        };

        window.axios
          .post(window.main_urls["get-token"], requestBody, {
            headers: requestHeader
          })
          .then(response => {
            VueCookies.set("token", response.data.access_token);
          });
      } else {
        console.log(VueCookies.get("token"));
      }
    },

    getCartTotal() {
      console.log("here");
      let requestHeader = {
        Authorization: "Bearer " + VueCookies.get("token"),
        "Access-Control-Allow-Origin": "*",
        "Cache-Control": null,
        "X-Requested-With": null
      };
      window.axios
        .get(window.main_urls["get-cart"], { headers: requestHeader })
        .then(response => {
          if (response.data.error === "Cart is empty") {
            console.log(response.data);
            this.cartCount = 0;
          } else {
            this.cartCount = response.data.data.products.length.toString();
          }
        });
    }
  }
};
</script>
<style>
</style>

Cart.vue:


<template>
  <div class="has-background-ishtari-grey">
    <div class="container">
      <div>
        <section v-if="this.loading || this.emptyCart" class="hero is-fullheight-with-navbar">
          <div
            v-if="this.loading"
            class="button is-loading hero is-fullheight-with-navbar has-background-ishtari-grey"
            style="border: none"
          >Please Wait</div>
          <div v-if="! this.loading && this.emptyCart" class="hero-body">
            <div class="container has-text-centered">
              <i class="material-icons has-text-grey" style="font-size: 80px">shopping_cart</i>
              <h1 class="title has-text-grey has-text-weight-bold is-4">Your Shopping Cart Is Empty</h1>
              <h2 class="subtitle title has-text-grey is-6">what are you waiting for</h2>
              <br />
              <button
                @click="goHome()"
                class="button is-ishtari-blue is-outlined has-text-weight-bold is-7"
              >START SHOPPING</button>
            </div>
          </div>
        </section>
      </div>

      <div class="section" v-if="! this.loading && !this.emptyCart">
        <div class="columns is-bordered" id="cart-products-container">
          <div class="column is-9" style="margin-right:20px">
            <h1
              class="subtitle has-text-weight-bold is-4"
            >My Cart ({{this.cartData.products.length}} items)</h1>
            <img
              src="https://storage.googleapis.com/noon-cdn-res/rn/banners/en_disclaimer-cart-desktop.gif"
              style="margin-bottom:15px"
            />

            <div
              class="cart-product-row has-background-white"
              style="padding:10px 15px"
              v-for="product in cartData.products"
              :key="product.product_id"
            >
              <div
                class="columns padding-top:20px"
                :class="product.stock ? '' : 'has-background-danger'"
              >
                <div class="image is-128x128 column is-narrow">
                  <img :src="product.thumb" />
                </div>

                <div
                  class="column"
                  style="display:flex;flex-direction:column;justify-content:space-between"
                >
                  <p
                    class="has-text-grey subtitle is-7 is-marginless"
                    style="margin-bottom:10px !important"
                  >{{product.model}}</p>
                  <p class="has-text-weight-bold" style="font-size:14px">{{product.name}}</p>
                  <p>
                    <i @click="product.quantity = 0;updateCartQuantity(product.key,0)" class="material-icons has-text-grey" id="cart-delete">delete</i>
                  </p>
                </div>
                <div
                  class="column is-narrow"
                  style="padding-left:15px;display:flex;flex-direction:column;justify-content:center"
                >
                  <p class="has-text-weight-bold">{{product.price}}</p>
                </div>

                <div
                  class="column is-narrow"
                  style="display:flex;flex-direction:column;justify-content:center"
                >
                  <div class="field has-addons">
                    <p class="control">
                      <a
                        @click="product.quantity = Number(product.quantity) - 1;updateCartQuantity(product.key,product.quantity)"
                        class="button"
                      >-</a>
                    </p>
                    <p class="control">
                      <input
                        class="input has-text-centered"
                        type="text"
                        placeholder="0"
                        style="width:80px"
                        readonly
                        :value="product.quantity"
                        :ref="product.product_id"
                      />
                    </p>
                    <p class="control">
                      <a
                        class="button"
                        @click="product.quantity = Number(product.quantity) + 1;updateCartQuantity(product.key,product.quantity)"
                      >+</a>
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="column is-narrow" style=" align-self:flex-start;margin-top:10px">
            <div style="border:1px solid #eee; background:#f7f9fe; padding:20px 15px">
              <div class="field has-addons">
                <p class="control">
                  <input class="input is-ishtari-green" type="text" placeholder="Coupon Code" />
                </p>
                <p class="control">
                  <a class="button is-ishtari-green">Apply</a>
                </p>
              </div>

              <div class="columns">
                <div class="column">
                  <p class="has-text-weight-bold">Order Summary</p>
                </div>
              </div>
              <div class="columns"></div>
              <div v-for="total in cartData.totals" :key="total.code">
                <div class="columns">
                  <div class="column">
                    <p>{{total.title}}</p>
                  </div>
                  <div class="column is-narrow">
                    <p>{{total.text}}</p>
                  </div>
                </div>
              </div>
            </div>
            <button
              class="button is-ishtari-blue has-text-weight-bold"
              style="display:block;width:100%;margin-top:10px"
            >CHECKOUT NOW</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import VueCookies from "vue-cookies";

export default {
  data() {
    return {
      cartData: [],
      emptyCart: false,
      loading: true
    };
  },

  created() {
    this.getCartContent();
  },
  methods: {
    goHome() {
      this.$router.push({ name: "home" }).catch(err => {
        return err;
      });
    },

    getCartContent() {
      let requestHeader = {
        Authorization: "Bearer " + VueCookies.get("token")
      };
      window.axios
        .get(window.main_urls["get-cart"], { headers: requestHeader })
        .then(response => {
          if (response.data.error === "Cart is empty") {
            this.emptyCart = true;
            this.loading = false;
          } else {
            this.loading = false;
            this.cartData = response.data.data;
          }
        });
    },

    updateCartQuantity(pkey, pquan) {
      this.loading = true;
      let requestHeader = {
        Authorization: "Bearer " + VueCookies.get("token")
      };
      let requestBody = {
        key: pkey.toString(),
        quantity: pquan.toString()
      };

      window.axios
        .put(window.main_urls["get-cart"], requestBody, {
          headers: requestHeader
        })
        .then(response => {
          if (response.data.success == "1") {
            this.getCartContent();
            this.$emit("getCartAgain");
          }

        });
    },
  }
};
</script>
<style scoped la>
.cart-product-row {
  border-bottom: 1px solid #eee;
  padding: 10px 0;
}
.cart-product-row:last-of-type {
  border-bottom: none;
}
#cart-delete {
  font-size: 20px;
  cursor: pointer;
}
#cart-delete:hover{
  transform: scale(1.05);
}
</style>


我需要在 Cart.vue 中名為updateCartQuantity()Cart.vue來觸發 Main.vue 中名為getCartTotal()Main.vue

Vuex 可能比你需要的多一點。 您可以通過創建一個導出新 vue 實例的簡單文件來使用pub/sub技術,然后您可以監聽該 Vue 實例上發出的事件:

//bus.js

import Vue from 'vue'

export default new Vue()

然后在您的Main.vue中,您可以導入:

import EventBus from '@/path/to/bus'

在您created的掛鈎中,您可以設置一個偵聽器:

created() {
    EventBus.$on('refresh_cart_total', this.getCartTotal)
}

您可以在需要時從您的Cart.vue$emit該事件。 再次導入總線:

import EventBus from '@/path/to/bus'

然后在您的Cart.vue中隨時調用它:

EventBus.$emit('refresh_cart_total')

現在你有了一個雙向的發布/訂閱系統,你不需要為像這樣的簡單任務引入 Vuex。

獎金

為了保持干燥,您還可以在bus.js中實現常量,例如:

export const REFRESH_CART_TOTAL = 'refresh_cart_total'

現在您可以使用import * as CART_CONSTANTS from '/path/to/bus'並使用以下方法:

EventBus.$on(CART_CONSTANTS.REFRESH_CART_TOTAL, this.getCartTotal)

和:

EventBus.$emit(CART_CONSTANTS.REFRESH_CART_TOTAL)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM