切换 HTML 布尔属性的新方法 Element.toggleAttribute()

切换 HTML 布尔属性的新方法 Element.toggleAttribute()

HTML 中有一些属性叫做布尔属性(Boolean Attribute),只要属性名存在,不管属性值是什么、存不存在,都代表对应的某个内部状态为 true,只有属性名不存在,才代表 false。 比如常见的 <input>上的 disabledreadonly,或者 <video>上的 controlsloop 等。

规范小课堂:

真正的规范中布尔属性合法的属性值只有空字符串(等价于不写)和与属性名同名的字符串两种,其它都是非法的,比如 disabled=disabled或者 disabled=""/disabled,但浏览器的实现不会这么严格。

如何切换布尔属性的值

既然是个布尔值,就会有来回切换的需求,比如从 true改成 false,或者从 false改回true。回到布尔属性上来说的话,就是在删除一个属性和添加一个属性之间来回切换。

HTML 规范中内置的这些布尔属性,都会在 DOM 上存在同名(大小写可能不同,比如 readonly 的反射属性叫 readOnly)的反射属性,比如 HTML 是 <input disabled>的话,就会存在个input.disabled 属性且初始值是 true,你还可以通过 DOM 属性来修改原本的 HTML 属性,比如执行 input.disabled = false后,HTML 中的 disabled属性就不存在了。所以假设foo是一个内置的布尔属性,我们可以通过 element.foo = !element.foo这样简单的代码来实现布尔属性的切换。

规范小课堂:

我们常常不知道在口头上该怎么区分 HTML 中的属性和 DOM 中的属性,有些人认为正规的叫法应该是 HTML attribute 和 DOM property,其实规范中的叫法是 content attribute 和 IDL attribute,因为 DOM API 的规范是用 WebIDL 语言描述的,懂了吗,接下来试着读一下规范中这段讲布尔属性反射规则的话 html.spec.whatwg.org/#

但如果我们想切换的属性不是一个 HTML 中内置的布尔属性,而是在自身业务中,比如说在普通的 div标签上定义的一个布尔属性呢?再想想未来的规范的话,我们自己创建的一个 custom element 上定义的布尔属性该怎么切换呢?那可能就需要自己用 setAttribute()/removeAttribute()方法封装一个函数了。

jQuery 有没有这样的方法?并没有,jQuery 只有个 toggleClass(),并没有toggleAttr()

Element.toggleAttribute() 来了

去年一名 Mozilla 的工程师建议在 DOM 规范中添加一个切换布尔属性的方法,经过一段时间的讨论,昨天这个方法终于进规范了,名字叫做 toggleAttribute(),它有两个参数(name, force),第一个参数是要切换的属性名,第二个参数是一个可选的布尔类型参数,表示是否强制删除还是强制添加这个属性,而不再是简单的切换了:

input.toggleAttribute('disabled') 
// 相当于现在的 input.disabled = !input.disabled

input.toggleAttribute('disabled', input.value > 10) 
// 相当于现在的 input.disabled = input.value > 10

如果你已经熟悉 jQuery 的 toggleClass()和原生的 classList.toggle() 方法的话,会发现这三个 API 的设计是一模一样的。

我已经在 MDN 上写好了这个方法的文档 Element.toggleAttribute(),建议读一遍我写的 Polyfill,就能完全理解了它是在干什么了。

不要切换普通属性

你可能有过将一个非布尔属性的值来回在某两个值比如 foobar之间切换的需求,toggleAttribute() 不是用来干这个的。

toggleAttribute()不会保留普通属性原来的属性值,比如 <div foo=bar>的话,执行一次 toggleAttribute('foo')foo属性不存在了,再执行一次 foo又回来了,但它的属性值会是空字符串,而不会是bar

浏览器的实现进度

Firefox 已经实现了,其它三大浏览器厂商也已经明确表态会实现这个方法。

发布于 2018-06-22

文章被以下专栏收录