从另一个组件中更改一个组件中的属性值

时间:2018-08-30 19:31:10

标签: javascript typescript vue.js vue-component

我想把头放在V Vue.js的作品上,阅读大量文档和教程,并学习一些复数课程。我有一个非常基本的网站用户界面,并且正在运行。这是App.vue(我正在使用kind。作为母版页)。

(要使阅读起来更轻松,更快捷,请查找以下评论:This is the part you should pay attention to)...

<template>
    <div id="app">
        <div>
            <div>
                <CommandBar />
            </div>
            <div>
                <Navigation />
            </div>
        </div>
        <div id="lowerContent">

            <!-- This is the part you should pay attention to -->

            <template v-if="showLeftContent">
                <div id="leftPane">
                    <div id="leftContent">
                        <router-view name="LeftSideBar"></router-view>
                    </div>
                </div>
            </template>

            <!-- // This is the part you should pay attention to -->

            <div id="mainPane">
                <div id="mainContent">
                    <router-view name="MainContent"></router-view>
                </div>
            </div>
        </div>
    </div>
</template>

然后在同一App.vue文件中,这是脚本部分

<script lang="ts">
    import { Component, Vue } from 'vue-property-decorator';

    import CommandBar from './components/CommandBar.vue';
    import Navigation from './components/Navigation.vue';


    @Component({
        components: {
            CommandBar,
            Navigation,
        }
    })
    export default class App extends Vue {
        data() {
            return {
                showLeftContent: true // <--- This is the part you should pay attention to
            }
        }
    }
</script>

好的,所以想法是,有些页面我想显示左侧边栏,而其他页面我不需要。这就是将div包裹在<template v-if="showLeftContent">中的原因。

然后使用名为<router-view>'s的文件,我可以控制将哪些组件加载到“ router \ index.ts \”文件中。路线如下所示:

    {
        path: '/home',
        name: 'Home',
        components: {
            default: Home,
            MainContent: Home,  // load the Home compliment the main content
            LeftSideBar: UserSearch  // load the UserSearch component in the left side bar area
        }
    },

到目前为止一切顺利!但是,这是踢脚线。某些页面没有左侧栏,在这些页面上,我想将showLeftContenttrue更改为false。那是我不知道的部分。

假设我们有一个类似这样的“注释”组件。

<template>
    <div class="notes">
        Notes
    </div>
</template>

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator';

    @Component
    export default class Notes extends Vue {
        data() {
            return {
                showLeftContent: false  // DOES NOT WORK
            }
        }
    }
</script>

很显然,我在这里没有正确处理showLeftContent。据我了解,似乎data中的属性仅作用于该组件。我只是找不到关于如何在App组件中设置数据属性,然后在通过router-view加载子组件时在子组件中进行更改的任何方法。

谢谢!

编辑:

我从以下位置更改了Notes组件的脚本部分:

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator';

    @Component
    export default class Notes extends Vue {
        data() {
            return {
                showLeftContent: false  // DOES NOT WORK
            }
        }
    }
</script>

收件人:

<script lang="ts">
    import { Component, Prop, Vue } from 'vue-property-decorator';

    @Component
    export default class Notes extends Vue {
        mounted() {
            this.$root.$data.showLeftContent = false;
        }
    }
</script>

尽管这没有引起任何编译或运行时错误,但也没有达到预期的效果。在Notes上,左侧栏仍然显示。

编辑2:

如果我在Notes组件的脚本部分中放置了警报:

export default class Notes extends Vue {
    mounted() {
        alert(this.$root.$data.showLeftContent);
        //this.$root.$data.showLeftContent = false;
    }
}

直到我单击导航中的“注释”,警报才会弹出。但是,该值为“未定义”。

编辑3:

在这里使用语法(请记住这是TypeScript,我不太清楚!)

enter image description here

编辑4:

寸步难行!

export default class App extends Vue {
    data() {
        return {
            showLeftContent: true
        }
    }

    leftContent(value: boolean) {
        alert('clicked');
        this.$root.$emit('left-content', value);
    }
}

这不会导致任何错误,但也不起作用。该事件永远不会被解雇。我将尝试将其放在“导航”组件中,看看是否可行。

3 个答案:

答案 0 :(得分:3)

如@lukebearden回答中所述,您可以使用发出事件在单击App时将true / false传递给主router-link组件。

假设您的Navigation组件如下所示,您可以执行以下操作:

#Navigation.vue
<template>
  <div>
      <router-link to="/home" @click.native="leftContent(true)">Home</router-link> - 
      <router-link to="/notes" @click.native="leftContent(false)">Notes</router-link>
  </div>
</template>

<script>
export default {
  methods: {
    leftContent(value) {
      this.$emit('left-content', value)
    }
  }
}
</script>

在主App中,您收听Navigation上的发射:

<template>
  <div id="app">
    <div>
      <Navigation @left-content="leftContent" />
    </div>
    <div id="lowerContent">
      <template v-if="showLeftContent">
         //...
      </template>

      <div id="mainPane">
         //...
      </div>
    </div>
  </div>
</template>

<script>
  //...
  data() {
    return {
      showLeftContent: true
    }
  },
  methods: {
    leftContent(value) {
      this.showLeftContent = value
    }
  }
};
</script>

答案 1 :(得分:2)

父子组件关系中的一种基本方法是从子组件发出事件,然后在父组件中侦听和处理该事件。

但是,我不确定在使用路由器视图时该方法是否有效。这个人通过观察$ route属性的更改来解决它。 https://forum.vuejs.org/t/emitting-events-from-vue-router/10136/6

您可能还想研究使用vue实例或vuex创建简单的事件总线。

答案 2 :(得分:1)

如果您想访问根实例的数据属性(或道具,选项等),则可以使用this.$root.$data。 (选中Vue Guide: Handling Edge

对于您的代码,您可以在其他组件的hook = this.$root.$data.showLeftContent中将mounted更改为true / false,然后在Vue为这些组件创建实例时,它将相关显示/隐藏左侧面板。

以下是一个演示

Vue.config.productionTip = false
Vue.component('child', {
  template: `<div :style="{'background-color':color}" style="padding: 10px">
                Reach to root: <button @click="changeRootData()">Click me!</button>
                <hr>
                <slot></slot>
             </div>`,
  props: ['color'],
  methods: {
    changeRootData() {
      this.$root.$data.testValue += ' :) '
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return {
      testValue: 'Puss In Boots'
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
  <h2>{{testValue}}</h2>
  <child color="red"><child color="gray"><child color="green"></child></child></child>

</div>