如何制作对选定元素起作用的下拉菜单?

时间:2019-06-20 22:21:34

标签: vue.js vuejs2

TL; TR

我如何:

getMyComponent(selectedMyComponentID).complexOperation()

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

更多细节

假设我正在做某种类型的编辑器(想想待办事项列表之类的东西)。 GUI具有“选定”元素的概念。 (在我们的实际情况下,它是当前可见的bootstrap nav-tab),我想要具有菜单项的下拉菜单,这些菜单项对所选元素执行不同的操作。

假设我具有“选定”组件的ID,那么对MyComponent的引用就很难了。该MyComponent具有与ID对应的complexOperation()方法。

也许是因为我没有采用这种“ Vue方式”。

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

  • 使用ref s-看起来很凌乱和丑陋
  • complexOperation()从MyComponent重构到新的MyData中,因此数据上的业务逻辑将由App.vue和MyComponent.vue使用。现在,父母正在更改数据,因此正在更改道具-听起来有些虚幻。但这会导致大量样板,因为每个组件中的每个操作现在都有两个版本。我不喜欢样板和重复...
  • 使用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方法中放什么呢?

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

我在想按钮是恰好位于组件内部还是外部都是次要的细节。获取对所选ID的MyComponent的引用,然后在菜单项的selectedComponent.complexOperation()处理程序中调用@click

在我们的实际情况中,用户通过单击导航栏(而不是MyComponent实例)来选择“组件”,因此我们拥有的是id(mydata[n].id或0、1或2以上)。

使用ref-s

我可以做的是将ref="components"放在<MyComponents>定义中。由于它处于v-for循环中,因此this.$refs.components将是MyComponents的数组。找到具有正确ID的ID并使用它。

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

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

1 个答案:

答案 0 :(得分:0)

如果您需要直接访问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>