核心原因:{{ }} 是「单向绑定」,不是双向绑定
在微信小程序里,WXML 中的 {{ }} 只负责 数据 → 视图 一个方向:
例如:
<switch type="switch" checked="{{switchChecked}}" bindchange="switchChange" />
data.switchChecked ──{{ }}渲染──▶ 视图上 switch 的显示状态
它只做一件事:读取 switchChecked 的值,把开关渲染成对应状态。它没有能力反向写回 switchChecked。
对比一下:
框架 写法 方向
Vue v-model="switchChecked" 双向(读 + 写)
小程序 checked="{{switchChecked}}" 仅单向(读)
小程序里没有 v-model 这种语法糖。用户拨动开关时,框架只是根据新状态重绘视图,但不会自动去改 data.switchChecked。
那值从哪来?
用户操作产生的「新值」不会自己跑进 data,它被放在 事件对象 里,需要你手动接住:
code
用户拨动 switch
└─▶ 触发 bindchange 事件
└─▶ 事件对象 e.detail.value = 新的 true/false
└─▶ 你必须 setData 才能写回 data
所以完整链路是「视图 → 事件 → setData → data → 视图」,缺了 bindchange + setData 这一环,switchChecked 就永远停在初始值。
换个角度理解
checked="{{switchChecked}}" 相当于一句只读的赋值:
js
// 它等价于:把 switchChecked 读出来给 checked,仅此而已
switch.checked = data.switchChecked; // 方向:data → view
它并不是:
js
// 小程序不支持这种自动回写
switchChecked = switch.checked; // 方向:view → data(需要你自己做)
一个容易踩的坑
如果只写 checked="{{switchChecked}}" 而不接 bindchange,会出现「开关点了会弹回」的现象:
你拨动开关 → 视图短暂变化
但没有任何 setData 改 switchChecked
下一次渲染时,框架又用 switchChecked(还是旧值)重新渲染 → 开关被「拉回」原状
这也正是你之前 console.log(this.data.switchChecked) 一直是 false 的根本原因:{{ }} 从来没有、也不会去改这个变量。
一句话总结:{{ }} 只读不写,想让开关状态存进 data,必须靠 bindchange 拿到 e.detail.value 再 setData 写回去。