baobaobao


  • 首页

  • 关于他

  • 博客分类

  • 博客归档

第二十四章笔记

发表于 2018-06-23 | 分类于 JavaScript高级程序设计读书笔记 |

1 避免全局变量

//一个全局变量——我们推荐这样使用
var MyApplication = {
 name: "Nicholas",
 sayName: function(){
 alert(this.name);
 }
}; 

2 定义常量,我们推荐这样

var Constants = {
 INVALID_VALUE_MSG: "Invalid value!",
 INVALID_VALUE_URL: "/errors/invalid.php"
};
function validate(value){
 if (!value){
 alert(Constants.INVALID_VALUE_MSG);
 location.href = Constants.INVALID_VALUE_URL;
 }
} 

3 注意作用域

这里将document用于局部变量,总是有用的,因为我们不需要每次都去作用域链中寻找我们的
全局变量

   function updateUI(){
    var doc = document;
    var imgs = doc.getElementsByTagName("img");
    for (var i=0, len=imgs.length; i < len; i++){
    imgs[i].title = doc.title + " image " + i;
    }
    var msg = doc.getElementById("msg");
    msg.innerHTML = "Update complete.";
   } 
将在一个函数中会用到多次的全局对象存储为局部变量总是没错的。 

4 避免属性查找,多次用到一个属性时,应该把它当做一个局部变量使用

一旦多次用到对象属性,应该将其存储在局部变量中。第一次访问该值会是 O(n),然而后续
的访问都会是 O(1),就会节省很多。例如,之前的代码可以如下重写:

var url = window.location.href;
var query = url.substring(url.indexOf("?"));

这个版本的代码只有 4 次属性查找,相对于原始版本节省了 33%。在更大的脚本中进行这种
优化,倾向于获得更多改进。

5 避免双重解释

JavaScript 代码想解析 JavaScript 的时候就会存在双重解释惩罚。当使用 eval()函数
或者是Function构造函数以及使用 setTimeout()传一个字符串参数时都会发生这种情况。
下面有一些例子:

//某些代码求值——避免!!
    eval("alert('Hello world!')");
//创建新函数——避免!!
var sayHi = new Function("alert('Hello world!')");
//设置超时——避免!!
setTimeout("alert('Hello world!')", 500);

  在以上这些例子中,都要解析包含了 JavaScript 代码的字符串。这个操作是不能在初始的
解析过程中完成的,因为代码是包含在字符串中的,也就是说在 JavaScript 代码运行的同
时必须新启动一个解析器来解析新的代码。
  实例化一个新的解析器有不容忽视的开销, 所以这种代码要比直接解 析慢得多。
对于这几个例子都有另外的办法。只有极少的情况下 eval()是绝对必须的,所以尽可能避免
使用。在这个例子中,代码其实可以直接内嵌在 原代码中。对于 Function 构造函数,
完全可以直接写成一般的函数,调用
setTimeout()可以传入函数作为第一个参数。以下是一些例子:

//已修正
alert('Hello world!');
//创建新函数——已修正
var sayHi = function(){
 alert('Hello world!');
};
//设置一个超时——已修正
setTimeout(function(){
 alert('Hello world!');
}, 500);

如果要提高代码性能,尽可能避免出现需要按照 JavaScript 解释的字符串。

6 优化DOM交互

(1)优化DOM交互
  1. 最小化现场更新
    一旦你需要访问的 DOM 部分是已经显示的页面的一部分,那么你就是在进行一个现场更新。之所
    以叫现场更新,是因为需要立即(现场)对页面对用户的显示进行更新。每一个更改,不管是插入单个
    字符,还是移除整个片段,都有一个性能惩罚,因为浏览器要重新计算无数尺寸以进行更新。现场更新
    进行得越多,代码完成执行所花的时间就越长;完成一个操作所需的现场更新越少,代码就越快。请看
    以下例子:

    var list = document.getElementById("myList"),
    item,
    i;
    for (i=0; i < 10; i++) {
     item = document.createElement("li");
     list.appendChild(item);
     item.appendChild(document.createTextNode("Item " + i));
    }
    

    这段代码为列表添加了 10 个项目。添加每个项目时,都有 2 个现场更新:一个添加

  2. 元素,另
    一个给它添加文本节点。这样添加 10 个项目,这个操作总共要完成 20 个现场更新。
    要修正这个性能瓶颈,需要减少现场更新的数量。一般有 2 种方法。第一种是将列表从页面上移除,
    最后进行更新,最后再将列表插回到同样的位置。这个方法不是非常理想,因为在每次页面更新的时候
    它会不必要的闪烁。第二个方法是使用文档片段来构建 DOM 结构,接着将其添加到 List 元素中。这
    个方式避免了现场更新和页面闪烁问题。请看下面内容:
    就是先一次性建好所有的li再放进去。而不是,建一个,放一个。
  3. var list = document.getElementById("myList"),
     fragment = document.createDocumentFragment(),
     item,
     i;
    for (i=0; i < 10; i++) {
     item = document.createElement("li");
     fragment.appendChild(item);
     item.appendChild(document.createTextNode("Item " + i));
    }
    list.appendChild(fragment);
    

    在这个例子中只有一次现场更新,它发生在所有项目都创建好之后。文档片段用作一个临时的占位
    符,放置新创建的项目。然后使用 appendChild()将所有项目添加到列表中。记住,当给 appendChild()
    传入文档片段时,只有片段中的子节点被添加到目标,片段本身不会被添加的。
    一旦需要更新 DOM,请考虑使用文档片段来构建 DOM 结构,然后再将其添加到现存的文档中。

第二十三章笔记

发表于 2018-06-23 | 分类于 JavaScript高级程序设计读书笔记 |

1 检测网络存在

 /*测试是否有网络*/
  if (navigator.onLine) {
      alert("有网络");
  } else {
      alert("无网络");
  }


/*测试是否有网络触发事件*/  

  EventUtil.addHandler(window, "online", function () {
      alert("Online");
  });
  EventUtil.addHandler(window, "offline", function () {
      alert("Offline");
  });

2 数据存储

####(1)获取cookie的封装方法关于cookie的设定,他是同域的。而且它是以键值对形式出现
var CookieUtil = {
get: function (name) {
var cookieName = encodeURIComponent(name) + “=”,
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if (cookieStart > -1) {
var cookieEnd = document.cookie.indexOf(“;”, cookieStart);
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart

                  + cookieName.length, cookieEnd));
        }
        return cookieValue;
    },
    set: function (name, value, expires, path, domain, secure) {
        var cookieText = encodeURIComponent(name) + "=" +
            encodeURIComponent(value);
        if (expires instanceof Date) {
            cookieText += "; expires=" + expires.toGMTString();
        }
        if (path) {
            cookieText += "; path=" + path;
        }

        if (domain) {
            cookieText += "; domain=" + domain;
        }
        if (secure) {
            cookieText += "; secure";
        }
        document.cookie = cookieText;
    },
    unset: function (name, path, domain, secure) {
        this.set(name, "", new Date(0), path, domain, secure);
    }
}; 

小结

离线 Web 应用和客户端存储数据的能力对未来的 Web 应用越来越重要。浏览器已经能够检测到用

户是否离线,并触发 JavaScript 事件以便应用做出处理。可以指定在应用缓存中保存哪些文件以

便离线时使用。对于应用缓存的状态及变化,也有相应的 JavaScript API 可以调用检测。
本书还讨论了客户端存储的以下几方面内容。
 以前,这种存储只能使用 cookie 完成,cookie 是一小块可以客户端设置也可以在服务 器端设置
的信息,每次发起请求时都会传送它 。
 在 JavaScript 中通过 document.cookie 可以访问 cookie。
 cookie 的限制使其可以存储少量数据,然而对于大量数据效率很低 。
IE 发明了一种叫做用户数据的行为,可以应用到页面的某个元素上,它有以下特点。
 一旦应用后,该元素便可以从一个命名数据空间中载入数据,然后可以通过 getAttribute()、
setAttribute()和 removeAttribute()方法访问。
 数据必须明确使用 save()方法保存到命名数据空间中,以便能在会话之间持久化数据。
Web Storage 定义了两种用于存储数据的对象:sessionStorage 和 localStorage。前者严格用
于在一个浏览器会话中存储数据,因为数据在浏览器关闭后会立即删除;后者用于跨会话持久化数据并
遵循跨域安全策略。
IndexedDB 是一种类似 SQL 数据库的结构化数据存储机制。但它的数据不是保存在表中,而是保存
在对象存储空间中。创建对象存储空间时,需要定义一个键,然后就可以添加数据。可以使用游标在对
象存储空间中查询特定的对象。而索引则是为了提高查询速度而基于特定的属性创建的。
有了以上这些选择,就可以在客户端机器上使用 JavaScript 存储大量数据了。但你必须小心,不要
在客户端存储敏感数据,因为数据缓存不会加密。

第二十二章笔记

发表于 2018-06-23 | 分类于 JavaScript高级程序设计读书笔记 |

1 作用域安全函数,以及如何防止this跑掉。使用寄生模式。

 /* 作用域安全的构造函数,我们可能会忘记在类名之前加new,所以我们可以构造一个
   作用域安全的函数,比如下面的person,每次都要确定this指没指向Person。
   */
function Person(name, age, job) {
    if (this instanceof Person) {
        this.name = name;
        this.age = age;
        this.job = job;
    } else {
        return new Person(name, age, job);
    }
}
var person1 = Person("Nicholas", 29, "Software Engineer");
alert(window.name); //""
alert(person1.name); //"Nicholas"
var person2 = new Person("Shelby", 34, "Ergonomist");
alert(person2.name); //"Shelby" 


/*你会锁定这个作用域环境,但是一旦你在另一个对象中初始话Person就会出现问题比如*/
function Polygon(sides) {
    if (this instanceof Polygon) {
        this.sides = sides;
        this.getArea = function () {

            return 0;
        };
    } else {
        return new Polygon(sides);
    }
}
function Rectangle(width, height) {
    Polygon.call(this, 2);
    this.width = width;
    this.height = height;
    this.getArea = function () {
        return this.width * this.height;
    };
}
var rect = new Rectangle(5, 10);
alert(rect.sides); //undefined 

在这段代码中,Polygon 构造函数是作用域安全的,然而 Rectangle 构造函数则不是。新创建一
个 Rectangle 实例之后,这个实例应该通过 Polygon.call()来继承 Polygon 的 sides 属性。但是,
由于 Polygon 构造函数是作用域安全的,this 对象并非 Polygon 的实例,所以会创建并返回一个新
的 Polygon 对象。Rectangle 构造函数中的 this 对象并没有得到增长,同时 Polygon.call()返回
的值也没有用到,所以 Rectangle 实例中就不会有 sides 属性。

/改进之后我们可以/

function Polygon(sides) {
    if (this instanceof Polygon) {
        this.sides = sides;
        this.getArea = function () {
            return 0;
        };
    } else {
        return new Polygon(sides);
    }
}
function Rectangle(width, height) {
    Polygon.call(this, 2);
    this.width = width;
    this.height = height;
    this.getArea = function () {
        return this.width * this.height;
    };
}
Rectangle.prototype = new Polygon();
var rect = new Rectangle(5, 10);
alert(rect.sides); //2 组,那么以上代码就会返回 false。

2函数绑定

另一个日益流行的高级技巧叫做函数绑定。函数绑定要创建一个函数,可以在特定的 this 环境中
以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量
传递的同时保留代码执行环境。

/我们实现了函数绑定好吧。将函数绑定到特定的环境中,这样,函数就可以访问到对应的变量了/

Html

<button id="mybtn">my</button>

Javascript

function bind(fn, context) {
        return function () {
            return fn.apply(context, arguments);
        };
    } 

        var handler = {
            message: "Event handled",
            handleClick: function (event) {
                alert(this.message);
            }
        };
        var btn = document.getElementById("mybtn");

        //这里的handler.handleClick函数可以访问到handler对象环境中的message
        EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));

3高级定时器

我们需要明白原本的工作线程机制以及加入定时器的工作机制。

  • 定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对
    它立刻执行,而只能表示它会尽快执行。设定一个 150ms 后执行的定时器不代表到了 150ms 代码就立刻
    执行,它表示代码会在 150ms 后被加入到队列中。如果在这个时间点上,队列中没有其他东西,那么这
    段代码就会被执行,表面上看上去好像代码就在精确指定的时间点上执行了。其他情况下,代码可能明
    显地等待更长时间才执行。
  • 一旦某个函数需要花 50ms 以上的时间完成,那么最好看看能否将任务分割为一
    系列可以使用定时器的小任务。
setTimeout(function(){
 //取出下一个条目并处理
 var item = array.shift();
 process(item);
 //若还有条目,再设置另一个定时器
 if(array.length > 0){
 setTimeout(arguments.callee, 100);
 }
}, 100); 

4函数节流

只要代码是周期性执行的,都应该使用节流,但是你不能控制请求执行的速率。这里展示的
throttle()函数用了 100ms 作为间隔,你当然可以根据你的需要来修改它。

     function throttle(method, context) {
    clearTimeout(method.tId);
    method.tId = setTimeout(function () {
        method.call(context);
    }, 100);
}

function resizeDiv() {
    var div = document.getElementById("myDiv");
    div.style.height = div.offsetWidth + "px";
}

/*下面的界面装换就会频繁的更换大小,特别当屏幕变化时,它需要节流。你调用它20次,但其实它只调用了两次*/
window.onresize = function () {
    throttle(resizeDiv);
}; 

5自定义事件,好好学习下

/自定义事件背后的概念是创建一个管理事件的对象,让其他对象监听那些事件。/

 function EventTarget(){

     this.handlers={};//事件的处理程序序列
 }

EventTarget.prototype = {
    constructor: EventTarget,
    addHandler: function (type, handler) {
        if (typeof this.handlers[type] == "undefined") {

            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
         //激发事件
    fire: function (event) {
        if (!event.target) {
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array) {
            var handlers = this.handlers[event.type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                handlers[i](event);
            }
        }
    },
    /*移除事件*/
    removeHandler: function (type, handler) {
        if (this.handlers[type] instanceof Array) {
            var handlers = this.handlers[type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                if (handlers[i] === handler) {
                    break;
                }
            }
            handlers.splice(i, 1);

        }
    }
}; 

/如何使用自定义事件呢?/

function handleMessage(event){

    alert("Message received:"+event.message);
}
//创建一个新对象
var target=new EventTarget();

//添加一个事件处理程序
target.addHandler("message",handleMessage);
//触发事件

target.fire({type:"message",message:"hello world"});
//删除事件处理程序

target.removeHandler("message",handleMessage);
//再次,应没有处理程序
target.fire({type:"message",message:"hello world"});

/那么这种事件可以通过继承的方式给别人,让别的控件或者div也能拥有这个事件类型的处理程序等等/

5拖拽实现

<html>

<title>login</title>

<body>


<div   id="myDiv" style="width: 200px;height: 200px; border:1px solid #F00">


</div>

<div class="draggable" style="position:absolute; background:red;width: 300px;height: 300px;"  > </div> 

<script>



var EventUtil = {

    addHandler: function (element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function (element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    getEvent: function (event) {
        return event ? event : window.event;
    },
    getTarget: function (event) {
        return event.target || event.srcElement;
    },

    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    }
}; 

/自定义事件背后的概念是创建一个管理事件的对象,让其他对象监听那些事件。/

 function EventTarget(){

     this.handlers={};//事件的处理程序序列
 }

EventTarget.prototype = {
    constructor: EventTarget,
    addHandler: function (type, handler) {
        if (typeof this.handlers[type] == "undefined") {

            this.handlers[type] = [];
        }
        this.handlers[type].push(handler);
    },
         //激发事件
    fire: function (event) {
        if (!event.target) {
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array) {
            var handlers = this.handlers[event.type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                handlers[i](event);
            }
        }
    },
    /*移除事件*/
    removeHandler: function (type, handler) {
        if (this.handlers[type] instanceof Array) {
            var handlers = this.handlers[type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                if (handlers[i] === handler) {
                    break;
                }
            }
            handlers.splice(i, 1);

        }
    },

}; 

/拖拽实现/
//第一步:拖尾的基本代码需要为文档设置一个 onmousemove 事件处理程序,它总是将指定元素移动到鼠标指针的位置,
EventUtil.addHandler(document, “mousemove”, function (event) {
var myDiv = document.getElementById(“myDiv”);
myDiv.style.left = event.clientX + “px”;
myDiv.style.top = event.clientY + “px”;
});

        /*DragDrop 对象封装了拖放的所有基本功能。这是一个单例对象,并使用了模块模式来隐藏某些实
        现细节。*/
            var DragDrop = function () {
                var dragging = null;
                function handleEvent(event) {
                    //获取事件和目标
                    event = EventUtil.getEvent(event);
                    var target = EventUtil.getTarget(event);
                    //确定事件类型
                    switch (event.type) {
                        case "mousedown":
                            if (target.className.indexOf("draggable") > -1) {
                                dragging = target;
                            }
                            break;
                        case "mousemove":
                            if (dragging !== null) {
                                //指定位置
                                dragging.style.left = event.clientX + "px";
                                dragging.style.top = event.clientY + "px";
                            }
                            break;
                        case "mouseup":
                            dragging = null;
                            break;
                    }
                };
                //公共接口
                return {
                    enable: function () {
                        EventUtil.addHandler(document, "mousedown", handleEvent);
                        EventUtil.addHandler(document, "mousemove", handleEvent);
                        EventUtil.addHandler(document, "mouseup", handleEvent);
                    },

                    disable: function () {
                        EventUtil.removeHandler(document, "mousedown", handleEvent);
                        EventUtil.removeHandler(document, "mousemove", handleEvent);
                        EventUtil.removeHandler(document, "mouseup", handleEvent);
                    }
                }
            }(); 


            DragDrop.enable();

   </script>
</body>

</html>

6小结

JavaScript 中的函数非常强大,因为它们是第一类对象。使用闭包和函数环境切换,还可以有很多
使用函数的强大方法。可以创建作用域安全的构造函数,确保在缺少 new 操作符时调用构造函数不会改
变错误的环境对象。
 可以使用惰性载入函数,将任何代码分支推迟到第一次调用函数的时候。
 函数绑定可以让你创建始终在指定环境中运行的函数,同时函数柯里化可以让你创建已经填了
某些参数的函数。
 将绑定和柯里化组合起来,就能够给你一种在任意环境中以任意参数执行任意函数的方法。
ECMAScript 5 允许通过以下几种方式来创建防篡改对象。
 不可扩展的对象,不允许给对象添加新的属性或方法。
 密封的对象,也是不可扩展的对象,不允许删除已有的属性和方法。
 冻结的对象,也是密封的对象,不允许重写对象的成员。
JavaScript 中可以使用 setTimeout()和 setInterval()如下创建定时器。
 定时器代码是放在一个等待区域,直到时间间隔到了之后,此时将代码添加到 JavaScript 的处理
队列中,等待下一次 JavaScript 进程空闲时被执行。
 每次一段代码执行结束之后,都会有一小段空闲时间进行其他浏览器处理。
 这种行为意味着,可以使用定时器将长时间运行的脚本切分为一小块一小块可以在以后运行的
代码段。这种做法有助于 Web 应用对用户交互有更积极的响应。
JavaScript 中经常以事件的形式应用观察者模式。虽然事件常常和 DOM 一起使用,但是你也可以通
图灵社区会员 StinkBC(StinkBC@gmail.com) 专享 尊重版权

过实现自定义事件在自己的代码中应用。使用自定义事件有助于将不同部分的代码相互之间解耦,让维
护更加容易,并减少引入错误的机会。
拖放对于桌面和 Web 应用都是一个非常流行的用户界面范例,它能够让用户非常方便地以一种直
观的方式重新排列或者配置东西。在 JavaScrip 中可以使用鼠标事件和一些简单的计算来实现这种功能
类型。将拖放行为和自定义事件结合起来可以创建一个可重复使用的框架,它能应用于各种不同的情
况下。

第二十章笔记

发表于 2018-06-22 | 分类于 JavaScript高级程序设计读书笔记 |

(1)表单之阻止表单提交

Html

</form>

Javascript可以阻止我们表单提交等等。

          var EventUtil = {
        addHandler: function (element, type, handler) {
            if (element.addEventListener) {
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }

        },
        getEvent: function (event) {
            return event ? event : window.event;
        },
        getTarget: function (event) {
            return event.target || event.srcElement;
        },

        preventDefault: function (event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },

        removeHandler: function (element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }

        },
        stopPropagation: function (event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        },
getCharCode: function (event) {
                if (typeof event.charCode == "number") {
                    return event.charCode;
                } else {
                    return event.keyCode;
                }
            }
    };

    var myform=document.getElementById("myform");
    EventUtil.addHandler(myform,"submit",function(event){

        event=EventUtil.getEvent(event);
        //阻止默认事件
        EventUtil.preventDefault(event);
    })

(2)阻止表单进行重置

Html

当点击reset按钮时我们可以用代码来阻止重置。
JavaScript

var form = document.getElementById("myForm");
EventUtil.addHandler(form, "reset", function(event){
 //取得事件对象
 event = EventUtil.getEvent(event);
 //阻止表单重置
 EventUtil.preventDefault(event);
}); 

(3)一些属性

Html

<form id="myform">
       <input />
       <input name="nihao"/>
 </form>

JavaScript

var form = document.getElementById("myform");
//取得表单中的第一个字段
var field1 = form.elements[0];
//取得名为"nihao"的字段
var field2 = form.elements["nihao"];
field2.value="nihao";
//取得表单中包含的字段的数量
var fieldCount = form.elements.length;  
alert(fieldCount);  
我们以此给了btn加了三个事件。只用了一个函数。

(4)避免重复提交

能够动态修改表单字段属性,意味着我们可以在任何时候,以任何方式来动态操作表单。例如,很
多用户可能会重复单击表单的提交按钮。在涉及信用卡消费时,这就是个问题:因为会导致费用翻番。
为此,最常见的解决方案,就是在第一次单击后就禁用提交按钮。只要侦听 submit 事件,并在该事件
发生时禁用提交按钮即可。以下就是这样一个例子。

//避免多次提交表单
EventUtil.addHandler(form, "submit", function(event){
 event = EventUtil.getEvent(event);
 var target = EventUtil.getTarget(event);
 //取得提交按钮
 var btn = target.elements["submit-btn"];
 //禁用它
 btn.disabled = true;
});

以上代码为表单的 submit 事件添加了一个事件处理程序。事件触发后,代码取得了提交按钮
并将其 disabled 属性设置为 true。注意,不能通过 onclick 事件处理程序来实现这个功能,原
因是不同浏览器之间存在“时差”:有的浏览器会在触发表单的 submit 事件之前触发 click 事件,
而有的浏览器则相反。对于先触发 click 事件的浏览器,意味着会在提交发生之前禁用按钮,结果
永远都不会提交表单。因此,最好是通过 submit 事件来禁用提交按钮。不过,这种方式不适合表
单中不包含提交按钮的情况;如前所述,只有在包含提交按钮的情况下,才有可能触发表单的 submit
事件。

(4)文档加载时自动获得焦点

EventUtil.addHandler(window,"load",function(event){

    document.forms[0].elements[0].focus();
}) 

(5)针对某个控件过滤所有按钮输入

EventUtil.addHandler(textbox, "keypress", function(event){
 event = EventUtil.getEvent(event);
 EventUtil.preventDefault(event);
}); 

(6)针对某个控件只过滤特定字符

如下只能输入数字

var textbox = document.getElementById("textboxs");
   EventUtil.addHandler(textbox, "keypress", function (event) {
       event = EventUtil.getEvent(event);
       var target = EventUtil.getTarget(event);
       var charCode = EventUtil.getCharCode(event);
       if (!/\d/.test(String.fromCharCode(charCode))) {
           EventUtil.preventDefault(event);
       }
   }); 

(7)针对某一个控件输入完毕后自动切换焦点到下一个控件

Html

<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4"> 

JavaScript

(function () {
    function tabForward(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.value.length == target.maxLength) {
            var form = target.form;
            for (var i = 0, len = form.elements.length; i < len; i++) {
                if (form.elements[i] == target) {
                    if (form.elements[i + 1]) {
                        form.elements[i + 1].focus();
                    }
                    return;
                }
            }
        }
    }
    /*以上为处理焦点切换的函数*/
    var textbox1 = document.getElementById("txtTel1");
    var textbox2 = document.getElementById("txtTel2");
    var textbox3 = document.getElementById("txtTel3");
    //获取textbox
    EventUtil.addHandler(textbox1, "keyup", tabForward);
    EventUtil.addHandler(textbox2, "keyup", tabForward);
    EventUtil.addHandler(textbox3, "keyup", tabForward);
    /*给textbox添加事件*/
})(); 

(8)h5一些属性

*第一种情况是在表单字段中指定了 required 属性,如下面的例子所示:

<input type="text" name="username" required>
<input type="email" name ="email">

<input type="url" name="homepage"> 

(9)给选择框加选项

可以使用 JavaScript 动态创建选项,并将它们添加到选择框中。添加选项的方式有很多,第一种方
式就是使用如下所示的 DOM 方法。

var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption); 

(10)小结

  虽然 HTML 和 Web 应用自诞生以来已经发生了天翻地覆的变化,但 Web 表单相对却没有什么改
变。使用 JavaScript 可以增强已有的表单字段,从而创造出新的功能,或者提升表单的易用性。为此,
表单、表单字段都引入了相应的属性和方法,以便 JavaScript 使用。下面是本章介绍的几个概念。
1 可以使用一些标准或非标准的方法选择文本框中的全部或部分文本。
2 大多数浏览器都采用了 Firefox 操作选择文本的方式,但 IE 仍然坚持自己的实现。

3 在文本框的内容变化时,可以通过侦听键盘事件以及检测插入的字符,来允许或禁止用户输入
某些字符。
除 Opera 之外的所有浏览器都支持剪贴板事件,包括 copy、cut 和 paste。其他浏览器在实现剪
贴板事件时也可以分为几种不同的情况。
4IE、Firefox、Chrome 和 Safari 允许通过 JavaScript 访问剪贴板中的数据,而 Opera 不允许这种访
问方式。
5 即使是 IE、Chrome 和 Safari,它们各自的实现方式也不相同。
6  Firefox、Safari 和 Chrome 只允许在 paste 事件发生时读取剪贴板数据,而 IE 没有这个限制。
7  Firefox、Safari 和 Chrome 只允许在发生剪贴板事件时访问与剪贴板相关的信息,而 IE 允许在任
何时候访问相关信息。
在文本框内容必须限制为某些特定字符的情况下,就可以利用剪贴板事件来屏蔽通过粘贴向文本框
中插入内容的操作。
8选择框也是经常要通过 JavaScript 来控制的一个表单字段。由于有了 DOM,对选择框的操作比以前
要方便多了。添加选项、移除选项、将选项从一个选择框移动到另一个选择框,甚至对选项进行排序等
操作,都可以使用标准的 DOM 技术来实现。
   富文本编辑功能是通过一个包含空 HTML 文档的 iframe 元素来实现的。通过将空文档的
designMode 属性设置为"on",就可以将该页面转换为可编辑状态,此时其表现如同字处理软件。另外,
也可以将某个元素设置为 contenteditable。在默认情况下,可以将字体加粗或者将文本转换为斜体,
还可以使用剪贴板。JavaScript 通过使用 execCommand()方法也可以实现相同的一些功能。另外,使用
queryCommandEnabled()、queryCommandState()和 queryCommandValue()方法则可以取得有关
文本选区的信息。由于以这种方式构建的富文本编辑器并不是一个表单字段,因此在将其内容提交给
服务器之前,必须将 iframe 或 contenteditable 元素中的 HTML 复制到一个表单字段中。

第十四章笔记

发表于 2018-06-20 | 分类于 JavaScript高级程序设计读书笔记 |

(1)表单之阻止表单提交

Html

</form>

Javascript可以阻止我们表单提交等等。

          var EventUtil = {
        addHandler: function (element, type, handler) {
            if (element.addEventListener) {
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }

        },
        getEvent: function (event) {
            return event ? event : window.event;
        },
        getTarget: function (event) {
            return event.target || event.srcElement;
        },

        preventDefault: function (event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },

        removeHandler: function (element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }

        },
        stopPropagation: function (event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        },
getCharCode: function (event) {
                if (typeof event.charCode == "number") {
                    return event.charCode;
                } else {
                    return event.keyCode;
                }
            }
    };

    var myform=document.getElementById("myform");
    EventUtil.addHandler(myform,"submit",function(event){

        event=EventUtil.getEvent(event);
        //阻止默认事件
        EventUtil.preventDefault(event);
    })

(2)阻止表单进行重置

Html

当点击reset按钮时我们可以用代码来阻止重置。
JavaScript

var form = document.getElementById("myForm");
EventUtil.addHandler(form, "reset", function(event){
 //取得事件对象
 event = EventUtil.getEvent(event);
 //阻止表单重置
 EventUtil.preventDefault(event);
}); 

(3)一些属性

Html

<form id="myform">
       <input />
       <input name="nihao"/>
 </form>

JavaScript

var form = document.getElementById("myform");
//取得表单中的第一个字段
var field1 = form.elements[0];
//取得名为"nihao"的字段
var field2 = form.elements["nihao"];
field2.value="nihao";
//取得表单中包含的字段的数量
var fieldCount = form.elements.length;  
alert(fieldCount);  
我们以此给了btn加了三个事件。只用了一个函数。

(4)避免重复提交

能够动态修改表单字段属性,意味着我们可以在任何时候,以任何方式来动态操作表单。例如,很
多用户可能会重复单击表单的提交按钮。在涉及信用卡消费时,这就是个问题:因为会导致费用翻番。
为此,最常见的解决方案,就是在第一次单击后就禁用提交按钮。只要侦听 submit 事件,并在该事件
发生时禁用提交按钮即可。以下就是这样一个例子。

//避免多次提交表单
EventUtil.addHandler(form, "submit", function(event){
 event = EventUtil.getEvent(event);
 var target = EventUtil.getTarget(event);
 //取得提交按钮
 var btn = target.elements["submit-btn"];
 //禁用它
 btn.disabled = true;
});

以上代码为表单的 submit 事件添加了一个事件处理程序。事件触发后,代码取得了提交按钮
并将其 disabled 属性设置为 true。注意,不能通过 onclick 事件处理程序来实现这个功能,原
因是不同浏览器之间存在“时差”:有的浏览器会在触发表单的 submit 事件之前触发 click 事件,
而有的浏览器则相反。对于先触发 click 事件的浏览器,意味着会在提交发生之前禁用按钮,结果
永远都不会提交表单。因此,最好是通过 submit 事件来禁用提交按钮。不过,这种方式不适合表
单中不包含提交按钮的情况;如前所述,只有在包含提交按钮的情况下,才有可能触发表单的 submit
事件。

(4)文档加载时自动获得焦点

EventUtil.addHandler(window,"load",function(event){

    document.forms[0].elements[0].focus();
}) 

(5)针对某个控件过滤所有按钮输入

EventUtil.addHandler(textbox, "keypress", function(event){
 event = EventUtil.getEvent(event);
 EventUtil.preventDefault(event);
}); 

(6)针对某个控件只过滤特定字符

如下只能输入数字

var textbox = document.getElementById("textboxs");
   EventUtil.addHandler(textbox, "keypress", function (event) {
       event = EventUtil.getEvent(event);
       var target = EventUtil.getTarget(event);
       var charCode = EventUtil.getCharCode(event);
       if (!/\d/.test(String.fromCharCode(charCode))) {
           EventUtil.preventDefault(event);
       }
   }); 

(7)针对某一个控件输入完毕后自动切换焦点到下一个控件

Html

<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4"> 

JavaScript

(function () {
    function tabForward(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.value.length == target.maxLength) {
            var form = target.form;
            for (var i = 0, len = form.elements.length; i < len; i++) {
                if (form.elements[i] == target) {
                    if (form.elements[i + 1]) {
                        form.elements[i + 1].focus();
                    }
                    return;
                }
            }
        }
    }
    /*以上为处理焦点切换的函数*/
    var textbox1 = document.getElementById("txtTel1");
    var textbox2 = document.getElementById("txtTel2");
    var textbox3 = document.getElementById("txtTel3");
    //获取textbox
    EventUtil.addHandler(textbox1, "keyup", tabForward);
    EventUtil.addHandler(textbox2, "keyup", tabForward);
    EventUtil.addHandler(textbox3, "keyup", tabForward);
    /*给textbox添加事件*/
})(); 

(8)h5一些属性

*第一种情况是在表单字段中指定了 required 属性,如下面的例子所示:

<input type="text" name="username" required>
<input type="email" name ="email">

<input type="url" name="homepage"> 

(9)给选择框加选项

可以使用 JavaScript 动态创建选项,并将它们添加到选择框中。添加选项的方式有很多,第一种方
式就是使用如下所示的 DOM 方法。

var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("Option text"));
newOption.setAttribute("value", "Option value");
selectbox.appendChild(newOption); 

(10)小结

  虽然 HTML 和 Web 应用自诞生以来已经发生了天翻地覆的变化,但 Web 表单相对却没有什么改
变。使用 JavaScript 可以增强已有的表单字段,从而创造出新的功能,或者提升表单的易用性。为此,
表单、表单字段都引入了相应的属性和方法,以便 JavaScript 使用。下面是本章介绍的几个概念。
1 可以使用一些标准或非标准的方法选择文本框中的全部或部分文本。
2 大多数浏览器都采用了 Firefox 操作选择文本的方式,但 IE 仍然坚持自己的实现。

3 在文本框的内容变化时,可以通过侦听键盘事件以及检测插入的字符,来允许或禁止用户输入
某些字符。
除 Opera 之外的所有浏览器都支持剪贴板事件,包括 copy、cut 和 paste。其他浏览器在实现剪
贴板事件时也可以分为几种不同的情况。
4IE、Firefox、Chrome 和 Safari 允许通过 JavaScript 访问剪贴板中的数据,而 Opera 不允许这种访
问方式。
5 即使是 IE、Chrome 和 Safari,它们各自的实现方式也不相同。
6  Firefox、Safari 和 Chrome 只允许在 paste 事件发生时读取剪贴板数据,而 IE 没有这个限制。
7  Firefox、Safari 和 Chrome 只允许在发生剪贴板事件时访问与剪贴板相关的信息,而 IE 允许在任
何时候访问相关信息。
在文本框内容必须限制为某些特定字符的情况下,就可以利用剪贴板事件来屏蔽通过粘贴向文本框
中插入内容的操作。
8选择框也是经常要通过 JavaScript 来控制的一个表单字段。由于有了 DOM,对选择框的操作比以前
要方便多了。添加选项、移除选项、将选项从一个选择框移动到另一个选择框,甚至对选项进行排序等
操作,都可以使用标准的 DOM 技术来实现。
   富文本编辑功能是通过一个包含空 HTML 文档的 iframe 元素来实现的。通过将空文档的
designMode 属性设置为"on",就可以将该页面转换为可编辑状态,此时其表现如同字处理软件。另外,
也可以将某个元素设置为 contenteditable。在默认情况下,可以将字体加粗或者将文本转换为斜体,
还可以使用剪贴板。JavaScript 通过使用 execCommand()方法也可以实现相同的一些功能。另外,使用
queryCommandEnabled()、queryCommandState()和 queryCommandValue()方法则可以取得有关
文本选区的信息。由于以这种方式构建的富文本编辑器并不是一个表单字段,因此在将其内容提交给
服务器之前,必须将 iframe 或 contenteditable 元素中的 HTML 复制到一个表单字段中。

第十三章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1)DOM2级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()
和 removeEventListener()。所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处
理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获
阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。
要在按钮上为 click 事件添加事件处理程序,可以使用下列代码:

<body>

    <button></button>

    <script>
        var ben = document.getElementById("myBtn");
        ben.addEventListener("click", function () {

            alert(this.id);
        }, false);
      /*上面的代码为一个按钮添加了 onclick 事件处理程序,而且该事件会在冒泡阶段被触发(因为最
后一个参数是 false)。*/
    </script>

上面的代码为一个按钮添加了 onclick 事件处理程序,而且该事件会在冒泡阶段被触发(因为最
后一个参数是 false)。

(2)在不同浏览器中通过能力检测来加减方法处理程序,万金油

<html>



<body>

<button id="clickMe">点我,点我,别害羞</button>
<script>
    /*万金油式处理事件方法*/
    var EventUtil = {
        addHandler: function (element, type, handler) {
            if (element.addEventListener) {

                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }
        },
        removeHandler: function (element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }

        }
    }

    /*如何使用呢?*/
    var clickme = document.getElementById("clickMe");
    var handler = function () {
        alert("Clicked");
    }

    EventUtil.addHandler(clickme, "click", handler);/*添加事件*/
    EventUtil.removeHandler(clickme, "click", handler);/*移除事件*/

</script>
</body>

</html>

这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。如果存在 DOM2 级方法,则使用
该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的
方法,则采取第二种方案。注意,为了在 IE8 及更早版本中运行,此时的事件类型必须加上”on”前缀。
最后一种可能就是使用 DOM0 级方法(在现代浏览器中,应该不会执行这里的代码)。此时,我们使用
的是方括号语法来将属性名指定为事件处理程序,或者将属性设置为 null。

(3)在一个函数里面处理多个事件时,可以用type属性

<html>
<body>
    <button id="clickMe">点我,点我,别害羞</button>
    <script>
        var btn = document.getElementById("clickMe");
        var handler = function (event) {

            switch (event.type) {
                case "click":
                    alert("clickMe,ye");
                    break;
                case "mouseover":
                    event.target.style.backgroundColor = "red";
                    break;
            }
        }

        btn.onclick = handler;
        btn.onmouseover = handler;
    </script>
</body>

</html>

我们以此给了btn加了三个事件。只用了一个函数。

(4)跨浏览器的事件对象,以下代码可以再IE和其他浏览器运行,做好了能力检测。万金油

<html>

<body>
    <button id="clickMe">点我,点我,别害羞</button>
    <script>
        var EventUtil = {
            addHandler: function (element, type, handler) {
                //省略的代码,上面有
            },
            getEvent: function (event) {
                return event ? event : window.event;
            },
            getTarget: function (event) {
                return event.target || event.srcElement;
            },

            preventDefault: function (event) {
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            },

            removeHandler: function (element, type, handler) {
                //省略的代码,上面例子有
            },
            stopPropagation: function (event) {
                if (event.stopPropagation) {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
            }
        };


    </script>
</body>

</html>

(4)事件类型

1 确定浏览器是否支持DOM2级事件可以用以下代码

var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");  

注意,只有根据“DOM2 级事件”实现这些事件的浏览器才会返回 true。而以非标准方式支持这
些事件的浏览器则会返回 false。要确定浏览器是否支持“DOM3 级事件”定义的事件,可以使用如下
代码:

var isSupported = document.implementation.hasFeature("UIEvent", "3.0"); 

(5)load事件引起加载script文件

EventUtil.addHandler(window, "load", function () {
    var script = document.createElement("script");
    EventUtil.addHandler(script, "load", function (event) {
        alert("LoadedScript");
    });
    script.src = "demo.js";
    document.body.appendChild(script);
})

以上可以给文档加载时加一个加载js文件的方法.666

(6)以下列举一些事件,没事看看.

  • 当浏览器窗口被调整到一个新的高度或宽度时,就会触发 resize 事件。
 EventUtil.addHandler(window, "resize", function(event){  
 alert("Resized");  
}); 
  • 当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
    (1) focusout 在失去焦点的元素上触发;
    (2) focusin 在获得焦点的元素上触发;
    (3) blur 在失去焦点的元素上触发;
    (4) DOMFocusOut 在失去焦点的元素上触发;
    (5) focus 在获得焦点的元素上触发;
    (6) DOMFocusIn 在获得焦点的元素上触发。
    其中,blur、DOMFocusOut 和 focusout 的事件目标是失去焦点的元素;而 focus、DOMFocusIn
    和 focusin 的事件目标是获得焦点的元素。
    要确定浏览器是否支持这些事件,可以使用如下代码:
var isSupported = document.implementation.hasFeature("FocusEvent", "3.0"); 

(7)可以通过获取鼠标点击的位置来显示鼠标点击的位置.

<html>

<body>
  <div  id="myDiv"  style="width: 100%;height: 300px;"></div>

<script>
    var EventUtil = {
        addHandler: function (element, type, handler) {
            if (element.addEventListener) {
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent("on" + type, handler);
            } else {
                element["on" + type] = handler;
            }

        },
        getEvent: function (event) {
            return event ? event : window.event;
        },
        getTarget: function (event) {
            return event.target || event.srcElement;
        },

        preventDefault: function (event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },

        removeHandler: function (element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent("on" + type, handler);
            } else {
                element["on" + type] = null;
            }

        },
        stopPropagation: function (event) {
            if (event.stopPropagation) {
                event.stopPropagation();
            } else {
                event.cancelBubble = true;
            }
        }
    };



   var div=document.getElementById("myDiv");
   EventUtil.addHandler(div,"click",function(event){
       event=EventUtil.getEvent(event);
       alert("Page coordinates:"+event.pageX+","+event.pageY);
   })


</script>
</body>

</html>

(8)检测用户是否同时按下了键盘键

var div=document.getElementById("myDiv");
EventUtil.addHandler(div,"click",function(event){
    event=EventUtil.getEvent(event);
   var keys=new Array();
   if(event.shiftKey){
             keys.push("shift");

   }
   if(event.ctrlKey){
             keys.push("ctrl");

   }
   if(event.altKey){
             keys.push("alt");

   }

alert(keys.join(","));

})

这里检测用户是否同时按下了shift,ctrl,alt

(9)键盘和文本事件

var textBox=document.getElementById("MyText");
EventUtil.addHandler(textBox,"keyup",function(event){
    event=EventUtil.getEvent(event);
    alert(event.keyCode);
})

以上代码能帮助我们捕获到用户点击文本框的的键盘的键码进而显示。

(10)事件委托

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事
件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到 document 层次。
也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个可单击的元素分别添加事
件处理程序。以下面的 HTML 代码为例。

HTML
 <ul id="myLinks">
        <li id="goSomewhere">Go somewhere</li>
        <li id="doSomething">Do something</li>
        <li id="sayHi">Say hi</li>
       </ul> 

    /*如果在一个复杂的 Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不
清的代码用于添加事件处理程序。此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在
DOM 树中尽量最高的层次上添加一个事件处理程序,如下面的例子所示。*/
JAVASCRIPT  
   var list=document.getElementById("myLinks");
   EventUtil.addHandler(list,"click",function(event){
    event=EventUtil.getEvent(event);
   var target=EventUtil.getTarget(event);
   switch(target.id){
      case "doSomething":
          document.title="I changed the document's title";
          break;
      case "goSomewhere":
      location.href= "http://www.wrox.com"; 
      break;
      case "sayHi":
        alert("hi");
        break;
  }
   });

所有的按钮事件都可以用这种,取最高层次上的事件处理程序来处理。

(11)模拟鼠标事件

html

<button  id="myBtn">nihoa</button>

javascript

 var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEvent("MouseEvents");

btn.onclick=function(){
    alert("nihao");
}
//初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
 false, false, false, false, 0, null);

//触发事件
btn.dispatchEvent(event); 

(12)小结

事件是将 JavaScript 与网页联系在一起的主要方式。“DOM3 级事件”规范和 HTML5 定义了常见的
大多数事件。即使有规范定义了基本事件,但很多浏览器仍然在规范之外实现了自己的专有事件,从而
为开发人员提供更多掌握用户交互的手段。有些专有事件与特定设备关联,例如移动 Safari 中的
orientationchange 事件就是特定关联 iOS 设备的。
在使用事件时,需要考虑如下一些内存与性能方面的问题。

1 有必要限制一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户
感觉页面反应不够灵敏。
2建立在事件冒泡机制之上的事件委托技术,可以有效地减少事件处理程序的数量。
*3建议在浏览器卸载页面之前移除页面中的所有事件处理程序。
可以使用 JavaScript 在浏览器中模拟事件。“DOM2 级事件”和“DOM3 级事件”规范规定了模拟事
件的方法,为模拟各种有定义的事件提供了方便。此外,通过组合使用一些技术,还可以在某种程度上
模拟键盘事件。IE8 及之前版本同样支持事件模拟,只不过模拟的过程有些差异。
事件是 JavaScript 中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要。

第十二章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1)本章因为个人原因先跳过了。有时间再看。

第十一章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1)DOM扩展

这难道不就是jquery干的事情吗??

querySelector()方法
querySelector()方法接收一个 CSS 选择符,返回与该模式匹配的第一个元素,如果没有找到匹
配的元素,返回 null。请看下面的例子。
<html>

<body>

    <body>

        <div id="myDiv">
               dlskajflk
        </div>
    </body>
    <script>
      var body=document.querySelector("body");
      var myDiv=document.querySelector("#myDiv");
      alert(myDiv.outerHTML);//输出 <div id="myDiv"> dlskajflk</div>
    </script>
</body>

</html>

(2)Html5定义了大量的JavaScript的API

1 比较有特点的是插入标记。可以直接设置一个便签的innerHTML直接插入一些便签。

在读模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应
的 HTML 标记。在写模式下,innerHTML 会根据指定的值创建新的 DOM 树,然后用这个 DOM 树完全
替换调用元素原先的所有子节点。下面是一个例子。
<div id="content">
 <p>This is a <strong>paragraph</strong> with a list following it.</p>
 <ul>
 <li>Item 1</li>
 <li>Item 2</li>
 <li>Item 3</li>
 </ul>
</div>
对于上面的<div>元素来说,它的 innerHTML 属性会返回如下字符串。
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
 <li>Item 1</li>
 <li>Item 2</li>
 <li>Item 3</li>
</ul> 

而设置也超级简单。

div.innerHTML = “Hello & welcome, \”reader\”!“;

(3)不要频繁使用innerHTML

<html>

<body>

    <body>

        <div id="myDiv">
               dlskajflk
        </div>
    </body>
    <script>
      for(var i=0,len=values.length;i<len;i++){

        ul.innerHTML+="<li>"+values[i]+"</li>";
      }
   /*这个算法不好,这样会频繁的访问ul.innerHTML,性能很差*/
      var itemsHtml="";
      for(var i=0,len=values.length;i<len;i++){
          itemsHtml+="<li>"+values[i]+"</li>";
      }
      ul.innerHTML=itemsHtml;
      /*我们应该不断累加,再一次性加给innerHTML。*/
    </script>
</body>

</html>

(4)contains()方法

在实际开发中,经常需要知道某个节点是不是另一个节点的后代。IE 为此率先引入了 contains()
方法,以便不通过在 DOM 文档树中查找即可获得这个信息。调用 contains()方法的应该是祖先节点,
也就是搜索开始的节点,这个方法接收一个参数,即要检测的后代节点。如果被检测的节点是后代节点,
该方法返回 true;否则,返回 false。以下是一个例子:
alert(document.documentElement.contains(document.body)); //true
当然,考虑到不同浏览器之间的支持程度。我们可以使用一种通用的函数。比如。

function contains(refNode, otherNode) {
       if (typeof refNode.contains == "function" &&
           (!client.engine.webkit || client.engine.webkit >= 522)) {
           return refNode.contains(otherNode);
       } else if (typeof refNode.compareDocumentPosition == "function") {
           return !!(refNode.compareDocumentPosition(otherNode) & 16);
       } else {
           var node = otherNode.parentNode;
           do {
               if (node === refNode) {
                   return true;
               } else {
                   node = node.parentNode;
               }
           } while (node !== null);

           return false;
       }
   } 

   alert(contains(document.getElementById("myDiv")),document.getElementById("myLi"))

(5)innerText属性

通过 innertText 属性可以操作元素中包含的所有文本内容,包括子文档树中的文本。在通过
innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。在通过
innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。来看下面这
个 HTML 代码示例。

<div id="content">
 <p>This is a <strong>paragraph</strong> with a list following it.</p>
 <ul>
 <li>Item 1</li>
 <li>Item 2</li>
 <li>Item 3</li>
 </ul>
</div>
InnerTextExample01.htm
对于这个例子中的<div>元素而言,其 innerText 属性会返回下列字符串:
This is a paragraph with a list following it.
Item 1
Item 2
Item 3 

(6)小结

  • 虽然 DOM 为与 XML 及 HTML 文档交互制定了一系列核心 API,但仍然有几个规范对标准的 DOM
    进行了扩展。这些扩展中有很多原来是浏览器专有的,但后来成为了事实标准,于是其他浏览器也都提
    供了相同的实现。本章介绍的三个这方面的规范如下。
  • 1 Selectors API,定义了两个方法,让开发人员能够基于 CSS 选择符从 DOM 中取得元素,这两个
    方法是 querySelector()和 querySelectorAll()。
  • 2 Element Traversal,为 DOM 元素定义了额外的属性,让开发人员能够更方便地从一个元素跳到
    另一个元素。之所以会出现这个扩展,是因为浏览器处理 DOM 元素间空白符的方式不一样。
  • HTML5,为标准的 DOM 定义了很多扩展功能。其中包括在 innerHTML 属性这样的事实标准基
    础上提供的标准定义,以及为管理焦点、设置字符集、滚动页面而规定的扩展 API。
    虽然目前 DOM 扩展的数量还不多,但随着 Web 技术的发展,相信一定还会涌现出更多扩展来。很
    多浏览器都在试验专有的扩展,而这些扩展一旦获得认可,就能成为“伪”标准,甚至会被收录到规范
    的更新版本中。

第十章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1)DOM

这一章主要针对不同浏览器要使用功能时做出的检测是否支持这个功能的一章。
没啥意思。

(2)Document类型

JavaScript 通过 Document 类型表示文档。在浏览器中,document 对象是 HTMLDocument(继承
自 Document 类型)的一个实例,表示整个 HTML 页面。而且,document 对象是 window 对象的一个
属性,因此可以将其作为全局对象来访问。
通过它可以访问到文档各种信息。

//取得完整的 URL
 var url = document.URL;
 //取得域名
 var domain = document.domain;
 //取得来源页面的 URL
 var referrer = document.referrer; 

(3)文档写入

如果想要documen.write来写入我们需要插入到界面的JavaScript代码可以这样。

<script type="text/javascript">
document.write("<script type=\"text/javascript\"   src=\"file.js\" >" +"<\/script>"); 
</script> 

(4)node遍历

不过,如果想要遍历元素的特性,attributes 属性倒是可以派上用场。在需要将 DOM 结构序列
化为 XML 或 HTML 字符串时,多数都会涉及遍历元素特性。以下代码展示了如何迭代元素的每一个特
性,然后将它们构造成 name=”value” name=”value”这样的字符串格式
。

function outputAttributes(element){
 var pairs = new Array(),
 attrName,
 attrValue,
 i,
 len;
 for (i=0, len=element.attributes.length; i < len; i++){
 attrName = element.attributes[i].nodeName;
 attrValue = element.attributes[i].nodeValue;
 pairs.push(attrName + "=\"" + attrValue + "\"");
 }
 return pairs.join(" ");
} 

(5)遍历元素子节点

<html>

<body>
    <ul id="myList">
        <li>jlk</li>
        <li>jlksdjflk</li>
    </ul>
    <script>
        var mylist = document.getElementById("myList");

        for (var i = 0, len = mylist.childNodes.length; i < len; i++) {
            if (mylist.childNodes[i].nodeType == 1) {
                alert(mylist.childNodes[i].nodeName);//LI
            }
        }
    </script>
</body>

</html>

(6)用js代码实现加载js和css文件

比如在同级目录下有一个demo.js文件,我们不想用标签引用,只想用代码引入。我们可以

function loadScript(url){
       var script=document.createElement("script");
       script.type="text/javascript";
       script.src=url;
       document.body.appendChild(script);
   }
   loadScript("demo.js");

    /*需要注意的是,必须将<link>元素添加到<head>
    而不是<body>元素,才能保证在所有浏览器中的行为一致。整个过程可以用以下函数来表示:*/
    function loadStyles(url){
     var link = document.createElement("link");
     link.rel = "stylesheet";
     link.type = "text/css";
     link.href = url;
     var head = document.getElementsByTagName("head")[0];
     head.appendChild(link);
    }
    调用 loadStyles()函数的代码如下所示:
    loadStyles("styles.css"); 

(7)小结

  DOM 是语言中立的 API,用于访问和操作 HTML 和 XML 文档。DOM1 级将 HTML 和 XML 文档
形象地看作一个层次化的节点树,可以使用 JavaScript 来操作这个节点树,进而改变底层文档的外观和
结构。
  DOM 由各种节点构成,简要总结如下。
1 最基本的节点类型是 Node,用于抽象地表示文档中一个独立的部分;所有其他类型都继承自
Node。
2 Document 类型表示整个文档,是一组分层节点的根节点。在 JavaScript 中,document 对象是
Document 的一个实例。使用 document 对象,有很多种方式可以查询和取得节点。
3 Element 节点表示文档中的所有 HTML 或 XML 元素,可以用来操作这些元素的内容和特性。
4 另外还有一些节点类型,分别表示文本内容、注释、文档类型、CDATA 区域和文档片段。
访问 DOM 的操作在多数情况下都很直观,不过在处理<script>和<style>元素时还是存在一些
复杂性。由于这两个元素分别包含脚本和样式信息,因此浏览器通常会将它们与其他元素区别对待。这
些区别导致了在针对这些元素使用 innerHTML 时,以及在创建新元素时的一些问题。
理解 DOM 的关键,就是理解 DOM 对性能的影响。DOM 操作往往是 JavaScript 程序中开销最大的
部分,而因访问 NodeList 导致的问题为最多。NodeList 对象都是“动态的”,这就意味着每次访问
NodeList 对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少 DOM 操作。

第九章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1)客户端检测

这一章主要针对不同浏览器要使用功能时做出的检测是否支持这个功能的一章。
没啥意思。

(2)小结

   客户端检测是 JavaScript 开发中最具争议的一个话题。由于浏览器间存在差别,通常需要根据不同
浏览器的能力分别编写不同的代码。有不少客户端检测方法,但下列是最经常使用的。
1  能力检测:在编写代码之前先检测特定浏览器的能力。例如,脚本在调用某个函数之前,可能
要先检测该函数是否存在。这种检测方法将开发人员从考虑具体的浏览器类型和版本中解放出
来,让他们把注意力集中到相应的能力是否存在上。能力检测无法精确地检测特定的浏览器和
版本。

2    怪癖检测:怪癖实际上是浏览器实现中存在的 bug,例如早期的 WebKit 中就存在一个怪癖,即
它会在 for-in 循环中返回被隐藏的属性。怪癖检测通常涉及到运行一小段代码,然后确定浏
览器是否存在某个怪癖。由于怪癖检测与能力检测相比效率更低,因此应该只在某个怪癖会干
扰脚本运行的情况下使用。怪癖检测无法精确地检测特定的浏览器和版本。

3   用户代理检测:通过检测用户代理字符串来识别浏览器。用户代理字符串中包含大量与浏览器
有关的信息,包括浏览器、平台、操作系统及浏览器版本。用户代理字符串有过一段相当长的
发展历史,在此期间,浏览器提供商试图通过在用户代理字符串中添加一些欺骗性信息,欺骗
网站相信自己的浏览器是另外一种浏览器。用户代理检测需要特殊的技巧,特别是要注意 Opera
会隐瞒其用户代理字符串的情况。即便如此,通过用户代理字符串仍然能够检测出浏览器所用
的呈现引擎以及所在的平台,包括移动设备和游戏系统。
   在决定使用哪种客户端检测方法时,一般应优先考虑使用能力检测。怪癖检测是确定应该如何处理
代码的第二选择。而用户代理检测则是客户端检测的最后一种方案,因为这种方法对用户代理字符串具
有很强的依赖性。
1…891011
鲍志强

鲍志强

求道者

104 日志
19 分类
15 标签
GitHub E-Mail 知乎
© 2016 — 2019 baobaobao
主题 — NexT.Pisces v5.1.4