【问题标题】:How to make a pulldown menu that acts on a selected element?如何制作作用于选定元素的下拉菜单?
【发布时间】:2019-06-20 22:21:34
【问题描述】:

TL;TR

我该怎么做:

getMyComponent(selectedMyComponentID).complexOperation()

对我来说,这听起来像是一件微不足道而有用的事情,例如从下拉菜单中。

更多细节

假设我正在制作某种类型的编辑器(想想 todo-list 什么的)。 GUI 具有“选定”元素的概念。 (在我们的实际案例中,它是当前可见的bootstrap nav-tab),并且我想要具有对所选元素执行不同操作的菜单项的下拉菜单。

假设我有“选定”组件的 id,获取对具有与该 id 对应的 complexOperation() 方法的 MyComponent 的引用非常困难。

也许那是因为我没有这样做“Vue 方式”。

我看到了这些方法来完成complexOperationOnSelectedMyComponent()

  • 使用refs - 看起来又乱又丑
  • 将MyComponent中的complexOperation()重构为一个新的MyData,这样App.vue和MyComponent.vue都会用到数据上的业务逻辑。现在父母正在改变数据,因此道具 - 听起来像 vue-ish。但这会导致大量样板文件,因为每个组件中的每个操作现在都有两个版本。我不喜欢样板和重复...
  • 使用 vuex?我想我还没有……
  • 使用“事件总线”Vue 实例并从父级到子级使用 $emit 事件。似乎矫枉过正。而且很乱,有样板。

我错过了什么吗?这不是很标准的东西吗?

详情

为简单起见,我们会说有一个模板:

<template>
  <div id="app">
    <div v-for="elem in mydata" :key="elem.id" @click="setSelected(elem)">
      <MyComponent :value="elem"/>
    </div>
    <button @click="complexOperationOnSelectedComponent">
        Complex operation on Selected Component
    </button>
  </div>
</template>

以及最初选择第一个的数据结构:

data() {
  return {
    mydata: [
      { id: 0, foo: "bar", selected: true },
      { id: 1, foo: "baz", selected: false },
      { id: 2, foo: "world", selected: false }
    ]
  };
}

(填写codesandbox

所以有一个“对选定组件的复杂操作”按钮。但是我应该在complexOperationOnSelectedComponent 方法中放入什么?

上面的代码框在每个 MyComponent 中也有等效的按钮。他们只是在 MyComponent 定义中调用 complexOperation() 方法。

我认为按钮是在组件内部还是外部是一个小细节。获取对所选 id 的 MyComponent 的引用,并在菜单项的 @click 处理程序中调用 selectedComponent.complexOperation()

在我们的真实场景中,用户通过点击导航栏(不是在 MyComponent 实例上)选择“组件”,所以我们拥有的是一个 id(mydata[n].id 或上面的 0、1 或 2) .

使用 ref-s

我能做的就是将ref="components" 放入&lt;MyComponents&gt; 定义中。因为它在v-for 循环中,所以this.$refs.components 将是MyComponents 的数组。找到具有正确 id 的那个并使用它。

因为无法保证this.$refs.components 中的顺序,我每次都必须在数组中搜索 selectedMyComponentID,但是嘿...

这真的是最好的解决方案吗?

【问题讨论】:

  • 你可以绑定一个动态的ref并使用选中的组件的id,比如:ref="'mycomponents' + elem.id"
  • 谢谢,这比我的ref="components" 解决方案效果更好,即使this.$refs.mycomponents1 仍然是一个包含单个元素的数组。

标签: vue.js vuejs2


【解决方案1】:

如果您需要直接访问 DOM 以获取未连接/控制到任何 Vue 实例属性的元素,您通常希望使用 $refs。 您可以将选择的元素存储在数据中,并以该特定元素为目标。

将您的方法放在父母或孩子身上?这取决于,您是否需要其他地方的逻辑?在这种情况下,我认为这对孩子来说是有意义的,因为您也希望能够在那里执行操作。

Use an "event bus" Vue instance and $emit events from parent to child. Seems overkill.

道具从父母传给孩子。事件从子级发送到父级。 Vuex 和事件总线在大型应用程序中非常有用,但在这种情况下确实不需要。但是,您应该发出您想要对道具进行的更改,而不是像现在在 MyComponent 中那样直接编辑它们。

我稍微重构了你的代码,我想重申一下,直接修改 props 的值是不好的做法:https://codesandbox.io/s/button-onclick-on-selected-child-lf37c?fontsize=14

<template>
  <div id="app">
    <div v-for="elem in mydata" :key="elem.id" @click="selectedElem = mydata[elem.id]">
      <MyComponent :value="elem" :reverse="elem.reverse"/>
    </div>
    <button @click="reverseSelectedFoo">Reverse Selected Foo</button>
  </div>
</template>

<script>
import MyComponent from "./components/MyComponent";

export default {
  name: "App",
  data() {
    // Ideally this data is read from an API somewhere
    return {
      mydata: [
        { id: 0, foo: "bar", reverse: false },
        { id: 1, foo: "baz", reverse: false },
        { id: 2, foo: "world", reverse: false }
      ],
      selectedElem: null
    };
  },
  methods: {
    reverseSelectedFoo() {
      this.selectedElem.reverse = !this.selectedElem.reverse;
    }
  },
  components: {
    MyComponent
  }
};
</script>

【讨论】:

  • 感谢您的回答。我明确地调用了操作complexOperation() 来暗示它不能被建模为对象中单个布尔键的翻转。我希望逻辑存在于 My(Component|Data|Whatever) 特定对象中。我不希望父母知道该子域的内部运作。如果 MyComponent 不能修改 any 给定它的 props 中的数据,那么,哦,我的……难道应用程序的所有逻辑都不会最终存在于顶层 App.vue 中如果我把这件事放在心上?
  • 如果这个“不要修改内部道具”真的是真的,那么我将在哪里曾经在 Hello World 微型演示之外使用v-model,假设应用程序的状态很有用,需要在某个时候保存吗?
  • 我明确地调用了操作 complexOperation() 来暗示它不能被建模为对象中单个布尔键的翻转:好的,但我只能按照您提供的代码进行操作。如果你的 myComponent 中有一个函数需要调用以响应用户交互,你必须告诉你的组件。你如何做到这一点取决于你。在您的示例中,它是一个布尔值,但您可以传递任何内容。
  • 在任何比 Hello World 演示稍大的应用程序中,直接改变父级的状态确实会有问题,因为它几乎无法调试。处理v-model 和props 的一个好方法是将组件中的一个属性初始化为prop 并将v-model 绑定到本地属性。然后你可以$emit它返回给父母。
猜你喜欢
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多