从父组件到子组件的事件
Event from parent to child component
我有在父组件中生成的事件,子组件必须对其做出反应。我知道这不是 vuejs2
中推荐的方法,我必须执行 $root
发出,这非常糟糕。所以我的代码是这样的。
<template>
<search></search>
<table class="table table-condensed table-hover table-striped" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
<tbody id="trans-table">
<tr v-for="transaction in transactions" v-model="transactions">
<td v-for="item in transaction" v-html="item"></td>
</tr>
</tbody>
</table>
</template>
<script>
import Search from './Search.vue';
export default {
components: {
Search
},
data() {
return {
transactions: [],
currentPosition: 0
}
},
methods: {
loadMore() {
this.$root.$emit('loadMore', {
currentPosition: this.currentPosition
});
}
}
}
</script>
如您所见,loadMore
是在无限滚动时触发的,事件正在发送到子组件搜索。好吧,不仅是搜索,而且因为它是根目录,所以它正在广播给所有人。
对此有什么更好的方法。我知道我应该使用道具,但我不确定在这种情况下我该怎么做。
只要有一个变量(称之为 moreLoaded
),每次调用 loadMore
时它都会递增。将它和 currentPosition
作为道具传递给您的 search
组件。在搜索中,您可以 watch moreLoaded
并采取相应的行动。
更新
哈基? 我的解决方案?嗯,我从来没有! ;)
您也可以使用 localized event bus。像这样设置它:
export default {
components: {
Search
},
data() {
return {
bus: new Vue(),
transactions: [],
currentPosition: 0
}
},
methods: {
loadMore() {
this.bus.$emit('loadMore', {
currentPosition: this.currentPosition
});
}
}
}
并将其传递给搜索:
<search :bus="bus"></search>
将 bus
作为道具(当然),并且有一个像
这样的部分
created() {
this.bus.$on('loadMore', (args) => {
// do something with args.currentPosition
});
}
我认为@tobiasBora 对@Roy J 的回答的评论非常重要。如果您的组件被多次创建和销毁(例如使用 v-if
时),您将以处理程序被多次调用而告终。即使组件被销毁,处理程序也会被调用(结果可能真的很糟糕)。
正如@tobiasBora 所解释的,您必须使用 Vue 的 $off()
函数。这最终对我来说很重要,因为它需要对事件处理函数的引用。我最终做的是将此处理程序定义为组件数据的一部分。请注意,这必须是箭头函数,否则您需要在函数定义后添加 .bind(this)
。
export default {
data() {
return {
eventHandler: (eventArgs) => {
this.doSomething();
}
}
},
methods: {
doSomething() {
// Actually do something
}
},
created() {
this.bus.$on("eventName", this.eventHandler);
},
beforeDestroy() {
this.bus.$off("eventName", this.eventHandler);
},
}
我有在父组件中生成的事件,子组件必须对其做出反应。我知道这不是 vuejs2
中推荐的方法,我必须执行 $root
发出,这非常糟糕。所以我的代码是这样的。
<template>
<search></search>
<table class="table table-condensed table-hover table-striped" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
<tbody id="trans-table">
<tr v-for="transaction in transactions" v-model="transactions">
<td v-for="item in transaction" v-html="item"></td>
</tr>
</tbody>
</table>
</template>
<script>
import Search from './Search.vue';
export default {
components: {
Search
},
data() {
return {
transactions: [],
currentPosition: 0
}
},
methods: {
loadMore() {
this.$root.$emit('loadMore', {
currentPosition: this.currentPosition
});
}
}
}
</script>
如您所见,loadMore
是在无限滚动时触发的,事件正在发送到子组件搜索。好吧,不仅是搜索,而且因为它是根目录,所以它正在广播给所有人。
对此有什么更好的方法。我知道我应该使用道具,但我不确定在这种情况下我该怎么做。
只要有一个变量(称之为 moreLoaded
),每次调用 loadMore
时它都会递增。将它和 currentPosition
作为道具传递给您的 search
组件。在搜索中,您可以 watch moreLoaded
并采取相应的行动。
更新
哈基? 我的解决方案?嗯,我从来没有! ;)
您也可以使用 localized event bus。像这样设置它:
export default {
components: {
Search
},
data() {
return {
bus: new Vue(),
transactions: [],
currentPosition: 0
}
},
methods: {
loadMore() {
this.bus.$emit('loadMore', {
currentPosition: this.currentPosition
});
}
}
}
并将其传递给搜索:
<search :bus="bus"></search>
将 bus
作为道具(当然),并且有一个像
created() {
this.bus.$on('loadMore', (args) => {
// do something with args.currentPosition
});
}
我认为@tobiasBora 对@Roy J 的回答的评论非常重要。如果您的组件被多次创建和销毁(例如使用 v-if
时),您将以处理程序被多次调用而告终。即使组件被销毁,处理程序也会被调用(结果可能真的很糟糕)。
正如@tobiasBora 所解释的,您必须使用 Vue 的 $off()
函数。这最终对我来说很重要,因为它需要对事件处理函数的引用。我最终做的是将此处理程序定义为组件数据的一部分。请注意,这必须是箭头函数,否则您需要在函数定义后添加 .bind(this)
。
export default {
data() {
return {
eventHandler: (eventArgs) => {
this.doSomething();
}
}
},
methods: {
doSomething() {
// Actually do something
}
},
created() {
this.bus.$on("eventName", this.eventHandler);
},
beforeDestroy() {
this.bus.$off("eventName", this.eventHandler);
},
}