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

Svelte Radio组件时序问题:父onMount提前执行致DOM查找报错

解决Svelte父组件onMount等待子组件异步逻辑完成的问题

问题原因

父组件的onMount会在自身DOM挂载完成后立即执行,但子组件RadioCode.svelte中的异步请求还未完成,{#await}块还未渲染出radio的input标签,导致document.getElementsByName('apple')[0]找不到元素报错。以下是几种从外部控制的解决方案:


方案1:给子组件添加加载完成回调(最直接的外部控制方式)

给RadioCode.svelte新增一个回调属性,当异步请求完成、radio列表渲染后触发该回调,父组件通过这个回调执行后续逻辑。

修改RadioCode.svelte:

<script>
    export let id='';
    export let name='';
    export let grpCd='';
    export let radioList= [];
    export let onLoaded; // 新增:加载完成回调属性
    
    async function radioData() {
        const param = new FormData();
        param.append('grpCd', grpCd);
        
        const response = await Api.post('Controller Url', param);   
        radioList= response.data;
        // 异步完成后触发回调
        if (onLoaded) onLoaded();
    }
</script>
{#await radioData () then radioList}
    {#each radioList as dtlCd}
            <!-- 修正label的for属性,对应每个input的唯一id -->
            <label for={id + dtlCd.dtlCd}>
                    <input
                        id={id + dtlCd.dtlCd}
                        type="radio"
                        {name}
                        style="width: {width}"
                        value={dtlCd.dtlCd}
                        <!-- 不要写死checked,可根据需求绑定默认选中值 -->
                        checked={dtlCd.dtlCd === '默认选中的dtlCd'}
                    />{dtlCd.dtlNm} 
            </label>
    {/each}
{/await}    

父页面修改:

import { onMount } from 'svelte';
import Radio from '$comp/formObject/RadioCode.svelte';

// 子组件加载完成后执行的逻辑
function handleRadioLoaded() {
    const radio = document.getElementsByName('apple')[0];
    if (radio?.checked) {
        document.getElementById('apple_txt').disabled = true;
    }
}

<Radio id="apple" name="apple" grpCd="fruit_CD" onLoaded={handleRadioLoaded}/>
<input id="apple_txt" name="apple_txt" type="text"/>

方案2:子组件暴露加载状态,父组件监听状态变化

让RadioCode.svelte暴露一个loaded状态变量,父组件通过双向绑定监听该状态,当状态变为true时执行逻辑。

修改RadioCode.svelte:

<script>
    export let id='';
    export let name='';
    export let grpCd='';
    export let radioList= [];
    export let loaded = false; // 暴露加载完成状态
    
    async function radioData() {
        const param = new FormData();
        param.append('grpCd', grpCd);
        
        const response = await Api.post('Controller Url', param);   
        radioList= response.data;
        loaded = true; // 更新加载状态
    }
</script>
{#await radioData () then radioList}
    {#each radioList as dtlCd}
            <label for={id + dtlCd.dtlCd}>
                    <input
                        id={id + dtlCd.dtlCd}
                        type="radio"
                        {name}
                        style="width: {width}"
                        value={dtlCd.dtlCd}
                        checked={dtlCd.dtlCd === '默认选中的dtlCd'}
                    />{dtlCd.dtlNm} 
            </label>
    {/each}
{/await}    

父页面修改:

import { onMount } from 'svelte';
import Radio from '$comp/formObject/RadioCode.svelte';

let radioLoaded = false;

// 响应式监听加载状态变化
$: if (radioLoaded) {
    const radio = document.getElementsByName('apple')[0];
    if (radio?.checked) {
        document.getElementById('apple_txt').disabled = true;
    }
}

<Radio id="apple" name="apple" grpCd="fruit_CD" bind:loaded={radioLoaded}/>
<input id="apple_txt" name="apple_txt" type="text"/>

方案3:用响应式状态替代DOM操作(推荐,符合Svelte设计理念)

避免直接操作DOM,让子组件暴露选中的radio值,父组件通过双向绑定监听该值,自动控制输入框的禁用状态。

修改RadioCode.svelte:

<script>
    export let id='';
    export let name='';
    export let grpCd='';
    export let radioList= [];
    export let value = ''; // 暴露选中的radio值
    
    async function radioData() {
        const param = new FormData();
        param.append('grpCd', grpCd);
        
        const response = await Api.post('Controller Url', param);   
        radioList= response.data;
        // 默认选中第一个选项(可根据需求调整)
        if (radioList.length > 0) {
            value = radioList[0].dtlCd;
        }
    }
</script>
{#await radioData () then radioList}
    {#each radioList as dtlCd}
            <label for={id + dtlCd.dtlCd}>
                    <input
                        id={id + dtlCd.dtlCd}
                        type="radio"
                        {name}
                        style="width: {width}"
                        value={dtlCd.dtlCd}
                        bind:group={value} <!-- 用bind:group绑定选中值 -->
                    />{dtlCd.dtlNm} 
            </label>
    {/each}
{/await}    

父页面修改:

import { onMount } from 'svelte';
import Radio from '$comp/formObject/RadioCode.svelte';

let radioValue = '';
// 响应式控制输入框禁用状态(替换DOM操作)
$: appleTxtDisabled = radioValue === '需要禁用的dtlCd值';

<Radio id="apple" name="apple" grpCd="fruit_CD" bind:value={radioValue}/>
<input id="apple_txt" name="apple_txt" type="text" disabled={appleTxtDisabled}/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:30:59