details 标签不支持 v-model,需用 :open 绑定布尔值并配合 @click.prevent 手动切换 isDetailsOpen 状态,或监听 toggle 事件获取 $event.target.open 值以确保状态同步。

details 标签本身不支持 v-model
直接在 <details> 上写 v-model 会报错或静默失效,因为 Vue 的 v-model 只对原生表单控件(input、textarea、select)和组件实现的 v-model 接口生效。<details> 是普通 HTML 元素,没有内置的 value 属性或 input 事件语义,Vue 不会自动为其建立双向绑定。
用 v-bind + @click 模拟 open 状态控制
要响应式控制 <details> 的展开/收起,必须手动绑定 open 属性,并监听点击(或 toggle 事件)来更新数据。注意:<details> 的原生行为是点击 <summary> 触发 toggle,但该事件无法被 Vue 直接捕获为输入事件,所以更稳妥的做法是监听 @click 并阻止默认行为后手动切换状态。
- 在
data或ref中定义一个布尔值,如isDetailsOpen - 用
:open="isDetailsOpen"绑定open属性(注意是:open,不是v-model) - 给
<summary>添加@click.prevent="isDetailsOpen = !isDetailsOpen",显式切换 - 避免同时依赖原生 toggle 和 Vue 数据,否则状态可能不同步
示例(Vue 3 Composition API):
<details :open="isDetailsOpen"> <summary @click.prevent="isDetailsOpen = !isDetailsOpen">点我展开</summary> <p>这里是详情内容</p> </details>
监听 details 元素的 toggle 事件(Vue 3 支持,Vue 2 需 patch)
原生 <details> 触发 toggle 事件时,Vue 3 的 v-on 可以直接监听;Vue 2 默认不识别该事件,需用 @toggle.native 或通过 ref 手动 addEventListener。
立即学习“前端免费学习笔记(深入)”;
- Vue 3 写法:
@toggle="isDetailsOpen = $event.target.open" - Vue 2 写法:
@toggle.native="isDetailsOpen = $event.target.open"(仅限非自定义组件) - 更兼容的写法(Vue 2/3 通用):用
ref获取元素,在mounted或onMounted中添加原生监听器 - 注意:
$event.target.open返回的是当前真实 DOM 状态,比手动维护的布尔值更可靠
与 computed 或 watch 配合做副作用处理
如果展开/收起需要触发其他逻辑(比如懒加载内容、上报埋点),不要只靠模板表达式,应封装进 watch 或事件回调中。
- 用
watch监听isDetailsOpen变化,比在@click里塞一堆逻辑更清晰 - 若依赖外部状态(如权限控制是否允许展开),用
computed控制:open的可写性,再配合@click.prevent做拦截 - 避免在
summary上同时写@click和让浏览器默认触发toggle,容易造成状态抖动
真正容易被忽略的是:原生 <details> 的 open 属性是布尔属性,但它的 DOM 属性值是字符串 "open" 或 null,而 Vue 的 :open 绑定期望布尔值——Vue 内部已做转换,你只需传 true/false,不用手动写 "open" 字符串。



















