【问题标题】:VueJS: best way to toggle between two instances of the same componentVueJS:在同一组件的两个实例之间切换的最佳方式
【发布时间】:2021-10-12 14:05:05
【问题描述】:

假设我有 foo.vue,我将其作为名为 ab 的组件导入到父级中,并根据变量 show 显示

现在如果我在组件ab 之间切换而不设置show = null,我会得到各种子状态错误。

所以我将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)
 }

有没有更好的方法?这对我来说并不优雅

我的理解是,如果父母告诉它切换它应该从空白开始并重建,那么孩子内部发生的事情并不重要?但就我而言,情况并非如此。有什么可能导致我的问题吗?

设置为null 会以某种方式强制进行硬刷新?

我的子组件很复杂,通过 ajax 调用来检索列表,但没有什么特别之处。

父代码

<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>

孩子

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()
    }
   }

【问题讨论】:

  • 请为您的问题提供stackoverflow.com/help/mcve。目前还不清楚它到底是什么样子。 但这不起作用,因为 JS 是异步正确的 - 它是异步还是同步,为什么它不起作用取决于你的情况。
  • 是的,这不是一个好的说法,我知道 js 可以是异步的或同步的。但这与我认为的 JS 并没有真正的关系,而是更多的 vue 方式?我在网上没有看到任何地方说您应该使用承诺或异步或使用超时来保持状态分离
  • 请张贴代码,不要描述它,这是 SO 规则要求的,以避免歧义。您可以看到为什么这很重要,用户已经发布了没有解决问题的答案,因为它不适合您的实际代码。
  • 你想让我把孩子也寄出去吗?
  • @Roamer-1888 是的,就是这样,从您链接的帖子中,我只需将 :key="someUniqueValue" 添加到每个子组件,不再需要超时!谢谢。请发表一个答案,我会接受它

标签: javascript vue.js promise timeout


【解决方案1】:

这部分没有很好的用途:

const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')

JavaScript 模块(包括 ES 模块)的核心功能在第一次导入时只评估一次,import( './events.vue') 解析为同一个组件。它可以更好地了解以单个名称使用组件时会发生什么。

show 更新时发生的情况是,在组件层次结构中的同一位置有 1 个事件组件实例,因此它不会重新安装,只是接收一组新的道具,分别在 &lt;Events&gt;&lt;AttendingEvents&gt; 中指定.

同一组件的兄弟实例应该用key区分:

<Events ref="events" key="events" ... ></Events>
<Events ref="attending" key="attending" ... ></Events>

它与v-for 一起使用最多,但也适用于影响组件层次结构的所有指令 - v-if 等。

【讨论】:

    【解决方案2】:

    我认为你的问题是你调用 api 从mounted 钩子更改组件中的数据。

    如果您在没有timeout 的情况下“切换”组件,则会发生子组件已经渲染并处于活动状态,但它会更改道具。当您调用 timeout 时,您更改 this.show = null 之前会导致组件不被渲染,然后在 timeout 内将其更改为正确的组件并再次渲染组件,从而触发 mounted 钩子。

    这个问题的最佳解决方案是在子组件中使用watcher,它会随着每个组件实例(某种id)而改变。并从 watcher 调用 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 挂钩内再次调用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-21
      • 2020-12-29
      • 2018-12-06
      • 2016-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-12
      相关资源
      最近更新 更多