天天看點

android微信裡自帶浏覽器 removeAttribute('style') 失效

例如在某個條件下給動畫設定了 speedHandler.style.webkitAnimation = speedHandler.style.animation = 'none';

在某個時刻想恢複動畫  speedHandler.removeAttribute('style');

在android微信裡自帶浏覽器會失效

做了一些研究,應該算是理清了問題。

首先,我們在這裡常說的「屬性」(attributes)其實分為兩種:内容屬性(content attributes)以及 IDL 屬性(IDL attributes)。

内容屬性指那些在 HTML 中定義的屬性,例如在下面這個 HTML 片段中:

<p class="lede" style="font-size: 1.2em;">

定義了 2 個内容屬性 class 與 style。

IDL 指接口描述語言(Interface definition language),而描述 HTML 的接口所用的描述語言為 Web IDL( http://www.w3.org/TR/WebIDL/)。腳本語言(如 JavaScript)可以通過 HTML 定義的這些接口來進行諸如 DOM 操作的各種處理。(舉個例子,HTML 的 Element 接口描述: http://dom.spec.whatwg.org/#interface-element)。而其中的某些 IDL 屬性就是用來對應内容屬性的。

HTML 規範中有如下描述( http://dev.w3.org/html5/spec/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes):

Some IDL attributes are defined to reflect a particular content attribute. This means that on getting, the IDL attribute returns the current value of the content attribute, and on setting, the IDL attribute changes the value of the content attribute to the given value.

In general, on getting, if the content attribute is not present, the IDL attribute must act as if the content attribute's value is the empty string; and on setting, if the content attribute is not present, it must first be added.

對于 style 屬性,又有這樣的描述( http://dev.w3.org/html5/spec/global-attributes.html#the-style-attribute):

The style IDL attribute must return a CSSStyleDeclaration whose value represents the declarations specified in the attribute. (If the attribute is absent, the object represents an empty declaration.) Mutating the CSSStyleDeclaration object must create a style attribute on the element (if there isn't one already) and then change its value to be a value representing the serialized form of the CSSStyleDeclaration object. The same object must be returned each time.

從上面的兩段内容可以看出,浏覽器在實作 HTML 的接口規範時,會區分處理内容屬性和 IDL 屬性,但對在讀取、修改 IDL 屬性時會對内容屬性作同步處理(對于 style 屬性,兩者具體格式不同,但内容是同質的。比如 div.style.fontSize = '36px' 相當于把内容屬性 style 的值設為 "font-size: 36px;")。

看了上面這一堆,我們應該可以猜測題主所述的這個問題的産生過程:

可能是由于對 "style" 這個内容屬性做了一定的優化,進行了延遲建立(即在第一次運作 setAttribute('style', value) 或 getAttribute('style') 時才建立)。而最開始的 HTML 代碼沒有 style 屬性,是以 Chrome 開始時沒有建立新的内容屬性。而在通過 IDL 屬性修改 div.style.fontSize 後,并沒有導緻 Chrome 建立一個新的内容屬性 "style"。然後在 removeAttribute('style') 時,因為沒有找到此屬性是以也沒有對 IDL 屬性的變化進行修改。從表現來看,最終渲染的屬性值是與 IDL 屬性值保持一緻的,是以無法通過 removeAttribute('style') 來去掉元素的樣式。

也就是說,隻要我們人工保證先建立了 style 内容屬性,就能夠解決這個問題。是以你可以試一下以下的各個方法:

  1. 在 HTML 内容中先随便加入一點 style 比如:
    <div style="margin: 0;">測試</div>
    需要注意的是,用這種方法,在第一次删除樣式後,内容屬性被删除了,之後再删除又不會再生效;
  2. 在每次删除樣式之前任意時間先運作一下 div.getAttribute('style');

    在這種情況下,可以發現,如果 getAttribute('style') 之後才首次修改 IDL 屬性,删除也無法完成,即在 btn[0].onclick 中修改為下面代碼時,也不會導緻内容屬性被建立:

    div.getAttribute('style');

    div.style.fontSize = '36px';

    于是我們可以進一步認為,所謂的「延遲建立」其實不是在第一次getAttribute('style') 或 setAttribute('style', value) 時總會被建立。如果在此之前對應的 IDL 屬性為空,内容屬性亦不會被建立;
  3. 通過 div.setAttribute('style', 'font-size: 36px;') 來設定文字大小。

是以,removeAttribute('style') 生效的前提是,在其運作之前,已經

  1. 用 IDL 屬性添加了樣式并調用了 getAttribute('style') 與 setAttribute('style', value) 其中之一;
  2. 或者直接用 setAttribute('style', value) 來添加樣式。

至于為什麼打開開發者工具就能夠生效,我想也比較明顯了:因為開發者工具在渲染内容的過程中,在已經通過 IDL 屬性修改樣式後調用了 getAttribute('style'),導緻這個内容屬性被建立,于是也就能被正常删除了。

我測試了一下,這個問題對于 Windows 和 Mac 下的 Chrome 與 Safari 均成立,是以應該是 WebKit 的一個 bug。

是以文章開頭解決辦法是設定style的時候用 speedHandler.setAttribute('style','-webkit-animation:none; animation:none; ')

參考連結:http://www.zhihu.com/question/20529237