【问题标题】:How do I make a child component just run if click a link on the vue component?如果单击 vue 组件上的链接,如何使子组件运行?
【发布时间】:2018-09-13 12:12:04
【问题描述】:

我有两个组件

我的第一个组件(父组件)是这样的:

<template>
    <ul class="list-group">
        <li v-for="item in invoices" class="list-group-item">
            <div class="row">
                ...
                <div class="col-md-7">
                    ...
                    <a href="javascript:"
                       class="toggle-show"
                       aria-expanded="false"
                       data-toggle="collapse"
                       :data-target="'#' + item.id"
                       @click="show(item.id)">
                        Show <span class="caret"></span>
                    </a>
                </div>
            </div>
            <div class="collapse" :id="item.id">
                <order-collapse/>
            </div>
        </li>
    </ul>
</template>
<script>
    import orderCollapse from './orderCollapse.vue'
    export default {
        ...
        components: {orderCollapse},
        data() {
            return {
                invoices: [
                    {
                        id: 1,
                        ...
                    },
                    {
                        id: 2,
                        ...
                    },
                    {
                        id: 3,
                        ...
                    }
                ]
            }
        },
        methods: {
            show(id) {
                // orderCollapse executed if this method run
            }
        },
    }
</script>

我的第二个组件(子组件)是这样的:

<template>
    <table class="table table-bordered table-collapse">
        <!-- this is used to display detail by id -->
    </table>
</template>
<script>
    export default {
        name: 'order-collapse',
        ...
    }
</script>

如果父组件执行了,子组件也会自动执行

我要如果父组件执行,子组件不执行

如果用户点击显示链接,我希望子组件执行

我该怎么做?

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-component vuex


    【解决方案1】:

    如何创建一个属性 (displayedIds) 来保存每个 order-collapse 的显示状态,然后使用 v-if 调节它们的显示:

    <div ... v-if="displayedIds[item.id]">
        <order-collapse :id="item.id"></order-collapse>
    </div>
    

    并且,考虑到 displayedIds 最初声明为 {},您将拥有 show() 方法:

      methods: {
        show(id) {
            // orderCollapse executed if this method run
            this.$set(this.displayedIds, id, true); // use $set to be reactive
        }
      },
    

    演示:

    Vue.component('order-collapse', {
      template: "#oc",
      name: 'order-collapse',
      props: ['id'],
      mounted() {
        console.log('order-collapsed mounted for id', this.id);
      }
    });
    
    new Vue({
      el: '#app',
      data() {
        return {
          displayedIds: {},
          invoices: [{id: 1},{id: 2},{id: 3}]
        }
      },
      methods: {
        show(id) {
          // orderCollapse executed if this method run
          this.$set(this.displayedIds, id, true);
        }
      },
    })
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    
    <div id="app">
        <ul class="list-group">
            <li v-for="item in invoices" class="list-group-item">
                <div class="row">
                    ...
                    <div class="col-md-7">
                        ...
                        <a href="javascript:"
                           class="toggle-show"
                           aria-expanded="false"
                           data-toggle="collapse"
                           :data-target="'#' + item.id"
                           @click="show(item.id)">
                            Show <span class="caret"></span>
                        </a>
                    </div>
                </div>
                <div class="collapse" :id="item.id" v-if="displayedIds[item.id]">
                    <order-collapse :id="item.id"></order-collapse>
                </div>
            </li>
        </ul>
    </div>
    
    <template id="oc">
        <table class="table table-bordered table-collapse">
            <!-- this is used to display detail by id -->
            <tr>
              <td>ID: {{ id }}</td>
            </tr>
        </table>
    </template>


    另一种可能性是将displayedIds 作为一个数组 而不是一个对象。这样你就不能使用$set,只能使用普通的.push()

    methods: {
      show(id) {
        // orderCollapse executed if this method run
        this.displayedIds.push(id);
      }
    },
    

    并使用.includes()调整显示:

    <div ... v-if="displayedIds.includes(item.id)">
        <order-collapse :id="item.id"></order-collapse>
    </div>
    

    演示:

    Vue.component('order-collapse', {
      template: "#oc",
      name: 'order-collapse',
      props: ['id'],
      mounted() {
        console.log('order-collapsed mounted for id', this.id);
      }
    });
    
    new Vue({
      el: '#app',
      data() {
        return {
          displayedIds: [],
          invoices: [{id: 1},{id: 2},{id: 3}]
        }
      },
      methods: {
        show(id) {
          // orderCollapse executed if this method run
          this.displayedIds.push(id);
        }
      },
    })
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    
    <div id="app">
        <ul class="list-group">
            <li v-for="item in invoices" class="list-group-item">
                <div class="row">
                    ...
                    <div class="col-md-7">
                        ...
                        <a href="javascript:"
                           class="toggle-show"
                           aria-expanded="false"
                           data-toggle="collapse"
                           :data-target="'#' + item.id"
                           @click="show(item.id)">
                            Show <span class="caret"></span>
                        </a>
                    </div>
                </div>
                <div class="collapse" :id="item.id" v-if="displayedIds.includes(item.id)">
                    <order-collapse :id="item.id"></order-collapse>
                </div>
            </li>
        </ul>
    </div>
    
    <template id="oc">
        <table class="table table-bordered table-collapse">
            <!-- this is used to display detail by id -->
            <tr>
              <td>ID: {{ id }}</td>
            </tr>
        </table>
    </template>


    最后,如果你觉得更容易推理,display 标志可以在每个 item 本身中,作为一个属性

    在这种情况下,show 应该接收整个item(不仅仅是item.id):

    <a ... @click="show(item)">
    

    显示将只使用item.displayed:

    <div ... v-if="item.displayed">
        <order-collapse :id="item.id"></order-collapse>
    </div>
    

    以及方法:

    methods: {
      show(item) {
        // orderCollapse executed if this method run
        this.$set(item, 'displayed', true);
      }
    },
    

    演示:

    Vue.component('order-collapse', {
      template: "#oc",
      name: 'order-collapse',
      props: ['id'],
      mounted() {
        console.log('order-collapsed mounted for id', this.id);
      }
    });
    
    new Vue({
      el: '#app',
      data() {
        return {
          invoices: [{id: 1},{id: 2},{id: 3}]
        }
      },
      methods: {
        show(item) {
          // orderCollapse executed if this method run
          this.$set(item, 'displayed', true);
          // you could use `item.displayed = true` if you declared `displayed: false` in each item at data
        }
      },
    })
    <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
    
    <div id="app">
        <ul class="list-group">
            <li v-for="item in invoices" class="list-group-item">
                <div class="row">
                    ...
                    <div class="col-md-7">
                        ...
                        <a href="javascript:"
                           class="toggle-show"
                           aria-expanded="false"
                           data-toggle="collapse"
                           :data-target="'#' + item.id"
                           @click="show(item)">
                            Show <span class="caret"></span>
                        </a>
                    </div>
                </div>
                <div class="collapse" :id="item.id" v-if="item.displayed">
                    <order-collapse :id="item.id"></order-collapse>
                </div>
            </li>
        </ul>
    </div>
    
    <template id="oc">
        <table class="table table-bordered table-collapse">
            <!-- this is used to display detail by id -->
            <tr>
              <td>ID: {{ id }}</td>
            </tr>
        </table>
    </template>

    推荐哪种方法?归结为品味。如果您可以/不介意将 displayed 属性附加到每个项目,我认为这是最简单的解决方案。否则我会选择第一个(displayedIds 作为对象),除非它给你带来麻烦,在这种情况下我会选择数组解决方案。

    【讨论】:

    猜你喜欢
    • 2017-12-19
    • 2017-06-21
    • 2018-06-19
    • 2018-09-05
    • 2017-12-16
    • 2018-09-03
    • 2021-06-11
    • 1970-01-01
    • 2018-08-11
    相关资源
    最近更新 更多