【有书共读】《JS高级程序设计》读书笔记06

十六章. HTML5 脚本编程

跨文档消息传送

跨文档消息传送(cross-document messaging),简称 XDM,指的是在来自不同域的页面间传递消息。

XDM 的核心是postMessage()方法,除了 XDM 部分之外的其他部分也会提到这个方法名,但都是为了同一个目的:向另一个地方传递数据。对于 XDM 而言,另一个地方指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口。

postMessage()方法接受两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。第二个参数对保障安全通信非常重要,可以防止浏览器把消息发送到不安全的地方。如下:

最后一行代码尝试向内嵌框架中发送一条消息,并指定框架中的文档必须来源于http://www.wrox.com域。如果来源匹配,消息会传送到内嵌框架中;否则,postMessage()什么都不做。

接收到 XDM 消息后,会触发window对象的message事件,这个事件是以异步触发的。触发message事件后,传递给onmessage处理程序的事件对象包含以下三方面重要信息:

  • data:作为postMessage()第一个参数传入的字符串数据。
  • origin:发送消息的文档所在的域,例如http://www.wrox.com 。
  • source:发送消息的文档的window对象的***。这个***主要用于在发送上一条消息的窗口中调用postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是window。

最早postMessage()只能传入字符串,后来改成了允许传入任何数据结构,但并非所有浏览器都实现了这一变化,一般对传入的数据使用JSON.stringify()。XDM的兼容 IE8+ 和 其他主流浏览器,也支持相同域的页面间使用。

原生拖放

从 IE4 时代起,网页中的元素就可以被拖动了,HTML5 以 IE 的实例为基础制定了拖放规范。

拖放事件

自定义放置目标

dataTransfer 对象

拖放事件的事件对象拥有dataTransfer属性,用于从被拖放元素向放置目标传递字符串数据。

dataTransfer对象有两个主要的方法:

  • setData():保存数据,这个方法接受两个参数,保存的数据类型和要保存的数据字符串。
  • getData():取得数据,这个方法接受一个参数,即保存的数据类型。

数据类型允许指定各种 MIME 类型,由于要向后兼容,HTML5 也支持"text"和"URL",不过它们会被映射为"text/plain"和"text/uri-list"。dataTransfer对象可以为每种 MIME 都存储一个值,不过只能在drop事件处理程序中处理。

在拖动文本框中的文本时,浏览器会调用setData()方法,将拖动的文本以"text"格式保存在dataTransfer对象中。在拖放图片或者链接时,也会调用setData()方法将链接以"URL"格式保存在dataTransfer对象中。

dropEffect 和 effectAllowed

利用dataTransfer对象不只能传输数据,还能通过它来确定被拖动的元素以及作为放置目标的元素能够接收什么操作。需要访问dataTransfer对象的两个属性dropEffect和effectAllowed。

通过dropEffect属性可以知道被拖动的元素能够执行哪种放置行为。这个属性有下列的 4 个可能值。

  • "none":不能把拖动的元素放在这里。这是除文本框外所有元素的默认值。
  • "move":应该把拖动的元素移动到放置目标。
  • "copy":应该把拖动的元素复制到放置目标。
  • "link":表示放置目标会打开拖动的元素(拖动的元素必须是一个链接,有 URL)。

这个属性只能改变光标样式,光标所指示的动作需要通过编程实现,这个属性必须在 dropenter事件处理程序中针对放置目标设置。

dropEffect属性只有搭配effectAllowed属性才有用。它表示允许拖动元素的哪种dropEffect,可能值如下:

  • "uninitialized":没有给被拖动元素设置任何放置行为
  • "none":被拖动元素不能有任何行为。
  • "copy":只允许值为"copy"的dropEffect。
  • "link":只允许值为"link"的dropEffect。
  • "move":只允许值为"move"的dropEffect。
  • "copyLink":只允许值为"copy"和"link"的dropEffect。
  • "copyMove":只允许值为"copy"和"move"的dropEffect。
  • "linkMove":只允许值为"link"和"move"的dropEffect。
  • "all":允许任意dropEffect。

必须在dragstart事件中设置effectAllowed属性。

可拖动

默认情况下图像、链接和文本是可以拖动的,其他的元素可以通过draggable属性设置为可拖动。IE10+ 支持。

<div draggable="true">...</div>

其他成员

dataTransfer对象还包含下列方法和属性。

  • addElement(element):为拖动操作添加一个元素。添加这个元素只影响数据(即增加作为拖动源而相应回调的对象),不会影响拖动操作时页面元素的外观。
  • clearData(format):清除以特定格式保存的数据。
  • setDragImage(element, x, y):指定一幅图像,当拖动发生时,显示在光标下方。该方法接收的三个参数分别是要显示的 HTML 元素和光标在图像中的 x、y 坐标。
  • types:当前保存的数据类型,是一个类似数组的集合。

媒体元素

HTML5 新增了两个与媒体相关的标签,让开发人员不必依赖任何插件就能再网页中嵌入跨浏览器的音频和视频内容。这两个标签就是<video>和<audio>。使用这两个元素时,至少要在标签中包含src属性,指向要加载的媒体文件。还可以设置width和height属性指定视频播放器大小,而为poster属性指定图像 URI 可以在加载视频内容期间显示一副图像。如果标签中有controls属性,则意味着浏览器应该显示 UI 控件。

由于并非所有浏览器都支持所有媒体格式,所以可以指定多个不同的媒体来源。为此,不用在标签中指定src属性,而是像下面这样显示一个或多个<source>元素。

属性

使用<audio>和<video>元素的play()和pause()方法,可以手工***体文件的播放。自定义媒体播放器事件

<div class="mediaplayer"> <div class="video"> <video id="player" src="movie.mov" poster="mymovie.jpg" width="300" height="200"> Video player not available. </video> </div> <div class="controls"> <input type="button" value="Play" id="video-btn"> <span id="curtime">0</span>/<span id="duration">0</span> </div> </div> 
var player = document.getElementById("player"),
    btn = document.getElementById("video-btn"),
    curtime = document.getElementById("curtime"),
    duration = document.getElementById("duration");

duration.innerHTML = player.duration;            

EventUtil.addHandler(btn, "click", function(event){ if (player.paused){
        player.play();
        btn.value = "Pause";
    } else {
        player.pause();
        btn.value = "Play";
    }
});

setInterval(function(){
    curtime.innerHTML = player.currentTime;
}, 250);

检测编解码器的支持情况

两个媒体元素都有一个canPlayType()方法,该方法接收一种格式/编解码字符串,返回"probably"、"maybe"或""。

Audio 类型

<audio>元素还有一个原生的 JavaScript 构造函数 Audio,可以在任何时候播放音频。

历史状态管理

通过状态管理 API,能够在不加载新页面的情况下改变浏览器的 URL。需要使用history.pushState()方法,该方法接受三个参数:状态对象、新状态的标题和可选的相对 URL。

history.pushState({name: "Nicholas"}, "Nicholas' page", "nicholas.html");

执行pushState()后,新的状态信息就会被加入历史状态栈,而浏览器地址栏也会变成新的相对 URL。但是浏览器不会真的向服务器发送请求,即使状态改变以后查询location.href,也会返回与地址栏相同地址。另外,第二参数目前还没有浏览器实现,因此完全可以只传入一个空字符串,或者一个短标题。而第一个参数则应该尽可能提供初始化页面状态所需的各种信息。

按下“后退”或“前进”按钮会触发window的popstate事件,该事件对象有一个state属性,这个属性包含着当初以第一个参数传递给pushState()的状态对象。

更新当前状态,可以调用replaceState(),传入参数与pushState()的前两个参数相同。调用这个方法不会再历史状态栈中创建新状态,只会重写当前状态。

十七章. 错误处理与调试

错误处理

错误处理在程序设计中的重要性是毋庸置疑的,任何有影响力的web应用程序都需要一套完善的错误处理机制。

try-catch语句

try-catch 语句是 JavaScript 处理异常的一种标准方式,try 块中的任何代码发生了错误,就会立即退出代码执行过程,然后接着执行 catch 块,catch 块会接收到一个包含错误信息的对象,一般用该对象的message属性获取错误信息。如下:

try { // 可能会导致错误的代码 } catch (error){ // 处理错误 alert(erorr.message);
}

finally 子句

finally 子句一经使用,其代码无论如何都会被执行。

try{ return 2;
}catch(err){ return 1;
}finally{ // finally子句无论如何都会执行 return 0;
}

错误类型

JavaScript 有 7 种错误类型,其中,Error 是基类型,其他错误都继承自该类型。

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

抛出错误

使用throw语句,可以抛出上述的错误,也可以抛出自定义的错误;在遇到throw操作符时,代码会立刻停止执行。

// 抛出常规错误 throw new SyntaxError("I don't like your syntax"); throw new TypeError("What type of variable do you take me for?"); throw new RangeError("Sorry, you just dont have the range"); throw new EvalError("That't doesn't evaluate."); throw new URIError("Uri, is that you?"); throw new ReferenceError("You didn‘t cite your references properly."); // 抛出自定义错误 function CustomError(message){ this.name = "CustomError"; this.message = message;
}

CustomError.prototype = new Error(); throw new CustomError("My message");

错误(error)事件

任何没有通过 try-catch 处理的错误都会触发window对象的error事件。任何 Web 浏览器中,onerror事件处理程序都不会创建event对象,但可以接受三个参数:错误消息、错误所在的 URL 和行号。

window.onerror = function(message, url, line){
    alert(message); return false; //阻止浏览器报告错误的默认行为 }

图像也支持error事件,只要图像的src特性的 URL 不能反悔可以被识别的图像格式,就会触发error事件。此时的erorr事件遵循 DOM 格式,会返回一个以图像为目标的event对象。

var image = new Image();

EventUtil.addHandler(image, "load", function(event){
    alert("Image loaded!");
});

EventUtil.addHandler(image, "error", function(event){
    alert("Image not loaded!");
});

image.src = "smilex.gif";

常见的错误类型

一般来说,需要关注三种错误:

  • 类型转换错误
  • 数据类型错误
  • 通信错误

类型转换错误

为避免类型转换错误,建议使用全等操作符:

alert(5 == "5");//true alert(5 === "5");//false 

流控制语句也很容易出错。像 if 之类的语句,在确定下一步操作之前,会自动把任何值转化成布尔值:

数据类型错误

在将变量传递个函数时,对变量进行类型进行检测,可以避免类型错误:

在确切知道应该传入什么类型的情况下,应该使用instanceof来检测类型:

 

通信错误

常见的数据通信错误是把数据发给服务器之前,没有使用encodeURIComponent()对数据进行编码,可以定义一个处理查询字符串的函数:

function addQueryStringArg(url, name ,value){ if(url.indexOf("?") == -1){
        url += "?";
    }else{
        url += "&";
    }
    url += encodeURIComponent(name) + "=" +encodeURIComponent(value); return url;
} var url = "http://www.baidu.com"; var newUrl = addQueryStringArg(url, "redir", "http://wwww.someotherdomain.com?a=b&b=c");
alert(newUrl);

区分致命错误与非致命错误

非致命错误(这类错误没有必要对用户给出提示):

  • 不影响用户的主要任务
  • 只影响页面的一部分
  • 可以恢复
  • 重复相同操作可以消除错误

致命错误(这类错误应该立即给用户发送消息):

  • 应用程序根本无法运行
  • 错误明显影响到了用户的主要操作
  • 会导致其他连带错误

调试技术

将消息记录到控制台

可以使用console对象向 JavaScript 控制台写入消息来调试,这个对象具有下列方法:

  • error(message):将错误消息记录到控制台
  • info(message):将信息性消息记录到控制台
  • log(message):将一般消息记录到控制台
  • warn(message):将警告消息记录到控制台
function sum(num1, num2){ console.log("Enter sum(), arguements are " + num1 + ", " +num2 ); console.log("Before calculation"); var result = num1 + num2; console.log("After calculaation"); console.log("Exiting sum()"); return result;
}

将消息记录在当前页面

在页面开辟一小块信息,用于显示错误信息:

抛出错误

如果错误消息很具体,基本可以把它当做错误来源的依据,那么可以直接抛出错误:

也可以自定义一个assert语句:

常见的 IE 的错误

IE 是最难调试 JavaScript 错误的浏览器,以下介绍一些错误:

操作中止

对于 IE8 之前的版本,在修改尚未加载完的页面时,会发生操作中止错误。

无效字符

无效字符是 JavaScript 中没有定义的字符,例如直接从 word 中赋值文本到编辑器里,然后又在 IE 中运行,则可能会遇到无效字符的错误。

未找到成员

IE 中的所有 DOM 对象都是以 COM 对象实现的,这会导致一些与垃圾收集相关的非常奇怪的行为。IE 中的未找到的成员错误,就是由于垃圾收集例程配合错误所直接导致的。

具体来说,如果在对象被销毁之后,又给该对象赋值,就会导致未找到成员错误。如下:

未知运行时错误

当使用innerHTML或者outerHTML以下列方式指定 HTML 时,就会发生未知运行时错误:

  • 把块级元素插入到行内元素
  • 访问表格的任意部分的任意属性

语法错误

如果引用外部的 JavaScript 文件,而该文件最终没有返回 JavaScript 代码,IE 会抛出语法错误。

系统无法找到指定资源

当 URL 的长度超过 IE 对 URL 的最长不能超过 2083 个字符的限制时,就会发生这个错误。如下:

function createLongUrl(url){ var s = "?"; for(var i = 0; i < 2500; i++){
        s += "a";
    } return url + s;
} var x = new XMLHttpRequest();
x.open("get", createLongUrl("http://www.baidu.com/"), true);
x.send(null);
#设计##读书笔记##笔记#
全部评论

相关推荐

不愿透露姓名的神秘牛友
07-02 17:58
点赞 评论 收藏
分享
小叮当411:应该是1-3个月吧
点赞 评论 收藏
分享
代码飞升:别用口语,后端就写后端,前端就写前端,最后别光后悔
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务