Plus FAQ Accordion
介绍
基于原生 details 的问答列表,细线分隔,展开时加号旋转成叉号,答案轻微下滑淡入;同一时间只展开一项,没有脚本也能正常工作。
拆自整页模板 器枢 智能体工具接入平台首页,可以单独使用,也能和同一模板拆出的其他组件拼回整页。
纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 Plus FAQ Accordion 加进你的项目并换成你的配色。
适用场景
常见问题(FAQ)、折叠面板、可展开的说明和设置分组。
安装
订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。
$ npm i -g @8pt-dev/cli && 8pt add plus-faq-accordion
mcp › 使用 8pt MCP 调用 get_component("plus-faq-accordion")
代码
Plus FAQ Accordion 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。
<div class="x-qfa"><section class="qs-faq" id="faq"><div class="qs-wrap qs-faq__in"><h2 class="qs-h2">常见问题。</h2><div class="qs-qs"><details class="qs-q" open><summary><span>每家供应商都要单独申请密钥吗?</span><i aria-hidden="true"></i></summary><div class="qs-a"><p>不用。所有调用都走同一个账户,各家供应商的鉴权由平台在后台代为处理。</p></div></details><details class="qs-q"><summary><span>费用怎么计算?</span><i aria-hidden="true"></i></summary><div class="qs-a"><p>按调用次数结算。每个工具的单价都标在目录里,调用之前就能看到。</p></div></details><details class="qs-q"><summary><span>调用失败也会扣费吗?</span><i aria-hidden="true"></i></summary><div class="qs-a"><p>不会。供应商返回错误时不计费,预扣的金额会原样退回余额。</p></div></details><details class="qs-q"><summary><span>支持哪些智能体框架?</span><i aria-hidden="true"></i></summary><div class="qs-a"><p>只要能读取 Skill、连接 MCP 或执行命令行,就能接入,不挑框架。</p></div></details><details class="qs-q"><summary><span>有调用频率限制吗?</span><i aria-hidden="true"></i></summary><div class="qs-a"><p>有,按工具分别设定。接近上限时会提前返回提示,方便智能体自行降速或换用同类工具。</p></div></details></div></div></section></div>
.x-qfa{--acc:#0016D7;--ink:#1c1c1e;--mut:#6e6e73;--line:#ececee;--soft:#fafafa;
--sans:"Inter","PingFang SC","Hiragino Sans GB","Noto Sans CJK SC","Microsoft YaHei",system-ui,sans-serif;
--mono:ui-monospace,"SFMono-Regular","JetBrains Mono",Menlo,Consolas,"DejaVu Sans Mono",monospace;
font-family:var(--sans);color:var(--ink);-webkit-font-smoothing:antialiased;line-height:1.5;width:100%;box-sizing:border-box;text-align:left}.x-qfa *,.x-qfa *::before,.x-qfa *::after{box-sizing:border-box;margin:0;padding:0}.x-qfa a{color:inherit;text-decoration:none}.x-qfa button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}.x-qfa .qs-wrap{max-width:1100px;margin:0 auto;padding:0 24px}.x-qfa .qs-h2{font-size:clamp(30px,4.4vw,52px);font-weight:800;letter-spacing:-.035em;line-height:1.08;text-align:center}.x-qfa .qs-mark{display:inline-grid;grid-template-columns:repeat(2,6px);gap:2px;transform:rotate(45deg);margin:0 2px}.x-qfa .qs-mark i{width:6px;height:6px;border-radius:1.5px;background:currentColor;display:block}.x-qfa .qs-mark i:nth-child(4){opacity:.35}.x-qfa .qs-faq{padding:112px 0 96px}.x-qfa .qs-faq__in{max-width:860px}.x-qfa .qs-qs{margin-top:52px;border-top:1px solid var(--line)}.x-qfa .qs-q{border-bottom:1px solid var(--line)}.x-qfa .qs-q summary{list-style:none;display:flex;align-items:center;justify-content:space-between;gap:24px;padding:20px 0;font-size:17px;font-weight:500;cursor:pointer}.x-qfa .qs-q summary::-webkit-details-marker{display:none}.x-qfa .qs-q summary i{position:relative;flex:none;width:14px;height:14px;transition:transform .3s cubic-bezier(.2,.7,.2,1)}.x-qfa .qs-q summary i::before,.x-qfa .qs-q summary i::after{content:"";position:absolute;left:0;top:6.5px;width:14px;height:1.5px;background:#55555a;border-radius:1px}.x-qfa .qs-q summary i::after{transform:rotate(90deg)}.x-qfa .qs-q[open] summary i{transform:rotate(45deg)}.x-qfa .qs-q summary:hover span{color:var(--acc)}.x-qfa .qs-a{padding:0 40px 22px 0;color:var(--mut);font-size:15px;line-height:1.75;animation:xqfaA .35s ease}@keyframes xqfaA{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion:reduce){.x-qfa .qs-q summary i{transition:none}.x-qfa .qs-a{animation:none}}.x-qfa .qs-faq{padding:72px 0;min-height:min(860px,96vh);display:flex;flex-direction:column;justify-content:center;background:#fff radial-gradient(#e6e6ec 1px,transparent 1.3px) 0 0/18px 18px}.x-qfa .qs-qs{background:#fff;padding:0 20px;border-radius:12px;border:1px solid var(--line)}.x-qfa .qs-q:last-child{border-bottom:0}
(root) => {
const el = (root.classList && root.classList.contains('x-qfa')) ? root : (root.querySelector('.x-qfa') || root);
const offs = [];
const qs = [...el.querySelectorAll('details')];
qs.forEach((d) => {
const on = () => { if (d.open) qs.forEach((o) => { if (o !== d) o.open = false; }); };
d.addEventListener('toggle', on); offs.push(() => d.removeEventListener('toggle', on));
});
return () => offs.forEach((f) => f());
}订阅 Builder 查看完整源码。查看价格