【问题标题】:How to share methods between unrelated components in Vue?如何在 Vue 中不相关的组件之间共享方法?
【发布时间】:2021-01-05 04:57:43
【问题描述】:

我可能缺少 VueJS 的一些概念,所以我需要这方面的帮助。我做了一个example 让我的问题更清楚。假设我有一些多功能组件,例如modal 窗口。我正在从 Vuex 获取数据。

./components/modal.vue

<script>
export default {
  methods: {
    modalClose() {
      this.$store.commit("modalClose");
    },
  },
  computed: {
    body() {
      return this.$store.state.modal.body;
    },
    footer() {
      return this.$store.state.modal.footer;
    },
    show() {
      return this.$store.state.modal.show;
    },
  },
};
</script>

<template>
  <div class="wrap" @click.self="modalClose" v-if="show">
    <div id="modal" class="modal">
      <div class="modal-body" v-html="this.body">body</div>
      <div class="modal-footer" v-html="this.footer">footer</div>
    </div>
  </div>
</template>

<style>
/* whatever */
</style>

我有another component,它设置了 Vuex 数据并使用我的模态组件来显示数据。它工作正常 - 它呈现数据。但在某些时候,我需要处理模态窗口中的数据,而这正是我丢失它的地方。

./components/persons.vue


<script>
export default {
  data: function () {
    return {
      persons: [
        { name: "John Johnson", id: 1 },
        { name: "David Lynch", id: 2 },
        { name: "Marshall Attack", id: 3 },
      ],
    };
  },
  methods: {
    showModal: function (person) {
      this.$store.commit("modal", {
        body: "Name: " + person.name,
        footer: `<a href="#" person-id="${person.id}">Add</a>`,
      });
    },
    addPerson: function (id) {
      // how to trigger this function with "Add" button?
      console.log("Success! Person " + id + " was added!");
    },
  },
};
</script>
<template>
  <div id="page1">
    <div v-for="person in persons" :key="person.id">
      {{ person.name }}
      <a href="#" @click="showModal(person)"> Open modal </a>
    </div>
  </div>
</template>

在这个例子中你可以看到方法addPerson。它属于persons.vue,它应该通过单击模态窗口内的“添加”按钮来执行(需要参数)。所以,我有两个问题:

  1. 我该怎么做?
  2. 我是否在灌输不良做法?

P.S.我读到了$emit,但我没有任何运气。

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    我没有完全理解您的问题,但基本思想是各种组件可以将数据提交到您的商店。并且还派发动作到存储。并且存储本身应该能够使用已经提交的数据来处理像addPerson 这样的操作。通常在“创建”条目的多个组件的情况下,您的商店(或商店模块)将拥有

    • 具有相关条目的状态,例如在一般 CRUD 中,它通常是一个由 peoplenewPerson 组成的数组,用于存储临时条目
    • 允许编辑部分数据的突变
    • 一个 getter canAddPerson 计算 newPerson 对象中是否有足够的数据来实际创建一个新人
    • 使用newPerson 的操作addPerson,可选择执行AJAX POST,提交要包含在人员数组中的新人员并清除newPerson 字段。

    我偶尔会遇到的一个警告是,这个 newPerson 不应该是 {},而是应该使用所有字段 {name: null, height: null, ...} 定义,否则这些字段将不会是响应式的。

    我是否在灌输不良做法?

    你不应该把 HTML 放在商店里,只是数据。

    附:标题中问题的答案是“mixins”,但我认为这不是您在问题正文中提出的问题。

    【讨论】:

    • 对不起,我是 Vue 的新手,所以我可能会出错。 Add 按钮只是按钮的随机名称。我真正希望它了解如何通过在模态窗口内单击来触发addPerson 函数。
    • 我的意思是 addPerson 函数应该是你商店中的一个动作(参见 Vuex 动作)。然后你只需向按钮添加一个@click="$store.dispatch('addPerson')" 属性,它就会被调用。
    • 绝对不要把html放到商店里,+1
    • 我可以阅读任何约定以了解更多信息吗?
    【解决方案2】:

    这里有很多剥猫皮的方法。

    1. 模态组件将自己的数据写入存储。

    由于模态已经从存储中读取数据,您也可以直接从模态中设置存储值。创建一个执行此操作的新方法。这里的好处是模态可以读取和写入自己的数据。缺点是模式现在与您应用中的某种类型的数据相关联,并且通常不可重用。

    1. 来自persons.vue$emit

    当某个事件发生时,您的模态应该$emit,例如当用户单击“添加”时。无论您在哪里定义了该链接,都将@click="$emit('add', whateverDataYouWantToReturn)" 添加到其中。然后在父组件中,使用模态时使用@add="addPerson($event)" 监听事件。这里的好处是您不一定需要使用商店;您可以将数据作为props 传递给模态,并使用$emit 捕获事件。

    1. 在模态框上使用slot

    每当您在父模板中使用模态框时,您都可以在模态框内插入您需要的任何视觉内容,这些内容提供给模态框的插槽。这样做的好处是保持模态组件通常可重用,同时还允许您调用父级上的方法。

    【讨论】:

    • 我分叉了演示代码并实现了您的第一个建议,如下所示:codesandbox.io/s/dark-flower-36fcv 在此实现中,我将模式窗口的按钮作为对象存储在 Vuex 商店中,并在 modal.vue 中使用 @ 监听点击事件987654332@ 方法。这就是你的意思吗?它的功能有限,但可以工作。
    • 我也看不出在这种情况下我们如何使用slot(建议#3)。我特别指出,两个(或更多)组件假设是不相关的。
    • 您在 footer 计算属性中做了很多不必要的工作,可以直接在模板中使用 v-for 轻松处理。只需将@click="" 直接添加到您使用v-for 渲染的元素。
    • 带有插槽的组件非常适合包装需要父作用域的通用/不相关内容。例如您的模态模板可以简单地为&lt;template&gt;&lt;div class="modal"&gt;&lt;slot&gt;&lt;/slot&gt;&lt;/div&gt;&lt;/template&gt;,并让父级使用&lt;modal&gt;your content here&lt;/modal&gt;
    【解决方案3】:

    看起来很糟糕的钩子。

    通常: modal.vue 在persons.vue里面 那么在数据属性中modal show必须为false后(modalShow:false)

    如果显示带有所选数据的模态,则必须向模态组件发送“道具”。

    【讨论】:

    • 实际上我想过,但后来我阅读了引导文档,它指出:“模态使用位置:固定,有时可能对其呈现有点特殊。只要有可能,放置模态 HTML在顶级位置,以避免来自其他元素的潜在干扰。在另一个固定元素中嵌套 .modal 时,您可能会遇到问题。"
    • "在另一个固定元素中嵌套 .modal 时,您可能会遇到问题。"不是为了地位。模态必须在父组件内。如主组件->模态组件。所以数据钩子必须是带有道具的模态的主要内容。在你了解我之后研究 Vue 文档中的道具
    猜你喜欢
    • 2020-10-21
    • 2021-10-12
    • 2016-05-04
    • 1970-01-01
    • 2021-06-24
    • 2018-05-15
    • 2020-09-23
    • 1970-01-01
    相关资源
    最近更新 更多