简体   繁体   English

Vuejs2多个实例之间调用方法和更新组件

[英]Call method and update component between Vuejs2 multiple instances

I have index.html我有索引。html

<!DOCTYPE html>
<html lang="en">
<body>
<div id="appOne">
</div>
<div id="appTwo">
</div>
</body>
</html>

And 2 Vue instances in different files:以及不同文件中的 2 个 Vue 实例:

//appOne.js
import Vue from 'vue';
import AppOne from "./AppOne.vue";

new Vue({
    render: h => h(AppOne),
}).$mount('#appOne')
//appTwo.js
import Vue from 'vue';
import AppTwo from "./AppTwo.vue";

new Vue({
    render: h => h(AppTwo),
}).$mount('#appTwo')

And components:和组件:

//AppOne.vue
<template>
  <component-one/>
</template>

<script>
import ComponentOne from "./components/ComponentOne.vue";

export default {
  name: "AppOne",
  components: {ComponentOne}
}
</script>
//AppTwo.vue
<template>
  <component-two/>
</template>

<script>
import ComponentTwo from "./components/ComponentTwo.vue";

export default {
  name: "AppTwo",
  components: {ComponentTwo}
}
</script>
//components/ComponentOne.vue
<template>
  <div>
    <div>
      <button @click="foo(counter)">ComponentOne</button>
      <div>{{ label }}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: "ComponentOne",
  data() {
    return {
      counter: 1,
      label: "default"
    }
  },
  methods: {
    foo: function (id) {
      this.label = id
    }
  }
}
//components/ComponentTwo.vue
<template>
  <div>
    <div>
      <button @click="updateComponentOne">ComponentTwo</button>
    </div>
  </div>
</template>

<script>
export default {
  name: "ComponentTwo",
  methods: {
    updateComponentOne: function () {
      //update componentOne.label and do some additional logic
    }
  }
}
</script>

Question: Click on ComponentTwo button and in method updateComponentOne update data in ComponentOne and do some additional logic问题:单击 ComponentTwo 按钮并在方法updateComponentOne中更新 ComponentOne 中的数据并执行一些附加逻辑

I tried:我试过了:

  1. EventBus = new Vue() and emit and subsribe on event. EventBus = new Vue() 并发出和订阅事件。 Result: event is received on component one but data is not updated (I guess because of this reference scope)结果:在组件一上收到事件但数据未更新(我猜是因为this参考范围)
  2. mitt library - same as above手套库 - 与上面相同
  3. export const state = Vue.observable(initialState), update state in component two and see how it affects computed property on component one export const state = Vue.observable(initialState),更新组件二中的 state,看看它如何影响组件一的计算属性
  computed: {
    someStateThatShouldBeChanged(): {
      return state.initialState
    }
  }

also does not work.也不起作用。

  1. Custom Event bus, smth like:自定义事件总线,例如:
class Event {
    constructor() {
        this.events = {};
    }

    on(eventName, fn) {
        this.events[eventName] = this.events[eventName] || [];
        this.events[eventName].push(fn);
    }

    emit(eventName, data) {
        if (this.events[eventName]) {
            this.events[eventName].forEach(function (fn) {
                fn(data);
            });
        }
    }
}

export default new Event();

Works as in the 1st case.像第一种情况一样工作。

  1. Tried to use vm variables directly:尝试直接使用vm变量:
export const vm1 = new Vue({
    render: h => h(AppTwo),
})
and after that tried to change data directly: 
vm1.someData = 'newValue'

Also does not work也不起作用

I'm confused, please help me to understand why all these options do not work and how to fix it.我很困惑,请帮助我理解为什么所有这些选项都不起作用以及如何解决它。

Two unrelated instance is pretty isolate and can't access to each others.两个不相关的实例非常孤立,无法相互访问。

Most people in this scenario will create an instance and set AppOne and AppTwo as its components.在这种情况下,大多数人会创建一个实例并将AppOneAppTwo设置为其组件。 After than you can using $emit to pass event to main instance from AppTwo 's updateComponentOne function and let main instance to call AppOne by $refs and change value.之后,您可以使用$emit将事件从AppTwoupdateComponentOne function 传递给主实例,并让主实例通过$refs调用AppOne并更改值。

But I can only assume you have your reason to keep those App isolate, but it's okay - I still have some trick can achieved it.但我只能假设您有理由将这些 App 隔离,但没关系 - 我仍然有一些技巧可以实现它。


First: merge appOne.js and appTwo.js into something like this:首先:将appOne.jsappTwo.js合并成这样的:

import Vue from 'vue';
import AppOne from "./AppOne.vue";
import AppTwo from "./AppTwo.vue";

const InstanceOne = new Vue({
    render: h => h(AppOne),
}).$mount('#appOne')

const InstanceTwo = new Vue({
    render: h => h(AppTwo),
}).$mount('#appTwo')

InstanceTwo.$el.addEventListener('someCustomEventName', event => {
    // // you can get custom event payload by `event.detail`
    // console.log(event.detail);

    InstanceOne.someUpdateValueFunction();
});

Second: Adjust AppTwo.vue And components/ComponentOne.vue :第二:调整AppTwo.vuecomponents/ComponentOne.vue

//components/ComponentTwo.vue
<template>
  <div>
    <div>
      <button @click="$emit('updateComponentOne', {thisIsPayloadKey: 'thisIsValue'})">ComponentTwo</button>
    </div>
  </div>
</template>

<script>
export default {
  name: "ComponentTwo"
}
</script>
//AppTwo.vue
<template>
  <component-two updateComponentOne="updateComponentOne"/>
</template>

<script>
import ComponentTwo from "./components/ComponentTwo.vue";

export default {
  name: "AppTwo",
  components: {ComponentTwo},
  method: {
      updateComponentOne(detail) {
          const event = new CustomEvent("someCustomEventName", { detail });
          this.$el.dispatchEvent(event);
      }
  }
}
</script>

Result结果

Your ComponentTwo will trigger a $emit to AppTwo.vue and pass value you need in a object.您的ComponentTwo将触发$emitAppTwo.vue并在 object 中传递您需要的值。 Your AppTwo will dispatch a custom event to himself.您的AppTwo将向自己发送一个自定义事件。

Due to we already add a event listener, so we can aware when this custom event be trigger and execute whatever we want in that event listener.由于我们已经添加了一个事件侦听器,因此我们可以知道何时触发此自定义事件并在该事件侦听器中执行我们想要的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM