红宝书系列读书笔记(七)

HTML5脚本编程

1.跨文档消息传递
跨文档消息传送,有时简称XDM,指的是在来自不同域的页面间传递消息。
XDM的核心是postMessage()方法,该方法的作用是:向另一个地方传递数据。
对于XDM而言,“另一个地方”指的是包含在当前页面中的<iframe>元素,或者由当前页面弹出的窗口。
postMessage()方法接收两个参数:一条消息和一个表示消息接收方来自哪个域的字符串。

1
2
3
//注意:所有支持XDM的浏览器也支持iframe的contentWindow属性
var iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("A secret","http://www.wrox.com");

接收到XDM消息时,会触发window对象的message事件,是以异步形式触发的,因此从发送消息到接收消息(触发窗口的message事件)可能要经过一段时间的延迟。
触发message事件后,传递给onmessage处理程序的事件对象(event)包含以下三方面的重要信息:
data:作为postMessage()第一个参数传入的字符串数据。
origin:发送消息的文档所在的域。
source:发送消息的文档的window对象的代理。这个代理对象主要用于在发送上一条消息的窗口中调用postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是window。

1
2
3
4
5
6
7
8
9
EventUtil.addHandler(window,"message",function(event){
    //确保发送消息的域是已知的域
    if(event.origin=="http://www.wrox.com"){
        //处理接收到的数据
        processsMessage(event.data);
        //可选:向来源窗口发送回执
        event.source.postMessage("Received","http://p2p.wrox.com");
    }
});

event.source大多数情况下只是window对象的代理,不能通过这个代理对象访问window对象的其他任何信息。
在使用postMessage()时,最好是只传字符串,如果想传入结构化的数据,最佳选择是先在要传入的数据上调用
JSON.stringify(),通过postMessage()传入得到字符串,然后再在onmessage事件处理程序中调用JSON.parse()。

2.原生拖放
拖放事件
拖动某元素时,将依次触发下列事件:
1)dragstart
2)drag
3)dragend
当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:
1)dragenter
2)dragover
3)dragleave(拖出了目标)或drop(放到目标中)

自定义放置目标
有些元素默认是不允许放置,但可以重写该元素的dragover和dragenter事件的默认行为,来使得元素变成有效的放置目标。

1
2
3
4
5
6
7
var droptarget = document.getElementById("droptarget");
EventUtil.addHandler(droptarget,"dragover",function(event){
    EventUtil.preventDefault(event);
});
EventUtil.addHandler(droptarget,"dragenter",function(event){
    EventUtil.preventDefault(event);
});

在firefox3.5+中,放置事件的默认行为是打开被放到放置目标上的URL,因此,为了让firefox 支持正常的拖放,还要取消事件的默认行为:
EventUtil.addHandler(droptarget,”drop”,function(event){
EventUtil.preventDefault(event);
});

dataTransfer对象
为了在拖放操作时实现数据交换,引入dataTransfer 对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。
dataTransfer对象主要有两个方法:getData()和setData()。

1
2
3
4
5
6
//设置和接收文本数据
event.dataTransfer.setData("text","some text");
var text = event.dataTransfer.getData("text");
//设置和接收URL
event.dataTransfer.setData("URL","http://www.wrox.com/");
var text = event.dataTransfer.getData("URL");

为了实现跨浏览器从dataTransfer对象取得数据,最好在取得URL数据时检测两个值,而在取得文本数据时使用“Text”.

1
2
3
4
5
var dataTransfer = event.dataTransfer;
//读取URL
var url = dataTransfer.getData("url") ||dataTransfer.getData("text/uri-list");
//读取文本
var text = dataTransfer.getData("Text") ;

dropEffect与effectAllowed
dataTransfer对象的两个属性:dropEffect和effectAllowed.
dropEffect有4个可能d值:
none:不能把拖动的元素放在这里。
move:应该把拖动的元素移动到放置目标。
copy:应该把拖动的元素复制到 放置目标。
link:表示放置目标会打开拖动的元素(但拖动的元素必须是一个链接,有URL)。

dropEffect属性只有搭配effectAllowed属性才有用。
effectAllowed有以下可能的值:
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。

必须在ondragstart事件处理程序中设置effectAllowed属性。

可拖动
默认情况下,图像、链接和文本是可以拖动的,但文本只有在被选中的情况下才可被拖动。
要想让其他元素也可被拖动,HTML5为所有HTML元素规定了draggable属性,表示元素是否可以拖动。

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

其他成员
HTML5还规定了dataTransfer对象还应该包含下列方法和属性:
addElement(element):为拖动操作添加一个元素。
clearData(format):清除以特定格式保存的数据。
setDragImage(element,x,y):指定一副图像,当拖动发生时,显示在光标下方。这个方法接收三个参数分别
是要显示的HTML元素和光标在图像中的x、y坐标。
types:当前保存的数据类型。

拖拽实现原理
计算出鼠标移动的距离,然后将元素的坐标位置加上鼠标前后坐标之差,最后改变元素的top和left值

1
2
3
4
nn6 = document.getElementById && !document.all;//判断是否是IE6浏览器
dragObj.style.top = (nn6 ? objY + e.clientY - mouseY : objY + event.clientY - mouseY) + "px";
dragObj.style.left = (nn6 ? objX + e.clientX - mouseX : objX + event.clientX - mouseX) + "px";
(e.clientX和e.clientY是鼠标当前的坐标位置,mouseX和mouseY是鼠标原来的坐标位置,objX和objY是元素的坐标位置)

媒体元素

<video>和<audio>
常用属性:
常用属性
全部属性:
全部属性
常用方法
常用方法
事件
事件

自定义媒体播放器

1
2
3
4
5
6
7
8
9
10
11
<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>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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”和“”(空字符串)。空字符串是假值,其他两个位真值,会转换为true。

1
2
3
if(audio.canPlayType("audio/mpeg")){
    
}

Audio类型
<audio>元素还有一个原生的Javascript构造函数Audio,与Images很相似。

1
var audio = new Audio("sound.mp3");

历史状态管理

通过hashchange事件,可知道URL的参数什么时候发生了变化。
通过状态管理API(HTML5的history对象),能够在不加载新页面的情况下改变浏览器的URL。
history.pushState()方法接收三个参数:状态对象、新状态的标题和可选的相对URL。

1
history.pushState({name:"Peter"},"Peter' page","peter.html");

执行pushState()方法后,新的状态信息就会被加入到历史状态栈中。
当按下“后退”按钮时,会触发window对象的popstate事件。popstate事件的事件对象有一个state属性。
当单击“后退”按钮返回浏览器加载的第一个页面时,event.state=null。
更新当前状态,调用replaceState(),传入参数与pushState()的前两个参数相同。
传递给pushState()或replaceState()的状态对象不能包含DOM元素。

重点了解利用history.pushState实现的pjax技术。

JSON

JSON是一种数据格式,不是一种编程语言,且并不从属与Javascript。
1.语法
JSON语法可以表示以下三种类型的值:
简单值:使用与javascript相同的语法,可以在JSON中表示字符串、数值、布尔值和null,但不支持javascript中的undefined。
JSON字符串必须使用双引号(单引号会导致语法错误)

对象:对象作为一种复杂数据类型,表示的是一组无序的键值对。而每个键值对中的值可以是简单值,也可以是复杂数据类型的值。
JSON中的对象要求给属性加双引号,此外JSON没有变量的概念。

1
2
3
4
{
    "name":"Peter",
    "age":29
}

数组:表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值可以是任意类型——简单值、对象或数组。
eg:[25,”hi”,true]

2.解析与序列化
JSON对象
早期的JSON解析器基本上是使用javascript的eval()函数,但存在风险。
JSON对象有两个方法:stringify()和parse()。在最简单的情况下,这两个方法分别用于把javascript对象序列化为JSON字符串和把JSON字符串解析为原生javascript值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var book={
    title:"Professional JavaScript",
    authors:["Nicholas C. Zakas"],
    edition: 3,
    year:2011
};
var jsonText = JSON.stringify(book); //将javascript对象序列化为JSON字符串
在jsonText中:
{
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    "edition": 3,
    "year":2011
}
var boookCopy = JSON.parse(jsonText);//将JSON字符串解析为原生javascript值

序列化选项
JSON.stringify()除了要序列化的javascript对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化javascript对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在JSON字符串中保留缩进。
1.过滤结果
如果过滤参数是数组,那么JSON.stringify()的结果中将只包含数组中列出的属性。

1
2
3
4
5
6
7
var book={
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    edition: 3,
    year:2011
};
var jsonText = JSON.stringify(book,["title","edition"])

在jsonText中为:

1
2
3
4
{
    "title":"Professional JavaScript",
    "edition": 3
}

如果第二个参数是函数,行为会稍有不同。传入的函数接收两个参数,属性(键)名和属性值。
根据属性(键)名可以知道应该如何处理要序列化的对象中的属性。属性名只能是字符串,而在值并非键值对结构的值时,键名可以是空字符串。函数返回的值就是相应键的值,但函数返回的是undefined,那么相应属性会被忽略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var book={
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    edition: 3,
    year:2011
};
var jsonText = JSON.stringify(book,function(key,value){
    switch(key){
        case "authors": return value.join(",");
        case "year": return 5000
        case "edition": return undefined;
        default: return value;
    }
});

序列化后,jsonText值为:

1
2
3
4
5
{
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    "year":5000
}

2.字符串缩进
JSON.stringify()方法的第三个参数数用于控制结果中的缩进和空白符。
第三个参数为数值时,表示每个级别缩进的空格数,最大缩进格数为10;
如果为字符串非数值,则这个字符串将在JSON字符串中被用作缩进字符(不再使用空格)

3.toJSON()方法

1
2
3
4
5
6
7
8
9
10
11
var book={
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    edition: 3,
    year:2011,
    toJSON:function(){
        return this.title;
    }
};
var jsonText = JSON.stringify(book);//图书的书名

序列化对象的顺序
1)如果存在toJSON()而且能通过它取得有效的值,则先调用该方法,否则返回对象本身。
2)如果提供了第二个参数,应用这个函数过滤器。
3)对第二步返回的每个值进行相应的序列化。
4)如果提供了第三个参数,执行相应的格式化

解析选项
JSON.parse()也可以像接收另一个参数,该参数是一个函数(还原函数),将在每一个键值对上调用。
如果还原函数返回undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var book={
    "title":"Professional JavaScript",
    "authors":["Nicholas C. Zakas"],
    edition: 3,
    year:2011,
    releaseDate: new Date(2015,11,8);
};
var jsonText = JSON.stringify(book);
var bookCopy = JSON.parse(jsonText,function(key,value){
    if(key=="releaseDate"){
        return  new Date(value);
    }else{
        return value;
    }
});

结果为:bookCopy.releaseDate属性中保存一个Date对象。

坚持原创技术分享,您的支持将鼓励我继续创作!