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
相关产品推荐
相关产品推荐

