从另一个组件中更改一个组件中的属性值
Posted
技术标签:
【中文标题】从另一个组件中更改一个组件中的属性值【英文标题】:Change a property's value in one component from within another component 【发布时间】:2019-02-05 19:40:54 【问题描述】:我正在努力学习 Vue.js 作品,阅读大量文档和教程,并参加了一些复数课程。我有一个非常基本的网站 UI 正在运行。这是 App.vue(我将其用作母版页)。
(为了让阅读更轻松、更快捷,请查看以下评论: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
,
到目前为止一切顺利!但这是踢球者。有些页面没有左侧栏,在这些页面上,我想将 showLeftContent
从 true
更改为 false
。那是我想不通的部分。
假设我们有一个看起来像这样的“Notes”组件。
<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,我不太了解!!)
编辑 4:
慢慢来!
export default class App extends Vue
data()
return
showLeftContent: true
leftContent(value: boolean)
alert('clicked');
this.$root.$emit('left-content', value);
这不会导致任何错误,但它也不起作用。该事件永远不会被触发。我将尝试将其放入 Navigation 组件中,看看是否可行。
【问题讨论】:
你确定 Notes 组件已经挂载了吗?可能会添加一个console.log
以仔细检查它。
@Sphinx,见编辑 2
如果值为'undefined',可能是App不是根实例造成的。通过console.log(this.$root.$el)
仔细检查。
大声笑,我也不知道打字稿(对于编辑 3)。添加了 typescript 标签。
this.$root.$emit('left-content', value);
应该在想要隐藏/显示侧面板的组件上调用。而你没有定义this.$on
【参考方案1】:
正如@lukebearden 回答中所说,您可以使用发出事件在router-link
点击时将真/假传递给App
主组件。
假设您的 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>
【讨论】:
@CaseyCrookston 我不太了解 ts,但我认为您不需要此块methods: ...
来初始化方法。
@CaseyCrookston 关于您的编辑 4,发出 'left-content'
事件的不是 App
,而是 Navigation
(你不需要$root
)。 App
在导航组件上监听事件。
@sovalina,你能告诉我那会是什么样子吗?伙计,我解决了一个问题,另一个问题突然出现了!!我真的很感谢你的帮助!!
@CaseyCrookston 我做了一个codesandbox here 来测试路由器链接(但它不在打字稿中)
@CaseyCrookston 如果/notes
是一个路由,您也可以将LeftSideBar
从它的路由组件中排除:codesandbox.io/s/6lp16pwjpr【参考方案2】:
父子组件关系中的一个基本方法是从子组件发出事件,然后在父组件中侦听和处理该事件。
但是,我不确定这种方法在使用路由器视图时是否有效。这个人通过观察 $route 属性的变化解决了这个问题。 https://forum.vuejs.org/t/emitting-events-from-vue-router/10136/6
您可能还想研究使用 vue 实例或使用 vuex 创建简单的事件总线。
【讨论】:
或this.$root.$emit/$on
将是一种选择。【参考方案3】:
如果您想访问根实例的数据属性(或道具、选项等),您可以使用this.$root.$data
。 (查看Vue Guide: Handling Edge)
对于您的代码,您可以在其他组件的 hook=mounted
中将 this.$root.$data.showLeftContent
更改为 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>
【讨论】:
在根 App 组件中,我应该使用道具而不是数据吗?意思是,showLeftContent 应该是一个道具而不是 data() 对象的一部分吗? @CaseyCrookston,Vue 在单向数据流下工作。一个组件不应更改其道具的值。所以我认为使用一个 prop 代替 data 属性不是一个好主意。 好的,谢谢。这就说得通了。所以...我仍在努力了解如何更改数据属性“showLeftContent” 如果做一个警报,像这样:alert(this.$root.$data.showLeftContent);它返回“未定义”以上是关于从另一个组件中更改一个组件中的属性值的主要内容,如果未能解决你的问题,请参考以下文章