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

使用shadcn-svelte <Accordion>如何保留<CardNumber>组件状态?

问题描述

在shadcn-svelte的Accordion组件中嵌入svelte-stripe的CardNumber元素时,遇到以下问题:当包含CardNumber的AccordionContent被关闭后,CardNumber的引用会因DOM被移除而丢失,用户再次打开该Accordion项时,CardNumber的输入值会变为null。

相关组件背景:

  • shadcn-svelte Accordion(底层依赖bits-ui Accordion)
  • svelte-stripe CardNumber

代码示例:

<script lang="ts">
  let cardElement: StripeCardNumberElement;
</script>

<AccordionItem value="card">
  <AccordionTrigger>Card</AccordionTrigger>
  <AccordionContent>   
    <div>
      <CardNumber
        on:change={handleCardNumber}
        bind:element={cardElement}
        style={stripeStyle} />
    </div>
   </AccordionContent>
</AccordionItem>
解决方案

方案1:让AccordionContent保持挂载(最简单)

bits-ui的AccordionContent组件支持keepMounted属性,设置为true后,关闭Accordion时内容不会被从DOM中卸载,仅通过CSS隐藏。这样CardNumber元素的引用和输入状态会被完整保留。

修改代码如下:

<script lang="ts">
  let cardElement: StripeCardNumberElement;
</script>

<AccordionItem value="card">
  <AccordionTrigger>Card</AccordionTrigger>
  <!-- 添加keepMounted属性 -->
  <AccordionContent keepMounted={true}>   
    <div>
      <CardNumber
        on:change={handleCardNumber}
        bind:element={cardElement}
        style={stripeStyle} />
    </div>
   </AccordionContent>
</AccordionItem>

方案2:手动缓存并恢复输入值

如果不想让AccordionContent始终挂载,可以在CardNumber的change事件中缓存输入状态,当AccordionContent重新挂载时,通过Stripe元素的API恢复值。

注意:严格遵循Stripe的安全规范,不要在客户端存储完整信用卡号,仅缓存Stripe元素的内部状态值用于恢复输入。

代码示例:

<script lang="ts">
  let cardElement: StripeCardNumberElement;
  // 缓存卡号的状态值(仅用于恢复输入,不会存储敏感数据)
  let cachedCardState: { number?: string } | null = null;

  function handleCardNumber(e: CustomEvent<StripeCardNumberElementChangeEvent>) {
    // 当输入完成时缓存状态
    if (e.detail.complete && cardElement) {
      cachedCardState = cardElement.getValue();
    }
  }

  // 当AccordionContent重新挂载时恢复值
  function onContentMount() {
    if (cardElement && cachedCardState) {
      cardElement.setValue(cachedCardState);
    }
  }
</script>

<AccordionItem value="card">
  <AccordionTrigger>Card</AccordionTrigger>
  <AccordionContent on:mount={onContentMount}>   
    <div>
      <CardNumber
        on:change={handleCardNumber}
        bind:element={cardElement}
        style={stripeStyle} />
    </div>
   </AccordionContent>
</AccordionItem>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 22:22:48