使用 Vue 的多个模态组件

2022-01-25 00:00:00 php javascript vue.js vue-component

我在 Vue 中实现动态模态组件时遇到问题.

我用来显示从 db 获取的一组数据的常用方法是,我通过遍历 db 结果的每一行来转储 HTML 表格元素中的每一行.像这样:

正如您在屏幕截图中看到的,每一行都有一个或多个由循环动态生成的按钮.为了将模态组件绑定到每个按钮(例如本场景中的删除"按钮),我做了这样的事情.
HTML:

<div id="app"><?php foreach($result as $x): ?><modal v-if="showModal">我是Modal $x</modal><btn @trigger="onShowModal">按钮 $x</btn><?php endforeach;?></div>

因此,如果我的结果中有三行,上述代码块将采用如下形式:

<div id="app"><modal v-if="showModal">我是Modal 1</modal><btn @trigger="onShowModal">按钮 1</btn><modal v-if="showModal">我是Modal 2</modal><btn @trigger="onShowModal">按钮 2</btn><modal v-if="showModal">我是Modal 3</modal><btn @trigger="onShowModal">按钮 3</btn></div>

这是我在 JavaScript 端所做的:

JavaScript:

 Vue.component('btn',{模板:`<button @click="$emit('trigger')"><slot></slot></button>`,});Vue.component('模态',{模板:`<p><slot></slot></p>`,});新的 Vue({埃尔:'#app',数据: {显示模式:假},方法: {onShowModal(){this.showModal = true;}}});

这种方法的问题是,当我单击任何一个删除"按钮时,我会得到一个模态堆栈",而不是我想要查看的模态.那是因为我将 showModal 设置为 true 并且如果您看到填充的 HTML 块,您会看到每个模式都设置为 v-if="showModal".

点击这里查看演示

随着我开始了解前端-后端关系,我了解到这种模式在应用程序中出现得越来越频繁.我该如何解决这个问题(非常适合 vue 初学者)?

解决方案

根本问题是您在所有模态组件上引用相同的数据属性 showModal.

您可以制作另一个组件来封装按钮和模态组件对.这样,每个 modalbtn 对都有一个单独的 showModal 数据属性:

Vue.component('btn',{模板:`<button @click="$emit('trigger')"><slot></slot></button>`,});Vue.component('模态',{模板:`<p><slot></slot></p>`,});Vue.component('modal-btn', {模板:`

<modal v-if="showModal"><slot>我是模态的</slot></模态><btn @trigger="showModal = true">显示模态</btn></div>`,数据() {返回 { 显示模式:假 }}});新的 Vue({埃尔:'#app',数据: {显示模式:假},方法: {onShowModal(){this.showModal = true;}}});

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></脚本><div id="app"><modal-btn></modal-btn><modal-btn>我是另一个模态</modal-btn><modal-btn>我是第三个模态</modal-btn></div>

I am having trouble implementing dynamic modal component in Vue.

A common approach I follow to display a set of data fetched from the db is I dump each of the rows in an HTML table element by iterating over each of the row of the db result. Something like this:

As you can see in the screenshot, each of the rows has one or more buttons which are dynamically generated by the loop. In order to bind a modal component to each of the buttons (say the Remove buttons in this scenario) I do something like this.
HTML:

<div id="app">
    <?php foreach($result as $x): ?>
        <modal v-if="showModal">I am Modal $x</modal>
        <btn @trigger="onShowModal">Button $x</btn>
    <?php endforeach; ?>
</div>

So if I have three rows in my result, the aforementioned block of code will take the shape of something like this:

<div id="app">
        <modal v-if="showModal">I am Modal 1</modal>
        <btn @trigger="onShowModal">Button 1</btn>

        <modal v-if="showModal">I am Modal 2</modal>
        <btn @trigger="onShowModal">Button 2</btn>

        <modal v-if="showModal">I am Modal 3</modal>
        <btn @trigger="onShowModal">Button 3</btn>
</div>

And here is what I do in the JavaScript end:

JavaScript:

    Vue.component('btn',{
      template: `<button @click="$emit('trigger')"><slot></slot></button>`,
    });

    Vue.component('modal',{
      template: `<p><slot></slot></p>`,
    });

    new Vue({
      el: '#app',
      data: {
        showModal: false
      },
      methods: {
        onShowModal(){
          this.showModal = true;
        }
      }
    });

The problem with this approach is, when I click any one of the Remove buttons, I get a 'stack' of modals instead of the modal I wanted to view. And that's because I am setting showModal to true and if you see the populated HTML block you will see that each of the modals is set to v-if="showModal".

Click here to see a demo

And as I am beginning to understand frontend-backend relationship, I am learning that this pattern is appearing more frequently in an application. How do I fix this issue (with a very vue-beginner-friendly level)?

解决方案

The root issue is that you are referencing the same data property showModal on all of the modal components.

You could make another component to encapsulate the button and modal component pair. This way there is a separate showModal data property for each modal and btn pair:

Vue.component('btn',{
  template: `<button @click="$emit('trigger')"><slot></slot></button>`,
});

Vue.component('modal',{
  template: `<p><slot></slot></p>`,
});

Vue.component('modal-btn', {
  template: `
    <div>
      <modal v-if="showModal">
        <slot>I am a modal</slot>
      </modal>
      <btn @trigger="showModal = true">Show Modal</btn>
    </div>
  `,
  data() {
    return { showModal: false }
  }
});

new Vue({
  el: '#app',
  data: {
    showModal: false
  },
  methods: {
    onShowModal(){
      this.showModal = true;
    }
  }
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div id="app">
  <modal-btn></modal-btn>
  <modal-btn>I am another modal</modal-btn>
  <modal-btn>I'm a third modal</modal-btn>
</div>

相关文章