关于如何更好的监听元素属性的变化(转)

我们都知道,jQuery有一个onchange的事件来判断类似input或者textarea标签值变化的事件。

jQuery中是通过比如keyup,blur,click等事件来监听值的变化,如果变化就触发change事件。

jQuery.event.special.change = {
        filters: {
            focusout: testChange,

            beforedeactivate: testChange,

            click: function( e ) {
                var elem = e.target, type = elem.type;

                if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
                    testChange.call( this, e );
                }
            },

            // Change has to be called before submit
            // Keydown will be called before keypress, which is used in submit-event delegation
            keydown: function( e ) {
                var elem = e.target, type = elem.type;

                if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
                    (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
                    type === "select-multiple" ) {
                    testChange.call( this, e );
                }
            },

            // Beforeactivate happens also before the previous element is blurred
            // with this event you can‘t trigger a change event, but you can store
            // information
            beforeactivate: function( e ) {
                var elem = e.target;
                jQuery._data( elem, "_change_data", getVal(elem) );
            }
        },

        setup: function( data, namespaces ) {
            if ( this.type === "file" ) {
                return false;
            }

            for ( var type in changeFilters ) {
                jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
            }

            return rformElems.test( this.nodeName );
        },

        teardown: function( namespaces ) {
            jQuery.event.remove( this, ".specialChange" );

            return rformElems.test( this.nodeName );
        }
    };

YUI3中也有一个模块,叫做value-change模块,YUI3中使用了一个50毫秒的定时器来定期检查value的变化

其实一开始的时候我觉得很纳闷,为什么浏览器原生有对值变化进行监听的事件,而yui和jquery却都不采用呢?

先说说原生的解决方案:

ie下有onpropertychange,onchange两个事件来监听一个元素下属性的变化

onchange的介绍

Fires when the contents of the object or selection have changed.

详细:http://msdn.microsoft.com/en-us/library/ms536912(v=VS.85).aspx

例子:http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/refs/onchangeEX.htm

实际上onchange却是在blur,也就是失去焦点的时候才会触发,这明显不是我们想要的

那么,onpropertychange呢?

Fires when a property changes on the object.

详细介绍:http://msdn.microsoft.com/en-us/library/ms536956(v=VS.85).aspx

例子:http://samples.msdn.microsoft.com/workshop/samples/author/dhtml/refs/onpropertychangeEX.htm

嗯,或许在ie下,onpropertychange更合适,可以直接在改变值的时候进行触发。

除了ie之外的浏览器上,解决方案就百花齐放了

首先,firefox有自己的一个watch方法,使用方法就是el.watah(“property”, callback),这个watch可以用于监听所有对象类型的属性改变,详细在https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch

比较通用的一个方法是input事件,在除了ie之外的浏览器都支持这个事件,不过现在的ie9也开始支持input事件了,这个事件和onpropertychange不一样的是input事件只监听内容文本的变化,也就是对value值的改变

Occurs when the text content of an element is changed through the user interface.

因为对value值的改变实际上也是对dom树的改变(dom树不仅仅是结构,也包括它的内容和属性),所以我们可以用dom level 2的 mutation event,比如DOMAttrModified,具体可以查看http://www.w3.org/TR/DOM-Level-3-Events/#event-type-DOMAttrModified,也可以阅读https://developer.mozilla.org/En/XUL/Events#Mutation%5FDOM%5Fevents,现在,chrome和safari对这些事件有比较好的支持

那么,我们回到之前的问题,为什么jQuery和YUI都没有选择使用这些浏览器原生提供的接口,而是另辟蹊径呢?

MDN里这么写的:

It should be noted that the presence of any mutation event listeners in a document degrades the performance of subsequent DOM operations in that document. In simple tests that can mean that a DOM operation takes between 1.5 and 7 as long as it would without any mutation listener. More information can be found in the “performance impact of DOM mutation listeners” threadin mozilla.dev.platform.

那么,它给的链接里有什么呢?

Boris Zbarsky这位同学把这个问题解释了一下:

Mutation listeners cause slowdown in two ways:

1)  Firing the event takes time O(tree depth at which mutation
happened), with a constant that can easily be comparable to the
cost of the mutation itself.
2)  Creating the event object includes various operations to grab the
information mutation event objects carry (e.g. the old and new
values for attribute changes); generating this can be expensive,
because generating the string representation of some attributes is
expensive (thing multi-dozen-kilobyte SVG path attribute, or large
inline style block), and because conversion from our internal types
to the ones mutation events want is expensive for nodes.

鉴于这段比较重要,所以我还是翻译一下吧

1.触发一个事件的时间复杂度是O(大小随着修改所在的dom深度变化),通过这个变量O,我们可以比较清楚的了解这个损耗的大小

2.创建一个事件对象的时候包括了各种操作,这些操作需要去抓取mutation事件对象时的信息,比如修改前的值和修改后的值(要做个比较)。执行这些操作是比较耗费资源的,因为为这些值生成一个字符串来做比较是很耗资源的(比如一堆SVG路径属性,或者大量的内联样式)。从一个内部类型转换到mutation事件对象所需要的类型也是非常耗时的。

那为什么不用oninput呢?

这是因为input事件只能监听textarea,type为password或者text的input,像type=checkbox这类的input就无法处理,显的不够通用。

理顺这些之后,就开始明白YUI和JQUERY各自选择的理由了

--完--

原文地址:http://www.f2es.com/better-way-listen-change/, 感谢原作者分享

时间: 2024-08-27 19:33:45

关于如何更好的监听元素属性的变化(转)的相关文章

监听元素属性改变事件的方法

一.onchange事件只在键盘或者鼠标操作改变对象属性,且失去焦点时触发,脚本触发无效.(就是说你在输入框中输入完内容,输入完了,然后鼠标点别的地方触发该事件)二.oninput事件oninput 事件在用户输入时触发.不支持JS等赋值改变的元素属性.该事件在 <input> 或 <textarea> 元素的值发生改变时触发.(也就是说,不用输入完,边输入边触发该事件)①但是,这个方法是HTML5中的标准事件,IE9以下的浏览器是不支持oninput事件的.②使用时,还需要oni

oninput和onpropertychange实时监听输入框值的变化

传统监听输入框的做法就是使用keyup.keydown.keypress,或者change事件来实现,但keyup.keydown.keypress事件是只要完成击键事件后就触发,不考虑输入框的值是否变化,也监听不了使用鼠标右键[剪贴]和[粘贴]这些操作,更监听不了使用JS动态改变值的变化.而change事件必须是焦点离开输入框后才触发,并不能实时监听.所以这几个事件来监听输入框值变化并不完美.ie浏览器(ie6-8)可以直接使用onpropertychange事件来实时监听(包括JS动态改变值

android 监听网络状态的变化及实战

android 监听网络状态的变化及实际应用 转载请注明博客地址:http://blog.csdn.net/gdutxiaoxu/article/details/53008266 平时我们在请求错误的情况下,通常会进行处理一下,一般来说,主要分为两方面的错误 - 没有网络的错误 - 在有网络的情况下,我们客户端的错误或者服务器端的错误 今天这篇博客主要阐述以下问题 怎样监听网络状态的变化,包括是否打开WiFi,否打开数据网络,当前连接的网络是否可用 网络没有打开情况下的处理,如弹出对话框,跳转到

关于实时监听输入框的值变化

实时监听文本框值变化是非常常见的功能,通常最简单的办法就是用keyup,keydown来实现,但是这种方法有两个问题,一个是当直接复制粘贴的时候没法监听到事件,另外一个问题是在移动端,使用删除键删除输入时候也无法监听到! 解决办法: 1.使用onchange事件 onchange事件是文本框内容改变并失去焦点的时候才触发. 2.比较完美的解决办法:oninput和onproper oninput 是 HTML5 的标准事件,对于检测 textarea, input:text, input:pas

javascript --- 实时监听输入框值的变化

实时监听文本框值变化是非常常见的功能,通常最简单的办法就是用keyup,keydown来实现,但是这种方法有两个问题,一个是当直接复制粘贴的时候没法监听到事件,另外一个问题是在移动端,使用删除键删除输入时候也无法监听到! 解决办法: 1.使用onchange事件 onchange事件是文本框内容改变并失去焦点的时候才触发. 2.比较完美的解决办法:oninput和onproper oninput 是 HTML5 的标准事件,对于检测 textarea, input:text, input:pas

vue中监听window.resize的变化

我只想说每个人遇到的bug真的不能一概而论,解决办法也会有不同.在vue中使用echarts的时候,会想要实现window.resize窗体变化大小的时候让图形大小跟着变化.实现的过程中各种bug,也真的让人有种想要发狂的感觉.但是还好,最后在不断的查资料和尝试当中.实现了想要的效果,仅供参考: 首先我这里实现的效果是切换echart图形,然后在window.resize过程中想要实现自适应窗口大小的变化. 这里的两个button分别是控制两个路由切换,也就是两个echart图形(柱状图和饼图)

js 实时监听input中值变化

js 实时监听input中值变化 分类: Javascript2014-05-11 11:13 849人阅读 评论(0) 收藏 举报 [html] view plaincopyprint? <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>RunJS

17.swift怎么监听该属性的改变

import UIKit class Person : NSObject { var name : String? { // 可以给newValue自定义名称 willSet (new){ // 属性即将改变,还未改变时会调用的方法 // 在该方法中有一个默认的系统属性newValue,用于存储新值 print(name) print(new) } // 可以给oldValue自定义名称 didSet (old) { // 属性值已经改变了,会调用的方法 // 在该方法中有一个默认的系统属性ol

Android_通过ContentObserver监听短信数据变化

1.简介 在小米等一些机型,无法接收系统发出的短信广播.只能通过观察者ContentObserver,去监听短信数据的变化 2.SMS数据介绍 content://sms/inbox        收件箱 content://sms/sent        已发送 content://sms/draft        草稿 content://sms/outbox        发件箱 content://sms/failed        发送失败 content://sms/queued