VueJS:在同一组件的两个实例之间切换的最佳方式

VueJS: best way to toggle between two instances of the same component

假设我有 foo.vue 作为名为 ab 的组件导入 parent 并根据变量 show

现在从 parent 如果我在组件 ab 之间切换而不设置 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