引子
上周项目中有一常见的场景需求:一组 checkbox
,然后一 checkbox
控制该组的全选/全不选状态,如该组未全选中需展示成半选中的状态。可能我描述的不够清楚,反正就是如下的样子(我用 jQuery 写了个 demo)。实现起来并不复杂,为了保持跨浏览器样式一致性,之前是其他 DOM 元素去模拟 checkbox
,半选状态是用添加特殊的 className
然后去实现对应的样式。为了提升效率(其实是懒),这次我直接用了系统控件。结果问题来了,原生控件半选模式怎么展示?学了这么多年 HTML,抓耳挠腮貌似没有表示 checkbox
半选状态的属性。
-
🍌香蕉 🍎苹果 🍑桃子
Solution
鲁迅曾经说过:
世界上没有百度不出来的东西,如果有,那就换 Google!
via心里MMP的鲁迅
一番面向 Google 编程之后,是我自己孤陋寡闻了,实际上有这么一个属性 indeterminate
,将其设置成 ture
即可让 checkbox
看起来是未完全选中的样子。indeterminate
并不是新出现的,很久以前它还是 IE 的一个私有属性,IE5 就支持,后来的浏览器基本上都支持,同人逼死官方啊。另外这个属性需要注意了,虽然都翻译成属性,但这是特指的是 DOM 对象属性而不是 HTML 属性。还不理解赶快了解下 jQuery 中 attr()
与 prop()
的区别。
直接添加 HTML 属性(attribute) 这么做是无效的。
<!--这样是无效的-->
<label><input type="checkbox" id="checkbox-demo" indeterminate="true"> 这样是无效的</label>
你要改变的是 DOM 对象的属性(property)才可以。
<label><input type="checkbox" id="checkbox-demo"> 这样才行</label>
<script>
var checkbox = document.getElementById("checkbox-demo");
checkbox.indeterminate = true;
</script>
那么与标题中的 Vue.js 有半毛钱关系?因为我们的项目是基于 Vue.js v1.x 版本,但是该版本的 Vue.js 并没有添加对 checkbox
属性 indeterminate
的支持。也就是说,如下的代码是无效的:
<label><input type="checkbox" id="checkbox-demo" v-indeterminate="true"> 这是无效的</label>
<label><input type="checkbox" id="checkbox-demo" :indeterminate="true"> 这也是无效的</label>
且在实际场景中,所有的 checkbox
都是通过遍历生成的,所以拿到 DOM 引用是个问题。幸好有 directive
,自定义指令中 this.el
可以指向绑定的 DOM 对象,我们可以通过实现一个特定的自定义指令来兼容之:
<div id="app">
<label>
<input type="checkbox" id="theCheckbox"
v-indeterminate="setting"
v-model="value"
/>
<span>A checkbox</span>
</label>
</div>
<script typp="javascript">
new Vue({
el: "#app",
data: {
setting: false,
value: false
},
directives: {
// In Vue 1.x
indeterminate: function(value) {
this.el.indeterminate = Boolean(value)
}
}
});
</script>
Vue.js 2.x 版本就好办了,直接这么办即可:
<input type="checkbox" :indeterminate.prop="true">
另外 indeterminate
状态在 CSS 中是有伪类的。:indeterminate
可表示状态不确定的表单元素:
/* Selects any <input> whose state is indeterminate */
input:indeterminate {
background: lime;
}
问题
indeterminate 属性在 iOS Safari 并不支持- indeterminate 属性在各个浏览器中演示表现有差异