我的Vue3模态组件在页面更改时不会重新挂载。

huangapple go评论87阅读模式
英文:

My modal component in Vue3 doesn't remount on page change

问题

我有一个签名模态框组件,它位于一个批准组件内,该组件同时被购物车页面和批准页面组件使用。当加载购物车页面时,签名模态框会被渲染或挂载。但是,每当我从购物车页面上的按钮导航到批准页面时,签名模态框会被卸载。然而,尽管批准页面也使用与购物车页面相同的签名模态框,但它不会重新挂载或重新渲染。为什么会发生这种情况?

已经努力解决这个问题几周了。

我已经尝试过v-if:key属性,但仍然存在相同的问题和错误。

以下是这种情况的简化代码:

Vue组件

ShoppingCart.vue

<template>
    <DefaultLayout :title="`购物车`">
        <div id="shopping-cart">

            <CartInformation />
            
            <div><ShoppingCartItem /></div>

        </div>
    </DefaultLayout>
</template>

<script setup>
import DefaultLayout from '@/Layouts/DefaultLayout.vue';
import CartInformation from './CartInformation.vue';
import ShoppingCartItem from './ShoppingCartItem.vue';
</script>

CartInformation.vue

<template>
    <div>
        <Link :href="approveAll()">
            <div>全部批准</div>
        </Link>
    </div>
</template>
<script setup>
import { Link } from '@inertiajs/vue3';
const approveAll = () => {
    return route('approval');
}
</script>

ApprovalPage.vue

<template>
    <DefaultLayout :title="`批准`">
        <div class="uk-container">
            <Approval />
        </div>
    </DefaultLayout>
</template>

<script setup>
import DefaultLayout from '@/Layouts/DefaultLayout.vue';
import Approval from '@/Components/Approval/Index.vue';
</script>

ShoppingCartItem.vue

<template>
    <a
        href="javascript:void(0)"
        @click="onApprove()"
        class="uk-button"
        >
            <span>批准项目</span>
    </a>
    <ApproveModal ref="approveModal" />
</template>

<script setup>
import ApproveModal from '@/Components/ShoppingCart/Modals/ApproveModal.vue';
const onApprove = () => {
    approveModal.value.showModal();
};
</script>

ApproveModal.vue

<template>
    <PlainModal :id="modalId" :fullscreen="true">
        <div uk-height-viewport>
            <div id="approve-single-item">
                <Approval/>
            </div>
        </div>
    </PlainModal>
</template>
<script setup>
import PlainModal from '@/Components/Common/PlainModal.vue';
import Approval from '@/Components/Approval/Index.vue';
import { modal } from "uikit";
import { useApprovalStore } from '@/stores/approval';
import { onUpdated, ref } from 'vue';

const props = defineProps({
    cartItem: {
        type: Object,
        default: { }
    },
})

const modalId = "approve-single-item-modal";
const approvalStore = useApprovalStore();
approvalStore.setItems(props);
approvalStore.setActiveItem(props.cartItem);

onUpdated(() => {
    approvalStore.setItems({
        cart_items: [props.cartItem]
    });
    approvalStore.setActiveItem(props.cartItem);
});

const showModal = () => {
    modal(`#${modalId}`).show();
};

defineExpose({
    showModal
});
</script>

Approval/Index.vue

<template>
    <div class="uk-box-shadow" v-if="approvalStore.getActiveItem">
        <hr />
        <div class="uk-padding">
            <hr class="uk-margin-small" />
            <div>
                <div class="uk-text-center">
                    <Button :text="`批准`" @click="onApprovedItem()" />
                </div>
            </div>
        </div>
    </div>

    <Signature ref="signatureModal"></Signature>
</template>

<script setup>
import Button from '../Common/Button.vue';
import Signature from '@/Components/Signature/Index.vue';
import { useApprovalStore } from '@/stores/approval';
import { ref, watch } from 'vue';

const approvalStore = useApprovalStore();
const signatureModal = ref(null);

watch(
    () => approvalStore.isFinished,
    isFinished => {
        if (isFinished) {
            signatureModal.value.showSignatureModal();
        }
    }
)

const onApprovedItem = () => {
    const activeItem = approvalStore.getActiveItemId;
    approvalStore.approvedItem(activeItem);
}
</script>

Signature/Index.vue

<template>
    <PlainModal :id="modalId" :fullscreen="true">
        <div uk-height-viewport>
            <h3>签名</h3>
            <!-- 其他组件 -->
        </div>
    </PlainModal>
</template>

<script setup>
import PlainModal from '@/Components/Common/PlainModal.vue';
import { modal } from 'uikit';
import { onUnmounted } from 'vue';

const modalId = 'signature-modal';

const showSignatureModal = () => {
    modal(`#${modalId}`).show();
}
defineExpose({
    showSignatureModal
});
onUnmounted(() => {
});
</script>

Laravel文件

web.php(用于路由)

<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Pages\ShoppingCartController;

Route::prefix('shopping-cart')
    ->middleware('auth')
    ->controller(ShoppingCartController::class)
    ->group(function() {
        Route::get('/', 'showApproval')->name('approval');
    });

ShoppingCartController.php

namespace App\Http\Controllers\Pages;
use App\Http\Controllers\Controller;
use Inertia\Inertia;
use App\Models\CartItem;

class ShoppingCartController extends Controller
{
    public function showApproval()
    {
        $cart_items = [CartItem];
        return Inertia::render('ShoppingCart/ApprovalPage', compact('cart_items'));
    }
}

请让我知道如果您需要进一步的帮助。

英文:

I have a signature modal component inside an approval component that is being used by both the shopping cart page and approval page components. When the shopping cart page is loaded, the signature modal is rendered or mounted. Whenever I navigate to the approval page from a button on the shopping cart page, the signature modal is unmounted. However, it doesn't remount or rerender on the approval page, even though the approval page also uses the same signature modal as the shopping cart page. Why is this happening?

Been working on this for weeks now.

I've already tried the v-if and the :key properties but same issue and error.

Here are the simplified codes for these scenario:

Vue Components

ShoppingCart.vue

    &lt;template&gt;
        &lt;DefaultLayout :title=&quot;`Shopping Cart`&quot;&gt;
                &lt;div id=&quot;shopping-cart&quot;&gt;

                    &lt;CartInformation /&gt;

                    &lt;div&gt;&lt;ShoppingCartItem /&gt;&lt;/div&gt;

                &lt;/div&gt;
        &lt;/DefaultLayout&gt;
    &lt;/template&gt;

    &lt;script setup&gt;
    import DefaultLayout from &#39;@/Layouts/DefaultLayout.vue&#39;;
    import CartInformation from &#39;./CartInformation.vue&#39;
    import ShoppingCartItem from &#39;./ShoppingCartItem.vue&#39;
    &lt;/script&gt;

CartInformation.vue

&lt;template&gt;
    &lt;div&gt;
        &lt;Link :href=&quot;approveAll()&quot;&gt;
            &lt;div&gt;Approve All&lt;/div&gt;
        &lt;/Link&gt;
    &lt;/div&gt;
&lt;/template&gt;
&lt;script setup&gt;
import { Link } from &#39;@inertiajs/vue3&#39;;
const approveAll = () =&gt; {
    return route(&#39;approval&#39;);
}
&lt;/script&gt;

ApprovalPage.vue

&lt;template&gt;
    &lt;DefaultLayout :title=&quot;`Approval`&quot;&gt;
        &lt;div class=&quot;uk-container&quot;&gt;
            &lt;Approval /&gt;
        &lt;/div&gt;
    &lt;/DefaultLayout&gt;
&lt;/template&gt;

&lt;script setup&gt;
import DefaultLayout from &#39;@/Layouts/DefaultLayout.vue&#39;;
import Approval from &#39;@/Components/Approval/Index.vue&#39;;
&lt;/script&gt;

ShoppingCartItem.vue

&lt;template&gt;
    &lt;a
        href=&quot;javascript:void(0)&quot;
        @click=&quot;onApprove()&quot;
        class=&quot;uk-button&quot;
        &gt;
            &lt;span&gt;Approve Item&lt;/span&gt;
    &lt;/a&gt;
    &lt;ApproveModal ref=&quot;approveModal&quot; /&gt;
&lt;/template&gt;

&lt;script setup&gt;
import ApproveModal from &#39;@/Components/ShoppingCart/Modals/ApproveModal.vue&#39;;
const onApprove = () =&gt; {
    approveModal.value.showModal();
};
&lt;/script&gt;

ApproveModal.vue

&lt;template&gt;
    &lt;PlainModal :id=&quot;modalId&quot; :fullscreen=&quot;true&quot;&gt;
        &lt;div uk-height-viewport&gt;
            &lt;div id=&quot;approve-single-item&quot;&gt;
                &lt;Approval/&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/PlainModal&gt;
&lt;/template&gt;
&lt;script setup&gt;
import PlainModal from &#39;@/Components/Common/PlainModal.vue&#39;;
import Approval from &#39;@/Components/Approval/Index.vue&#39;;
import { modal } from &quot;uikit&quot;;
import { useApprovalStore } from &#39;@/stores/approval&#39;;
import { onUpdated, ref } from &#39;vue&#39;;
const props = defineProps({
    cartItem: {
        type: Object,
        default: { }
    },
})
const modalId = &quot;approve-single-item-modal&quot;;
const approvalStore = useApprovalStore();
approvalStore.setItems(props);
approvalStore.setActiveItem(props.cartItem);

onUpdated(() =&gt; {
    approvalStore.setItems({
        cart_items: [props.cartItem]
    });
    approvalStore.setActiveItem(props.cartItem);
});

const showModal = () =&gt; {
    modal(`#${modalId}`).show();
};

defineExpose({
    showModal
});
&lt;/script&gt;

Approva/Index.vue

&lt;template&gt;
    &lt;div class=&quot;uk-box-shadow&quot; v-if=&quot;approvalStore.getActiveItem&quot;&gt;
        &lt;hr /&gt;
        &lt;div class=&quot;uk-padding&quot;&gt;
            &lt;hr class=&quot;uk-margin-small&quot; /&gt;
            &lt;div&gt;
                &lt;div class=&quot;uk-text-center&quot;&gt;
                    &lt;Button :text=&quot;`Approve`&quot; @click=&quot;onApprovedItem()&quot; /&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;Signature ref=&quot;signatureModal&quot;&gt;&lt;/Signature&gt;
&lt;/template&gt;

&lt;script setup&gt;
import Button from &#39;../Common/Button.vue&#39;;
import Signature from &#39;@/Components/Signature/Index.vue&#39;
import { useApprovalStore } from &#39;@/stores/approval&#39;;
import { ref, watch } from &#39;vue&#39;;
const approvalStore = useApprovalStore();
const signatureModal = ref(null);

watch(
    () =&gt; approvalStore.isFinished,
    isFinished =&gt; {
        if (isFinished) {
            signatureModal.value.showSignatureModal();
        }
    }
)

const onApprovedItem = () =&gt; {
    const activeItem = approvalStore.getActiveItemId;
    approvalStore.approvedItem(activeItem);
}
&lt;/script&gt;

Signature/Index.vue

&lt;template&gt;
    &lt;PlainModal :id=&quot;modalId&quot; :fullscreen=&quot;true&quot;&gt;
        &lt;div uk-height-viewport&gt;
            &lt;h3&gt;Signature&lt;/h3&gt;
            &lt;!-- other components --&gt;
        &lt;/div&gt;
    &lt;/PlainModal&gt;
&lt;/template&gt;

&lt;script setup&gt;
import PlainModal from &#39;@/Components/Common/PlainModal.vue&#39;;
import { modal } from &#39;uikit&#39;;
import { onUnmounted } from &#39;vue&#39;;

const modalId = &#39;signature-modal&#39;;

const showSignatureModal = () =&gt; {
    modal(`#${modalId}`).show();
}
defineExpose({
    showSignatureModal
});
onUnmounted(() =&gt; {
});

Laravel files

web.php (for routing)

&lt;?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Pages\ShoppingCartController;

Route::prefix(&#39;shopping-cart&#39;)
-&gt;middleware(&#39;auth&#39;)
-&gt;controller(ShoppingCartController::class)
-&gt;group(function() {
    Route::get(&#39;/&#39;, &#39;showApproval&#39;)-&gt;name(&#39;approval&#39;);
});

ShoppingCartController.php

namespace App\Http\Controllers\Pages;
use App\Http\Controllers\Controller;
use Inertia\Inertia;
use App\Models\CartItem;
class ShoppingCartController extends Controller
{
    public function showApproval()
    {
        $cart_items = [CartItem];
        return Inertia::render(&#39;ShoppingCart/ApprovalPage&#39;, compact(&#39;cart_items&#39;));
    }
}

答案1

得分: 0

已解决。我发现在页面切换期间,包括其子组件在内的批准组件已卸载。当在页面切换时重新挂载时,其子组件(例如签名模态框)不会重新挂载。因此,我在签名模态框中使用了 v-if,并通过批准组件的 onMountedonUnmounted 生命周期钩子更改了 v-if 中变量的值。

英文:

Already resolved. I discovered that the approval component was unmounted during page change including its child. When it remounts on page change, its child components (like the signature modal) doesn't remount. So i used the v-if in signature modal and change the value of the variable in the v-if through onMounted and onUnmounted lifecycle hooks of the Approval component

huangapple
  • 本文由 发表于 2023年6月16日 13:26:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76487176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定