如何通过Svelte Context配置手风琴默认展开及跳转联动功能?
帮助中心FAQ手风琴组件优化方案
问题背景
当前帮助中心FAQ使用的手风琴组件默认全部关闭,需要实现两个核心需求:
- 通过Svelte Context配置,页面加载时指定手风琴默认展开,保留原有交互功能;
- 从网站其他页面跳转至帮助中心时,自动展开目标手风琴及其子菜单。
第一步:修改Accordion.svelte,增强Context与路由匹配能力
给组件添加id属性,通过Context管理展开状态集合,同时监听URL哈希实现跳转自动展开:
<script context="module"> import { setContext, getContext } from 'svelte'; import { writable } from 'svelte/store'; const key = {}; export const getAccordionContext = () => getContext(key); export const createAccordionContext = (defaultOpenIds = []) => { // 存储当前展开的手风琴ID集合,支持多展开(单一展开可改为存储单个值) const openIds = writable(new Set(defaultOpenIds)); // 监听URL哈希变化 const urlHash = writable(window.location.hash.slice(1)); window.addEventListener('hashchange', () => { urlHash.set(window.location.hash.slice(1)); }); const context = { openIds, urlHash }; setContext(key, context); return context; } </script> <script> import { quadInOut } from 'svelte/easing'; import { slide } from 'svelte/transition'; import { onMount } from 'svelte'; export let id = ''; export let open = false; const { openIds, urlHash } = getAccordionContext(); // 子级重新创建Context,避免与父级状态冲突 createAccordionContext(); // 点击切换展开/关闭状态 function handleClick() { $openIds = new Set($openIds); if ($openIds.has(id)) { $openIds.delete(id); open = false; } else { // 若需单一展开模式,取消下方注释清空所有展开状态 // $openIds.clear(); $openIds.add(id); open = true; } } // 同步Context中的展开状态到当前组件 $: if ($openIds.has(id)) { open = true; } else if (open) { open = false; } // 页面加载时匹配URL哈希展开目标手风琴 onMount(() => { if ($urlHash === id) { $openIds.add(id); } }); // 监听哈希变化,实时展开对应组件 $: if ($urlHash === id && !$openIds.has(id)) { $openIds.add(id); } </script> <div class="accordion"> <div class="header" on:click={handleClick}> <div class="text"> <slot name="head"></slot> </div> </div> {#if open} <div class="details" transition:slide="{{ duration: 150, easing:quadInOut }}"> <slot name="details"></slot> </div> {/if} </div> <style> div.accordion { margin: 1rem 0; } div.header { display:flex; width:100%; cursor: pointer; } div.header .text { flex: 1; } div.details { background-color: transparent; padding:1rem; } </style>
第二步:修改App.svelte,配置默认展开与添加唯一ID
给每个手风琴添加唯一ID,同时在创建Context时传入默认展开的ID列表;跳转时只需在URL后拼接#目标ID即可自动展开:
<script> import Accordion, { createAccordionContext } from "./Accordion.svelte" // 配置默认展开的手风琴ID,支持多级嵌套 createAccordionContext(['faq-main-1', 'faq-sub-1']) </script> <Accordion id="faq-main-1"> <div slot="head"> <h2>Test one</h2> </div> <div slot="details"> <ul> <Accordion id="faq-sub-1"> <div slot="head"> <h4>The test of subitem?</h4> </div> <div slot="details"> <li>1</li> <li>2</li> <li>3</li> </div> </Accordion> <Accordion id="faq-sub-2"> <div slot="head"> <h4>Test of subitem 2</h4> </div> <div slot="details"> <li>one</li> <li>two</li> <li>three</li> </div> </Accordion> </ul> </div> </Accordion> <Accordion id="faq-main-2"> <div slot="head"> <h4>Second test</h4> </div> <div slot="details"> <ul> <li>again one</li> <li>two again</li> <li>three repeat</li> </ul> </div> </Accordion> <style> li { margin: 0; padding: 1em; text-align: left; list-style-type: none; cursor: pointer; color: black; } h4, h2 { cursor: pointer; } </style>
功能说明
- 默认展开配置:通过
createAccordionContext(['id1', 'id2'])传入需要默认展开的手风琴ID,页面加载时自动展开对应组件; - 跳转自动展开:其他页面跳转时,使用带哈希的URL(如
/help-center#faq-main-2),手风琴会自动匹配ID并展开; - 保留原有交互:点击头部仍可切换展开/关闭状态,完全兼容原有操作逻辑;
- 展开模式可选:若需同一层级仅展开一个手风琴,取消
handleClick中$openIds.clear()的注释即可。
内容的提问来源于stack exchange,提问作者Tomca z Brodku
相关产品推荐
相关产品推荐

