關於JS更新input元素的value屬性引起的狗血討論

來個面試題:
  1. 在瀏覽器中,對於input節點的用戶輸入,什麼時候觸發"change"事件呢?
  2. 在瀏覽器中,JS更新input的value屬性,會觸發"change"事件嗎?
  3. 若是不會觸發,請問爲何?有什麼辦法解決嗎?
根據對上面問題的理解,我分爲如下三個認知階段:


第一階段:讀者只須要答案便可:
  1. 當input在用戶輸入後,節點失去焦點的時候觸發」change"事件,而且在「input"事件以後;
  2. 若是讀者沒理解,能夠看下面的代碼; 結論是:不會觸發」change"事件
  3. 目前搜索到的W3C規範中,貌似沒有這樣的能力,包括:"MutationObserver";固然,若是開發者調用dispatchEvent的方式不算;
若是讀者只在意結論的話,就能夠不往下看了;下面聊下W3C的定義;

第二階段:W3C的規範約束:
你們是否好奇:JS更新input的value屬性,爲何不觸發"change"事件呢?
因此,咱們來看下 W3C是如何定義"change"事件的,下面摘自連接中:
The onchange event occurs when a control loses the input focus and its value has been modified since gaining focus. This attribute applies to the following elements: INPUT, SELECT, and TEXTAREA.
規範說:該事件源於input控件在 用戶操做後失去焦點而且value變化時觸發;
另外,咱們再看看 W3C是如何定義value更新的行爲的,下面摘自連接中:
value On getting, return the current value of the element. On setting: 1. Let oldValue be the element's value. 2. Set the element's value to the new value. 3. Set the element's dirty value flag to true. 4. Invoke the value sanitization algorithm, if the element's type attribute's current state defines one. 5. If the element's value (after applying the value sanitization algorithm) is different from oldValue, and the element has a text entry cursor position, move the text entry cursor position to the end of the text control, unselecting any selected text and resetting the selection direction to "none".
能夠看到:其中並無約定要觸發"change"事件;
因此各種瀏覽器不觸發事件是很正確的表現了;
若是讀者只在意W3C定義的話,就能夠不往下看了;下面聊聊爲何;

第三階段:爲何W3C這麼定義;
你們是否好奇:JS更新input的value屬性,W3C爲何不觸發"change"事件呢?
有人說,W3C就是這麼定義的啊!
實際上,我想問的是:爲何W3C這麼定義呢?
我以爲"change"事件這麼定義在語義上有問題,若是不想有問題,那麼辦法有兩種:
  1. JS更新,觸發」change"事件;
  2. 將規範中的"change"事件名稱,改名爲:"userchange"或者"uachange";(ua表明user agent)
爲何說語義有問題,解釋以下:
站在開發者的認知角度上,"change"表明的是一種"狀態"的變化,它不在意是"主動改變"仍是"被動改變";主動爲用戶的輸入改變,被動爲代碼層面的更新賦值;
按照正常人對上面"change"單詞的語義理解,JS更新value,也屬於一種狀態change(更況且UI都會變化),就應該觸發"change"事件纔對;
帶着這個疑問我問了一圈身邊的開發者,有了下面的對話:
做者:問個問題:經過JS修改input的value值,爲何監聽的input,change事件不會觸發呢?爲何這麼設計? 

大壯:我理解的change事件應是在value只改變且失去焦點時纔會觸發,應該是從性能上考慮的吧 html

翠花:value的改變是事件觸發的結果,若是變成緣由是否是就死循環了 二壯:應該是避免事件冒泡致使沒必要要的性能損失吧,我猜的html5

 W3C:When the change event applies, if the element does not have an activation behavior defined but uses a user interface that involves an explicit commit action, then any time the user commits a change to the element's value or list of selected files, the user agent must queue a task to fire a simple event that bubbles named change at the input element, then broadcast formchange events at the input element's form owner. git

做者:Chrome源碼沒看到線索,查了W3C,我理解這麼個意思: change事件屬於用戶GUI操做產生的,對於經過JS改變的行爲,不屬於這類管理範圍; 做者:我深深以爲這是web的坑,很早這種行爲就定了,又無法兼容。你看Android就不是這種行爲呀。從名字上來講,input事件不觸發合理,change事件名,從直觀理解就應該觸發呀。js更新不算change?github

 對話:... 後面又聊到了"event loop"與異步機制,對話走偏了,就不扯了;web

事實上,若是在Android平臺中,經過代碼修改,確實會觸發相似的"textchanged"事件的;
因爲兩個平臺表現不一致,沒辦法,在 Github帶着疑問去W3C問了;


老外效率真心高,次日就回復了;
老外2: Unfortunately, we cannot change the names of events that have been dispatching for over two decades.
事實證實了個人見解, 規範的原始定義形成了既成事實
若是硬要揪毛病,確實不合適;可是已經定義了20多年了,再改很容易不兼容!

好了,截止這裏就結束了;

之因此問這個問題,是由於快應用在設計的時候,就面臨着:面試

到底遵照W3C規範(不觸發),仍是Android其它平臺(觸發)的行爲;

我的見解,應該觸發事件,不遵照規範;瀏覽器

相關文章
相關標籤/搜索