将事件从父母传递给孩子

时间:2018-02-23 19:16:08

标签: vue.js

我有一个AppRoot.vue,AppToolbar.vue和AppDrawer.vue

当我单击AppToolbar.vue中的按钮并在AppRoot.vue中声明时,我需要更改AppDrawer.vue的isDrawerOpen变量。

我该怎么做?任何人都可以帮助我吗?

AppRoot.vue

<template>
    <v-app id="app-root">
        <app-drawer></app-drawer>
        <app-toolbar :title="title"></app-toolbar>
        <v-content>
            <v-container>
                <slot><h1>Não há nada para exibir aqui!</h1></slot>
            </v-container>
        </v-content>
        <app-footer></app-footer>
    </v-app>
</template>

<script>
    export default {
        name: 'app-root',
        props: ['title'],
    }
</script>

AppToolbar.vue

<template>
    <v-toolbar :color="$color" app>

        <v-layout row hidden-md-and-up>
            <v-toolbar-side-icon @click="openDrawer" class="white--text"></v-toolbar-side-icon>
        </v-layout>

        <v-toolbar-title class="white--text" v-text="title"></v-toolbar-title>

    </v-toolbar>
</template>

<script>
    export default {
        name: 'app-toolbar',
        props: ['title'],
        methods: {
            openDrawer() {

            }
        }
    }
</script>

AppDrawer.vue

<template>
    <v-navigation-drawer temporary v-model="isDrawerOpen" absolute>
        <v-list class="pa-1">
            <v-list-tile avatar>
                <v-list-tile-avatar>
                    <img src="https://rafaeldeveloper.com.br/img/rafael_developer.jpg">
                </v-list-tile-avatar>
                <v-list-tile-content>
                    <v-list-tile-title>Rafael de Azeredo</v-list-tile-title>
                </v-list-tile-content>
            </v-list-tile>
        </v-list>
    </v-navigation-drawer>
</template>

<script>
    export default {
        name: 'app-drawer',
        data: () => ({
            isDrawerOpen: false
        })
    }
</script>

2 个答案:

答案 0 :(得分:2)

首先,您不需要在AppRoot.vue文件中使用props属性,当您对孩子使用:title="title"时,它会传递道具。 props属性用于获取子级中的父组件属性。

对于您的查询,您可以使用事件总线在它们之间进行通信。或者,您可以使用vuex进行更好的状态管理。以下是我们如何使用事件总线实现的方法:

main.js文件中,定义事件中心或您想要的任何文件,但只需确保导入该文件的组件中的事件中心可用。

var eventHub = new Vue();

现在,这将用于您的所有组件。

接下来,您需要发出事件:

AppToolbar.vue

// ...
methods: {
  openDrawer: function () {
    eventHub.$emit('open-drawer', PASS_WHATEVER_YOU_WANT);
  }
}

然后听孩子发出的事件:

AppDrawer.vue

// ...
created: function () {
  eventHub.$on('open-drawer', this.openDrawer)
},
methods: {
  openDrawer(value) {
    // ... do whatever you want to do with value
    // this.isDrawerOpen = !this.isDrawerOpen
    this.isDrawerOpen = value;
  }
}

答案 1 :(得分:1)

组件有两种状态:内部和外部。内部状态通常由组件data控制,而外部状态通常通过props进入。

当外部状态与组件的父级不紧密相关时,您可以将其视为应用程序状态或全局状态。这通常保存在每个组件都可用的“商店”中。很多人使用Vuex,但我认为大多数时候你并不真正需要Vuex,这主要涉及同步受大量可能同时输入影响的数据。

在单用户应用程序中,你只需要一个“教父”:像父母一样,你从中获取道具并发出事件,但这种关系并不直接。

实际上,如果你的应用程序是一个组件集合,$root可用作该教父:你可以向它发出事件,你可以访问它的数据项和计算。

在您的示例中(我已将其拆分为下面的最小片段),抽屉的状态在应用程序中共享。它不在抽屉部件的内部。因此抽屉部件作为道具接收其状态;抽屉的父母 - app-root - 使用:is-open="$root.drawerIsOpen"来提供道具,这样抽屉就不会知道或关心它的状态是全局的;它就像任何道具一样流传下来。

工具栏组件知道应用程序中的某个抽屉,而不是它自己的父级,因此它会将open-drawer事件发送到$root

this.$root.$emit('open-drawer');

顶级Vue($root)在其created挂钩中设置了事件处理,因为无法在模板中全局标记@open-drawer

这应该感觉非常类似于“道具向下,事件向上”的方式,通信被设计为在Vue中工作。

Vue.component('app-root', {
  template: '#root-template',
  props: ['title']
});

Vue.component('app-toolbar', {
  template: '#toolbar-template',
  methods: {
    openDrawer() {
      this.$root.$emit('open-drawer');
    }
  }
});

Vue.component('app-drawer', {
  template: '#drawer-template',
  props: ['isOpen']
});

new Vue({
  el: '#app',
  // This is your store!
  data: {
    drawerIsOpen: false
  },
  created() {
    this.$on('open-drawer', () => {
      this.drawerIsOpen = true;
    });
  }
});
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <app-root title="My App!"></app-root>
</div>

<template id="root-template">
  <div>
    <h1>{{title}}</h1>
    <app-toolbar></app-toolbar>
    <app-drawer :is-open="$root.drawerIsOpen"></app-drawer>
  </div>
</template>

<template id="toolbar-template">
  <div>
    <button @click="openDrawer">Open Drawer</button>
  </div>
</template>

<template id="drawer-template">
  <div v-show="isOpen">
    Drawer here
  </div>
</template>

相关问题