【问题标题】:Accessing child component data in view访问视图中的子组件数据
【发布时间】:2018-03-17 08:43:02
【问题描述】:

目前我将 Laravel 5.2 与 Elixir 5 和 Vue 2.0 一起使用。

我不知道如何使用 v-if 之类的东西从元素视图访问和导入组件的数据。

这是我的设置:

资源\视图\vuetest.blade.php

<div id="app">
    <modal v-if="showModal"></modal>

    <button>Show Modal</button>
</div>

资源\资产\vuejs\app.js

import Vue from 'vue';
import Modal from './components/modals/show-modal.vue';
Vue.component('modal', Modal);

if (document.getElementById("app")){
    var app = new Vue({
        el: '#app',

        data: {

        },

        methods: {

        },

        computed: {

        },

        components: {
            'modal': Modal
        }

    });

    window.vue = app;
}

resources\assets\vuejs\components\modals\show-modal.vue

<template>
    <div id="myModal" class="modal fade" role="dialog">
    <div class="modal-dialog">

    <!-- Modal content-->
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal">&times;</button>
        <h4 class="modal-title">Modal Header</h4>
      </div>
      <div class="modal-body">
        <p>Some text in the modal.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
      </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                showModal: false
            }
        },

        components: {

        },
    }
</script>

现在,如果我在没有 v-if 的情况下使用它,那么它可以正常工作并正确拉入模板。

但是,如果我使用示例中的内容,则会出现错误:

app.js:967 [Vue warn]: Property or method "showModal" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.

(found in <Root>)

如果我在主 app.js 中添加数据,它可以访问它,但不能在导入的子组件中访问。我宁愿不要让主 app.js 变得凌乱,最好使用导入并将组件保存在有组织的子文件夹中。如何正确访问这些子组件数据?

【问题讨论】:

    标签: php laravel laravel-5 vue.js vuejs2


    【解决方案1】:

    如果要改变子组件的状态,可以在组件上设置ref,直接访问属性。

    在这个例子中,ref 被设置在每个模态组件上。

    <bootstrap-modal ref="modal1">
    

    然后,要更改引用组件中的数据值,只需像设置任何其他 javascript 值一样设置它。

     <button type="button" class="btn btn-primary" @click="$refs.modal1.visible = true">Show Modal One</button>
    

    console.clear()
    
    const BootstrapModal = {
      template: "#modal-template",
      data() {
        return {
          visible: false
        }
      },
      watch: {
        visible(show) {
          if (show) $(this.$el).modal('show')
          else $(this.$el).modal('hide')
        }
      },
      mounted() {
        // listen for the close event
        $(this.$el).on("hidden.bs.modal", () => {
          this.visible = false
        })
      }
    }
    
    new Vue({
      el: "#app",
      components: {
        BootstrapModal
      }
    })
    <script src="https://unpkg.com/vue@2.4.2"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
    
    <div id="app">
      <button type="button" class="btn btn-primary" @click="$refs.modal1.visible = true">Show Modal One</button>
      <bootstrap-modal ref="modal1">
        <span slot="title">Modal One</span>
        <p slot="body">Modal One Content</p>
      </bootstrap-modal>
      <button type="button" class="btn btn-success" @click="$refs.modal2.visible = true">Show Modal Two</button>
      <bootstrap-modal ref="modal2">
        <span slot="title">Modal Two</span>
        <p slot="body">Modal Two Content</p>
      </bootstrap-modal>
    </div>
    
    <template id="modal-template">
      <div class="modal fade">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title"><slot name="title">Modal Title</slot></h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-body">
            <slot name="body"><p>Modal Body</p></slot>
          </div>
          <div class="modal-footer" v-if="$slots.footer">
            <slot name="footer"></slot>
          </div>
        </div>
      </div>
    </div>
    </template>

    【讨论】:

    • 这效果很好,让我在了解 Vue 的过程中对未来如何处理不同的事情有了一些了解。我猜我只是走错路了。
    • @dmotors 我们都在学习 :) 在许多情况下,按照其他答案的建议并使用组件的属性来指示模态应该如何显示是很有用的,但你是对的,本质上,组件的 state 并没有真正包含在模态中。
    • 感谢您的帮助。是的,其他示例有效,但我从一开始就主要关注的是有一个干净的 app.js 仅引用导入的组件,而在需要时访问子组件时没有其他内容。正如我之前所说,如果有 100 个组件和每个至少 1 个属性,那么 app.js 看起来会非常混乱和庞大。
    【解决方案2】:

    不确定是否是最好的方法,但我在以下帮助下找到了答案: VueJS access child component's data from parent

    我所做的是在我的子组件中添加以下内容:

    <template>
        <div>
            <div id="myModal" class="modal fade" role="dialog">
            <div class="modal-dialog">
    
            <!-- Modal content-->
            <div class="modal-content">
              <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title">Modal Header</h4>
              </div>
              <div class="modal-body">
                <p>Some text in the modal.</p>
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
              </div>
            </div>
        </div>
    </template>
    
    <script>
        export default {
            data: function () {
                return {
                    showModal: false
                }
            },
    
            components: {
    
            },
        }
    </script>
    

    然后在我的 vuetest.blade.php 我把这个:

    <div id="app">
        <modal v-if="modalData.showModal"></modal>
    
        <button>Show Modal</button>
    </div>
    

    最后在我的 app.js 中我这样做了:

    import Vue from 'vue';
    import Modal from './components/modals/show-modal.vue';
    
    if (document.getElementById("app")){
        var app = new Vue({
            el: '#app',
    
            data: {
                modalData: Modal.data()
            },
    
            methods: {
    
            },
    
            computed: {
    
            },
    
            components: {
                'modal': Modal
            }
    
        });
    
        window.vue = app;
    }
    

    我显然没有完成显示模式按钮的代码,但至少使用这种方式我现在可以访问子数据。我只需要为每个组件定义它,这些组件应该解释它在数据中包含的尽可能多的变量。

    也感谢 Carlos 建议将其包装到 div 中。

    【讨论】:

    • 这里没有引用子组件数据。模态组件数据函数返回一个对象。当模态组件被实例化时,它会调用 data 函数,这将返回一个完全 不同的 对象。上面的代码似乎可以工作,因为v-if 正在控制是否显示模态框;孩子的数据与它无关。
    • @Bert 实际上它确实访问了子组件数据。我通过添加另一个变量来测试这个理论>
    • @Bert Ahh 我明白你的意思了。从子返回中获取的初始数据很好,但是一旦有诸如单击将其更改为 true 或返回为 false 之类的操作,它就不会更新它。我想试图找到一种方法来保持主 app.js 干净,只显示组件,没有特定变量,但仍然是反应性的。
    【解决方案3】:

    简短的回答:您正在尝试访问父组件范围内的子组件的属性(或您的案例中的 Root 实例)。你应该在父组件上声明showModal 属性。

    var app = new Vue({
        el: '#app',
        components: {Modal},
        data: {
            showModal: false
    
        },
    });
    

    然后您将拥有更改属性状态的按钮: &lt;button @click="showModal = true"&gt;&lt;/button&gt;

    棘手的部分是关闭模式 - 因为当模式处于活动状态时,您无法再访问您的按钮。您必须从子组件更改父组件的状态。在这种情况下,您可以使用自定义事件,如下所示:

    show-modal.vue

    <div class="modal-footer">
        <button type="button" class="btn btn-default" @click="close">
           Close
       </button>
      </div>
    
        ...
    
     <script>
    export default {
        methods: {
             close() {
                 this.$emit('close');
             }
        }
    }
    

    现在,我们要做的就是监听我们刚刚在主模板中触发的自定义事件,就像这样;

    <modal v-if="showModal" @close="showModal = false"></modal>
    

    【讨论】:

    • 与 Carlos 的另一个答案类似,主/根实例中的访问变量很好,但如果我以后有数百个组件,主文件将不得不声明所有可能的变量?如果来自 child 的 vars 没有被硬编码并且数据是从 api 中获取的怎么办?有没有一些动态的方法来实现这一点?
    【解决方案4】:

    您需要在您的主应用上声明 var showModal

    data: {
        showModal: false
    },
    

    您还需要在他们每次单击按钮时切换该变量,因此将其添加到您的按钮中:

    <button @click="showModal = !showModal">Show Modal</button>
    

    我还建议用 div 将模态框包裹在模板内。因为 vuejs 需要这个。

    <template>
        <div>
            <div id="myModal" class="modal fade" role="dialog">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal">&times;</button>
                            <h4 class="modal-title">Modal Header</h4>
                        </div>
                        <div class="modal-body">
                            <p>Some text in the modal.</p>
                        </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>
    </template>
    

    【讨论】:

    • 从主应用程序访问 var 很好,但想象一下我有 100 个组件,每个组件甚至可能有未硬编码的数据 var,也可能是一个数组,这会使主应用程序非常混乱,无法包含所有 var子组件。
    猜你喜欢
    • 2014-07-17
    • 2020-04-14
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多