You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte模态框组件仅首次点击可打开问题求助

问题描述

在Svelte中开发了商品展示模态框组件,首次点击商品时模态框正常弹出,但关闭后再次点击任意商品,模态框都无法再次显示。

组件代码(ProductModal.svelte):

<script>
    export let open = false;
    export let data = {};
    export let modalID = undefined;

    const closeModal = () => {
        console.log("closing modal...")
        open = false;

        // reset all fields
        data = {};
    }

    $: console.log(open)
</script>

{#if open}
<div class="modal" id="product-modal-{modalID}" class:modal-open={open}>
    <div class="modal-box relative w-56">
        <label for="product-modal-{modalID}" class="btn btn-sm btn-circle absolute right-2 top-2" on:click={closeModal}>✕</label>
        <div class="bg-white">
            <div class="flex items-center justify-center">
                <img class="object-scale-down h-40 w-40"
                     src="https://media.ldlc.com/r1600/ld/products/00/05/82/02/LD0005820208_1.jpg" alt=""
                />
            </div>
            <div class="py-2 px-2 bg-white">
                <p class="text-md font-semibold block text-gray-600">
                    { data.name }
                </p>
                <div class="flex flex-row py-4">
                    <div class="pr-8 pt-2 flex justify-between">
                        <span class="font-semibold">-</span>
                        <input type="text" class="focus:outline-none bg-gray-100 border h-6 w-8 rounded text-sm px-2 mx-2" value="1">
                        <span class="font-semibold">+</span>
                    </div>
                    <button class="btn btn-primary btn-sm">Add</button>
                </div>
            </div>
        </div>
    </div>
</div>
{/if}

页面调用代码:

<script>
    import { productSearch } from "../../lib/api/products.js";
    import ProductModal from "../../lib/components/ProductModal.svelte";

    let openModal = false;
    let productData = {}

    const openProductModal = (data) => {
        console.log(data);
        productData = data;
        openModal = !openModal;
        console.log(openModal)
    }
</script>
{#if searchResults}
   {#each searchResults as result (result.searchable.id)}
       <div class="w-64 rounded-md overflow-hidden shadow-lg hover:scale-105 transition duration-500 bg-white">
           <div class="flex items-center justify-center">
               <img class="object-scale-down h-40 w-40"                                          
 src="https://media.ldlc.com/r1600/ld/products/00/05/82/02/LD0005820208_1.jpg" alt=""
                                        />
           </div>
       <div class="py-4 px-4 bg-white">
       <p class="text-md font-semibold block text-gray-600 line-clamp-3 h-20 max-h-20">
           { result.searchable.name }
       </p>
       <div class="flex flex-row justify-between">
   <p class="text-lg font-semibold text-black cursor-auto my-3">${ result.searchable.retail_price }</p>
   <a href="#" on:click={openProductModal(result.searchable)} class="btn btn-circle btn-outline">
   <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
   <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5V6a3.75 3.75 0 10-7.5 0v4.5m11.356-1.993l1.263 12c.07.665-.45 1.243-1.119 1.243H4.25a1.125 1.125 0 01-1.12-1.243l1.264-12A1.125 1.125 0 015.513 7.5h12.974c.576 0 1.059.435 1.119 1.007zM8.625 10.5a.375.375 0 11-.75 0 .375.375 0 01.75 0zm7.5 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
   </svg>
</a>
        </div>
    </div>
</div>
{/each}
{/if}

{#if openModal}
<ProductModal open={openModal} data={productData} modalID={productData.id} />
{/if}
问题原因
  • 子组件直接修改props导致状态不同步:Svelte中props是单向绑定的,子组件ProductModal的closeModal函数里直接修改open = false,不会同步到父组件的openModal状态。关闭模态框后,父组件的openModal依然是true,后续点击商品执行openModal = !openModal会把状态改成false,无法触发模态框渲染。
  • 点击事件绑定错误:页面中on:click={openProductModal(result.searchable)}的写法会在组件初始化时立即执行openProductModal,而非点击时触发,导致首次加载就触发模态框,后续点击逻辑完全异常。
修复方案

1. 修改子组件(ProductModal.svelte)

子组件不直接修改props,而是通过自定义事件通知父组件更新状态:

<script>
    import { createEventDispatcher } from 'svelte';
    const dispatch = createEventDispatcher();
    
    export let open = false;
    export let data = {};
    export let modalID = undefined;

    const closeModal = () => {
        console.log("closing modal...")
        // 触发自定义事件让父组件处理状态变更
        dispatch('close');
        data = {};
    }

    $: console.log(open)
</script>

{#if open}
<div class="modal" id="product-modal-{modalID}" class:modal-open={open}>
    <div class="modal-box relative w-56">
        <label for="product-modal-{modalID}" class="btn btn-sm btn-circle absolute right-2 top-2" on:click={closeModal}>✕</label>
        <div class="bg-white">
            <div class="flex items-center justify-center">
                <img class="object-scale-down h-40 w-40"
                     src="https://media.ldlc.com/r1600/ld/products/00/05/82/02/LD0005820208_1.jpg" alt=""
                />
            </div>
            <div class="py-2 px-2 bg-white">
                <p class="text-md font-semibold block text-gray-600">
                    { data.name }
                </p>
                <div class="flex flex-row py-4">
                    <div class="pr-8 pt-2 flex justify-between">
                        <span class="font-semibold">-</span>
                        <input type="text" class="focus:outline-none bg-gray-100 border h-6 w-8 rounded text-sm px-2 mx-2" value="1">
                        <span class="font-semibold">+</span>
                    </div>
                    <button class="btn btn-primary btn-sm">Add</button>
                </div>
            </div>
        </div>
    </div>
</div>
{/if}

2. 修改父组件调用逻辑

  • 修正点击事件绑定,传递回调函数而非立即执行;
  • 监听子组件的close事件更新状态;
  • 打开模态框时直接设置openModal = true,避免依赖状态取反:
<script>
    import { productSearch } from "../../lib/api/products.js";
    import ProductModal from "../../lib/components/ProductModal.svelte";

    let openModal = false;
    let productData = {}

    const openProductModal = (data) => {
        console.log(data);
        productData = data;
        // 直接设置为true,确保每次点击都打开模态框
        openModal = true;
        console.log(openModal)
    }

    const closeProductModal = () => {
        openModal = false;
    }
</script>
{#if searchResults}
   {#each searchResults as result (result.searchable.id)}
       <div class="w-64 rounded-md overflow-hidden shadow-lg hover:scale-105 transition duration-500 bg-white">
           <div class="flex items-center justify-center">
               <img class="object-scale-down h-40 w-40"                                          
 src="https://media.ldlc.com/r1600/ld/products/00/05/82/02/LD0005820208_1.jpg" alt=""
                                        />
           </div>
       <div class="py-4 px-4 bg-white">
       <p class="text-md font-semibold block text-gray-600 line-clamp-3 h-20 max-h-20">
           { result.searchable.name }
       </p>
       <div class="flex flex-row justify-between">
   <p class="text-lg font-semibold text-black cursor-auto my-3">${ result.searchable.retail_price }</p>
   <!-- 修正点击事件,传递回调函数 -->
   <a href="#" on:click={() => openProductModal(result.searchable)} class="btn btn-circle btn-outline">
   <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
   <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5V6a3.75 3.75 0 10-7.5 0v4.5m11.356-1.993l1.263 12c.07.665-.45 1.243-1.119 1.243H4.25a1.125 1.125 0 01-1.12-1.243l1.264-12A1.125 1.125 0 015.513 7.5h12.974c.576 0 1.059.435 1.119 1.007zM8.625 10.5a.375.375 0 11-.75 0 .375.375 0 01.75 0zm7.5 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
   </svg>
</a>
        </div>
    </div>
</div>
{/each}
{/if}

<!-- 监听子组件的close事件,移除父组件的if判断,让子组件自己控制显示 -->
<ProductModal open={openModal} data={productData} modalID={productData.id} on:close={closeProductModal} />

内容的提问来源于stack exchange,提问作者MrCujo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:10:31