
本文详解如何使用 alpinejs 实现两级联动下拉框(国家 → 货币),通过 `x-model`、`@change` 和 `x-text` 动态绑定与响应,无需额外 js 文件,纯前端完成数据驱动的 ui 同步。
在构建表单时,级联选择(Cascading Select)是常见需求:用户选择“国家”后,“货币”下拉框应自动切换为该国默认货币,并支持只读展示或隐藏提交。AlpineJS 凭借其轻量、声明式语法和与服务端模板(如 Twig)天然契合的特性,非常适合此类场景。
以下是一个完整、可直接运行的实现方案,基于 CodeIgniter4 + Twig + AlpineJS:
✅ 核心思路
- 将国家列表(含 currencyId 字段)与货币列表(id, name, description)由后端一次性注入视图;
- 使用 x-data 初始化响应式状态(country, currency, currencyData);
- 利用 x-init 安全解析 JSON 数据(注意 Twig 的 |e("js") 防 XSS);
- 通过 data-currency-id 属性在
- @change 事件中提取所选国家对应的货币 ID 并更新 currency 状态;
- 使用 x-model="currency" 自动同步隐藏字段值,确保表单提交正确;
- 用 x-text 结合箭头函数实时查找并渲染货币名称与描述。
? 完整代码示例
<div x-data="{ country: '', currency: '', currencyData: [] }"
x-init="currencyData = JSON.parse('{{ currencyArray|json_encode()|e('js') }}');">
<div class="form-group">
<label for="country">{{ 'country'|translate }}</label>
<select id="country" name="country" class="form-select" aria-label="country"
x-model="country"
@change="currency = $event.target.options[$event.target.selectedIndex].dataset.currencyId">
<option value="">{{ 'select_country'|translate }}</option>
{% for country in countryArray %}
<option value="{{ country.id }}" data-currency-id="{{ country.currencyId }}">
{{ country.description|capitalize|translate }}
</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>{{ 'currency'|translate }}</label>
<input type="hidden" name="currency" x-model="currency">
<span class="text-muted" x-text="
() => {
const matched = currencyData.find(c => c.id == currency);
return matched ? `${matched.name} - ${matched.description}` : '{{ 'select_country_first'|translate }}';
}
"></span>
</div>
<!-- (可选)调试信息 -->
<div class="mt-2 text-sm text-gray-500">
当前国家 ID:<span x-text="country"></span>|当前货币 ID:<span x-text="currency"></span>
</div>
</div>⚠️ 关键注意事项
- 安全转义:务必使用 |e("js")(Twig)对 json_encode() 输出进行 JavaScript 上下文转义,防止 XSS;
- 数据结构一致性:确保 countryArray 中每个对象含 currencyId 字段,且与 currencyArray 中的 id 类型一致(推荐字符串或数字统一);
- 空值处理:初始状态 country: '' 和 currency: '' 需匹配
- 性能考量:本方案适用于货币种类较少(异步加载,建议改用 x-effect 或封装为 alpine-data 外部函数;
- 可访问性增强:为 添加 aria-live="polite" 可提升屏幕阅读器体验(如 )。
✅ 总结
该方案完全遵循 AlpineJS “HTML 优先”的设计哲学,将交互逻辑内聚于模板中,零外部 JS,易于维护与复用。它不仅解决了国家-货币联动问题,更为复杂表单(如省市区三级联动、产品分类与规格联动)提供了清晰可扩展的实现范式。当业务逻辑增长时,可平滑迁移至 Alpine Data Functions 进行解耦升级。










