VueJS:在同一组件的两个实例之间切换的最佳方式
VueJS: best way to toggle between two instances of the same component
假设我有 foo.vue
作为名为 a
和 b
的组件导入 parent 并根据变量 show
现在从 parent 如果我在组件 a
和 b
之间切换而不设置 show = null
我会得到各种 child 状态错误。
所以我先把show
设置成null
再设置成对应的vue组件这样
this.show = null
this.show = a // or b
但这不起作用。组件以前一个状态结束。即使在未更新的道具上也能验证这一点。
我使用 timeout
让它工作
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
}
有没有更好的方法?这对我来说不优雅
我的理解是 child 内部发生的事情并不重要,如果 parents 告诉它切换它应该从空白开始并重建?但就我而言,情况并非如此。有什么可能导致我的问题吗?
设置为 null
以某种方式强制进行硬刷新?
我的 child 组件很复杂,需要 ajax 调用来检索列表,但没有任何异常。
parent代码
<template>
<div id="userAreaEventWrapper">
<div class="userarea-submenu">
<div v-on:click="toggle(comps.eventForm)" class='button-base-out'>
<div :class="isSelected(comps.eventForm)">
New Event
</div>
</div>
<div v-on:click="toggle(comps.events)" class='button-base-out'>
<div :class="isSelected(comps.events)">
My Events
</div>
</div>
<div v-on:click="toggle(comps.eventsAttending)" class='button-base-out'>
<div :class="isSelected(comps.eventsAttending)">
Attending
</div>
</div>
</div>
<EventForm v-if="show === comps.eventForm" @created="toggle(comps.events)" :mode="'create'"></EventForm>
<Events ref="events" :mode="currentMode" v-if="show === comps.events" @noResults="toggle(comps.eventForm)" :attending="false"></Events>
<AttendingEvents ref="attending" :mode="'home'" v-if="show === comps.eventsAttending" :attending="true"></AttendingEvents>
</div>
</template>
<script>
const EventForm = () => import( './event-form.vue')
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
export default {
name: "UserEventComponent",
components:{
EventForm,
Events,
AttendingEvents
},
data(){
return{
comps:{
eventForm:1,
events:2,
eventsAttending:3
},
show: 2,
currentMode:'user',
}
},
methods: {
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
},
isSelected(n){
return n === this.show ? 'button-base-in button-base-in-hover' : 'button-base-in'
},
},
}
</script>
child
在 mounted()
上获取 api
mounted() {
this.currentMode = this.mode
if(this.resumeData && this.resumeData.slug){
this.selectedSlug = this.resumeData.slug
} else {
this.resume(this.resumeData)
this.getEvents()
}
}
我认为你的问题是你调用 api 从 mounted
挂钩更改组件中的数据。
如果您在没有 timeout
的情况下“切换”组件,会发生的情况是子组件已经呈现并处于活动状态,但它会更改道具。当您调用 timeout
时,您更改 this.show = null
之前会导致组件不被渲染,然后在 timeout
中将其更改为正确的组件,然后再次渲染该组件,从而触发mounted
勾.
这个问题的最佳解决方案是在子组件内使用 watcher
,子组件会针对每个组件实例(某种 id)发生变化。并从观察者那里调用 api。
所以例如添加一个id的道具并观看它:
props: {
id: {
type: Number,
default: 0
}
},
watchers: {
id() {
this.currentMode = this.mode
if(this.resumeData && this.resumeData.slug){
this.selectedSlug = this.resumeData.slug
} else {
this.resume(this.resumeData)
this.getEvents()
}
},
immediate: true
}
immediate: true
也会在组件的挂载处触发观察器,因此您无需在 mounted
挂钩中再次调用它。
这部分没有很好的用途:
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
JavaScript 模块(包括 ES 模块)的核心功能仅在首次导入时评估一次,import( './events.vue')
解析为同一组件。当组件以单个名称使用时,它可以更好地了解发生了什么。
show
更新发生的事情是组件层次结构中的同一个位置有 1 个事件组件实例,因此它没有重新安装,只是接收一组新的道具,在 [=14= 中指定] 和 <AttendingEvents>
分别。
同一组件的同级实例应通过 key
:
区分
<Events ref="events" key="events" ... ></Events>
<Events ref="attending" key="attending" ... ></Events>
它大部分时间与 v-for
一起使用,但也适用于影响组件层次结构的所有指令 - v-if
等
假设我有 foo.vue
作为名为 a
和 b
的组件导入 parent 并根据变量 show
现在从 parent 如果我在组件 a
和 b
之间切换而不设置 show = null
我会得到各种 child 状态错误。
所以我先把show
设置成null
再设置成对应的vue组件这样
this.show = null
this.show = a // or b
但这不起作用。组件以前一个状态结束。即使在未更新的道具上也能验证这一点。
我使用 timeout
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
}
有没有更好的方法?这对我来说不优雅
我的理解是 child 内部发生的事情并不重要,如果 parents 告诉它切换它应该从空白开始并重建?但就我而言,情况并非如此。有什么可能导致我的问题吗?
设置为 null
以某种方式强制进行硬刷新?
我的 child 组件很复杂,需要 ajax 调用来检索列表,但没有任何异常。
parent代码
<template>
<div id="userAreaEventWrapper">
<div class="userarea-submenu">
<div v-on:click="toggle(comps.eventForm)" class='button-base-out'>
<div :class="isSelected(comps.eventForm)">
New Event
</div>
</div>
<div v-on:click="toggle(comps.events)" class='button-base-out'>
<div :class="isSelected(comps.events)">
My Events
</div>
</div>
<div v-on:click="toggle(comps.eventsAttending)" class='button-base-out'>
<div :class="isSelected(comps.eventsAttending)">
Attending
</div>
</div>
</div>
<EventForm v-if="show === comps.eventForm" @created="toggle(comps.events)" :mode="'create'"></EventForm>
<Events ref="events" :mode="currentMode" v-if="show === comps.events" @noResults="toggle(comps.eventForm)" :attending="false"></Events>
<AttendingEvents ref="attending" :mode="'home'" v-if="show === comps.eventsAttending" :attending="true"></AttendingEvents>
</div>
</template>
<script>
const EventForm = () => import( './event-form.vue')
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
export default {
name: "UserEventComponent",
components:{
EventForm,
Events,
AttendingEvents
},
data(){
return{
comps:{
eventForm:1,
events:2,
eventsAttending:3
},
show: 2,
currentMode:'user',
}
},
methods: {
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
},
isSelected(n){
return n === this.show ? 'button-base-in button-base-in-hover' : 'button-base-in'
},
},
}
</script>
child
在 mounted()
mounted() {
this.currentMode = this.mode
if(this.resumeData && this.resumeData.slug){
this.selectedSlug = this.resumeData.slug
} else {
this.resume(this.resumeData)
this.getEvents()
}
}
我认为你的问题是你调用 api 从 mounted
挂钩更改组件中的数据。
如果您在没有 timeout
的情况下“切换”组件,会发生的情况是子组件已经呈现并处于活动状态,但它会更改道具。当您调用 timeout
时,您更改 this.show = null
之前会导致组件不被渲染,然后在 timeout
中将其更改为正确的组件,然后再次渲染该组件,从而触发mounted
勾.
这个问题的最佳解决方案是在子组件内使用 watcher
,子组件会针对每个组件实例(某种 id)发生变化。并从观察者那里调用 api。
所以例如添加一个id的道具并观看它:
props: {
id: {
type: Number,
default: 0
}
},
watchers: {
id() {
this.currentMode = this.mode
if(this.resumeData && this.resumeData.slug){
this.selectedSlug = this.resumeData.slug
} else {
this.resume(this.resumeData)
this.getEvents()
}
},
immediate: true
}
immediate: true
也会在组件的挂载处触发观察器,因此您无需在 mounted
挂钩中再次调用它。
这部分没有很好的用途:
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
JavaScript 模块(包括 ES 模块)的核心功能仅在首次导入时评估一次,import( './events.vue')
解析为同一组件。当组件以单个名称使用时,它可以更好地了解发生了什么。
show
更新发生的事情是组件层次结构中的同一个位置有 1 个事件组件实例,因此它没有重新安装,只是接收一组新的道具,在 [=14= 中指定] 和 <AttendingEvents>
分别。
同一组件的同级实例应通过 key
:
<Events ref="events" key="events" ... ></Events>
<Events ref="attending" key="attending" ... ></Events>
它大部分时间与 v-for
一起使用,但也适用于影响组件层次结构的所有指令 - v-if
等