With Vuejs, how to use a modal component inside a v-for loop the right way

拈花ヽ惹草 提交于 2021-01-20 20:07:49

问题


In my vue.js app, I need to display a list of items which the user can click.

When clicked, each of these items should then fire a modal, containing additional information about the item that the user just clicked.

What I have so far in my Items.vue component is:

<template>
    <div id="content">
        <li v-for="item in items" class="list-item pa2 ba">
            <div class="f5 pt2 pb2">
                <span>{{item.name}}</span>
            </div>
        </li>
    </div>
</template>

<script>
    import Items from '@/api/items';

    export default {
        name: 'items',
        asyncComputed: {
            items: {
                async get() {
                    const items = await Items.getAll();
                    return items.data;
                },
                default: []
            }
        },
        components: {}
    }
</script>

Now, I could simply add a modal component to the v-for loop, thus creating one modal for each item, but this does not seem ideal if, for example, I have a list of thousands of items.

This led me to believe that the modal should probably be placed at the root of the app (in my case App.vue), like this:

<template>
    <div id="app">
        <modal></modal>
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name: 'app'
    }
</script>

and then somehow fired with custom data whenever I needed it.

However, I'm not sure how to proceed. How do I fire this modal with custom information from inside the v-for loop, which is in a child component relative to App.vue?


回答1:


These two links helped me figure this out:

  • https://vuejs.org/v2/examples/modal.html

  • https://laracasts.com/discuss/channels/vue/passing-data-form-v-for-loop-to-modal-component

#In your Parent Component You don't have to create a modal for each item within the v-for loop, simply include the modal-component at the beginning of your parent and then work with v-if="..." and props.

<template>
  <div>
    <modal v-if="modalVisible" @close="modalVisible = false" :data="modalData"/>

    <div v-for="item in items">
      <button type="button" @click="openModal(item)">Open Modal</button>
    </div>

  </div>
</template>

and then in your script:

import modal from './Modal'

export default {
  components: {
    modal
  },
  data() {
    return {
      modalVisible: false,
      modalData: null
    }
  },
  methods: {
    openModal(data) {
      this.modalData = data
      this.modalVisible = true
    },
  }

#In your child (modal) component In your modal you can now do the following:

Template:

<template>
    {{ data.foo }}
    <button @click="$emit('close')">Cancel</button>
</template>

Script

<script>
  export default {
    props: ['user']
  };
</script>

Hope that helps :-)




回答2:


While the accepted answer is great but the modal component has to be designed only for that specific data and it's not reusable.

Here is how I created a reusable modal regardless of data and style :

Modal Component:

<template>
    <div  v-if="visible" class="modal-container">
          <!--  Modal content goes here -->
          <slot></slot>
          <button  @click="close">close</button>
        </div>
      </div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            visible : false
        }
    },
    methods : {
        show(index){
            this.visible = true
        },
        close(){
            this.visible = false
        }
    }
}
</script>

<style>
   // general styles for modal
.modal-container{
}
<style/>

Usage In Parent Component:

<template>
 <ul>
      <li v-for="(item, index) in myList" :key="index">
        <button @click="showModal(index)">Show Modal</button>
        <modal :ref="'modal_' + index">
             <!-- modal content goes here -->
             <div>{{ item.title }}</div>
             <div>{{ item.content }}</div>
        </modal>
      </li>
</ul>
</template>

<script>
import Modal from "./Modal";

export default {
  data(){
     return {
        myList : [
          { title : "title1", content : "content1"},
          { title : "title2", content : "content2"},
        ]
     }
  },
  components: {
    Modal
  },
  methods: {
    showModal(index) {
      let modal_id = "modal_" + index;
      this.$refs[modal_id][0].show(index);
    }
  }
};
</script>


来源:https://stackoverflow.com/questions/46618266/with-vuejs-how-to-use-a-modal-component-inside-a-v-for-loop-the-right-way

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!