【问题标题】:How to trigger component events from any other component in the app using vue.js?如何使用 vue.js 从应用程序中的任何其他组件触发组件事件?
【发布时间】:2019-12-22 04:26:11
【问题描述】:

我有一个组件(倒数计时器)将在网站的所有页面上运行。它在顶级 App.vue 文件中被引用。我需要能够从应用程序内的任何其他组件调用该组件内的事件(以重新启动时间),无论它在层次结构链有多深(意思是,我不想通过每个运行事件和 $emit网站上的单个组件用于这件事)。

每当我对服务器进行 ajax 调用时,我都想重置计时器。所以每次点击下面代码中的按钮,我想在倒计时组件上触发startCountdown(true)事件。

Here's a codesandbox example of what I'm doing.

Main.js

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";
import router from "./router/router";
import VueAwesomeCountdown from "vue-awesome-countdown";

Vue.config.productionTip = false;

Vue.use(Vuex);
Vue.use(VueAwesomeCountdown);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  getters: {
    count: state => {
      return state.count;
    }
  },
  mutations: {
    increment: state => state.count++,
    decrement: state => state.count--
  },
  actions: {
    increment: context => {
      context.commit("increment");
    },
    decrement: context => {
      context.commit("decrement");
    }
  }
});

new Vue({
  el: "#app",
  router,
  store,
  template: "<App />",
  components: {
    App
  }
});

App.vue

<template>
  <div id="app">
    <router-link to="/" class="btn bt-link">Page 1</router-link>&nbsp;|
    <router-link to="/Page2" class="btn bt-link">Page 2</router-link>&nbsp;|
    <router-link to="/Page3" class="btn bt-link">Page 3</router-link>
    <hr>
    <br>
    <br>
    <router-view></router-view>
    <br>
    <br>

    <hr>
    <!-- Timer countdown -->
    <countdown ref="sessionTimer" :left-time="99000">
      <span slot="process" slot-scope="{ timeObj }">Session Timer Countdown: {{ timeObj.ceil.s }}</span>
      <span slot="finish">TIMED OUT!</span>
    </countdown>
    <button class="ml-3 btn btn-warning" @click="restart">Manual Restart</button>
    <hr>
    <!-- The below is just show vuex is wired up correctly -->
    <p>This is just to show that Vuex is working properly.</p>
    <p>{{ count }}</p>
    <p>
      <button @click="increment">+</button>
      <button @click="decrement">-</button>
    </p>
  </div>
</template>

<script>
export default {
  name: "App",
  computed: {
    count() {
      return this.$store.getters.count;
    }
  },
  methods: {
    restart() {
      this.$refs.sessionTimer.startCountdown(true);
    },
    increment() {
      this.$store.dispatch("increment");
    },
    decrement() {
      this.$store.dispatch("decrement");
    }
  },
  components: {}
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 20px;
}
</style>

Page2.vue

<template>
  <div>
    <h1>Page 2</h1>
    <br>
    <br>
    <button class="btn btn-success" @click="interactWithServer">Interact with Server 2</button>
    <br>
    <br>
    <SubComponent></SubComponent>
  </div>
</template>

<script>
import SubComponent from "./Page2-SubComponent.vue";

export default {
  methods: {
    interactWithServer() {
      //This function will interact with server but I need to start countdown timer over again first
      //axios call goes here after timer is reset
    }
  },
  components: {
    SubComponent
  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>

Page-SubComponent.vue

<template>
  <div>
    <h3>SUB COMPONENT</h3>
    <br>
    <br>
    <button class="btn btn-primary" @click="interactWithServer">Interact with Server 2.1</button>
  </div>
</template>

<script>
export default {
  methods: {
    interactWithServer() {
      //This function will interact with server but I need to start countdown timer over again first
      //axios call goes here after timer is reset
    }
  }
};
</script>

【问题讨论】:

    标签: javascript vue.js vuejs2 vuex vue-router


    【解决方案1】:

    不确定是否有更短的方法,但您可以在商店中触发一个变量,然后从 App.vue 文件中收听该变量,然后执行 restart 打开那个 .. 这是一个 codesandbox 示例

    // store
    
    state: {
      changed: false
    }
    
    getters: {
      changed: (state) => state.changed
    }
    
    mutation: {
      changed: (state) => state.changed = !state.changed
    }
    
    // App.vue
    
     computed: {
        trigger() {
          return this.$store.getters.changed
        }
      },
      methods: {
        restart() {
          this.$refs.sessionTimer.startCountdown(true);
        }
      },
      watch: {
        trigger() {
          this.restart()
        }
      }
    

    在您的其他组件上:

    interactWithServer() {
      this.$store.commit("changed");
    }
    

    【讨论】:

    • 这对我有用!我希望不必使用观察者,但总比没有好!谢谢!
    【解决方案2】:

    :left-time="99000"中保存定时器的编号,在interactWithServer()中触发事件时保存会不会更好 strong> 重置它?

    Main.js(附加代码)

    state:{
      timer: 99000
    },
    getters: {
      getTimer: state => {
        return state.timer;
      }
    },
    mutations: {
      resetTimer: state => state.timer = 99000
    },
    actions: {
      restartTimer: context => {
        context.commit("resetTimer");
      }
    }
    

    App.vue(修改代码)

    </template>
        <countdown ref="sessionTimer" :left-time="timer">
          <span slot="process" slot-scope="{ timeObj }">Session Timer Countdown: {{ timeObj.ceil.s }}</span>
          <span slot="finish">TIMED OUT!</span>
        </countdown>
    </template>
    <script>
      computed: {
        timer() {
          return this.$store.getters.timer;
        }
      },
    </script>
    

    并在 interactWithServer() 中调用 this.$store.dispatch("restartTimer");

    【讨论】:

    • 我不认为它是这样工作的。简单地更新剩余时间值不会做任何事情。我相信你必须使用组件的 startCountdown(true) 方法。
    猜你喜欢
    • 2017-02-05
    • 2017-08-20
    • 2019-07-20
    • 2022-07-21
    • 2018-04-26
    • 2018-10-21
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多