《JavaScript高级程序设计》Chapter 15 canvas + Chapter 16 HTML5
Chapter 15 Canvas
- <canvas>元素:设定区域。JS动态在这个区域中绘制图形。
- 苹果公司引导的。由几组API构成。
- 2D上下文普及了。WebGL(3D上下文)还未足够普及。
基本用法
- 首先:width、height属性确定绘图区域大小。后备信息放在开始和结束标签之间。
- getContext():DOM获得这个canvas元素对象。再在这个对象上调用getContext()获取上下文,传入参数表示获取的是2d上下文还是WebGL上下文。
- toDataURL()方法,获取绘图区域中的图形对应的URL。注意,若canvas画布“不干净”,即来自不同的域,这个方法会报错。
2D上下文
- 绘制简单的2D图形。
- 坐标原点在canvas元素的左上角,原点坐标(0,0)
- 填充和描边:fillStyle和strokeStyle属性。
- 描边宽度由lineWidth属性控制。
- lineCap属性控制线条末端的形状
- lineJoin属性控制线条相交的方式。
- 绘制矩形:fillRect(),strokeRect()方法,clearRect()方法。4个参数:矩形的x,y坐标,矩形的宽度和高度。
- 绘制路径:
- 开始:beginPath()
- 一系列绘制方法
- 结束:closePath()/fill()/stroke()/clip()
- 是否在路径上:isPointInPath()
- 绘制文本:
- fillText()/strokeText():4个属性:字符串、x、y坐标、可选的最大像素宽度
- 3个属性:font、textAlign、textBaseline
- 辅助确定文本大小:measureText()方法,返回TextMetrics对象,只有width属性。
- 变换:
- 例如rotate(angle)/scale()/translate()/transform()/setTransform
- 记录状态:save()
- 返回上一个状态:restore()
- 记录和返回都是以栈结构的方式,可以一级级进入或者返回。
- 记录和返回只作用于状态或者设置。
- 绘制图像(对<img>或者<canvas>图像进行处理)
- drawImage():多种控制方式
- 阴影
- 渐变:
- createLinerGradient()/createRadiaGradient() ,addColorStop()
- 注意坐标匹配。
- 模式(重复的图像)createPattern()
- 使用图像数据(获取rgba)
- getImageData()获取原始图像数据,返回ImageData对象的实例。
- 上述对象拥有width、height、data属性。
- data属性是数组,每四位表示一个像素的数据,对应rgba
- 可以依次设置灰阶过滤器或者其他过滤器。
- putImageData()将图像数据绘制到画布上。
- 合成:
- globalAlpha属性:通用透明度
- globalCompositionOperation属性:合成方式。存在浏览器差异。
WebGL
- 类型化数组:视图--类型化视图。是WebGL项目的基础。
- 上下文:pdf P488-497
Chapter 16 HTML5 脚本编程
- HTML5增加了新标签,同时也花一定篇幅规定了一些JS的API,以简化复杂的操作。本章介绍了跨文档信息传递,拖放API,音频及视频,历史状态管理等一些操作。
跨文档消息传递(cross-document messaging:XDM)
- 利用postMessage()进行消息传递,postMessage()方法不仅可以在这里使用,功能就是“向另一个地方传送数据”。而XDM中,“另一个地方”指另一个域,一般将消息传给当前页面的<iframe>元素或者由当前页面弹出的窗口。
- 以当前页面的<iframe>元素包含另一个域为例:
- 当前页面需要做的:
- postMessage()传入两个参数:待传入的消息和消息的来源域---这就意味着实际上需要获得“另一个域”的window对象(代理)以在其上使用这个方法。见下个步骤。
- 可以通过document.getElementById("myframe").contentWindow;即contentWindow属性获取目标域的window对象或者代理。调用该方法即可传入数据。
- data不一定需要是字符串,但非字符串的情况在不同浏览器之间存在差异。可以利用JSON.stringify()/JSON.parse()处理字符串。
- 这种方法可以确保安全性,毕竟第二个参数是已知地址。
- <iframe>中的域需要做的:
- 会激发message事件。onmessage处理程序的事件对象event有三个重要属性。
- event的三个属性:data、origin、source
- 可以在确保origin(来源所在域)符合条件的情况下,处理data,再通过source(指向来源的window对象的代理)向来源发送消息,即调用:event.source.postMessage().
- 由于source只是可代理,所以能访问的属性和方法有限。建议只是用postMessage()方法。
- 注意到postMessage()方法是在待向其传送消息的域的代理对象上调用的。
原生拖放
- 注意到,HTML5提供了一些JS的API,向程序员暴露可以使用的属性或者方法,它本身更多的是规定浏览器在这些方法或者属性(或者事件)响应的时候提供一些怎样的显示效果。
- 拖放一般考虑3个阶段:被拖放的对象、拖放过程、放置的目标对象。
- 对应一些拖放事件:对于被拖放的对象,有dragstart/drag/dragend;对于放置的目标对象,有dragenter/dragover/dragleave或drop。很好理解。
- 自定义放置目标:针对有些元素默认是不允许作为放置目标的情况,由于默认是不允许,所以可以在dragenter和dragover中重写默认行为,即阻止默认行为的发生。以此来自定义放置目标。
- dataTransfer对象,为了在拖放操作时实现数据交换,是event的属性,用于从被拖放的元素向放置目标元素传递字符串格式的数据。
- setData()/getData()方法:设置和获取数据。getData()在drop事件中处理。注意在跨浏览器处理setData()的时候注意对短数据类型和MIME类型的处理。
- dropEffect/effectAllowed:两者配合,可以确定被拖放的元素能够执行哪种放置行为(而浏览器会对应给出显示的效果)。dropEffect在ondragenter事件处理程序中针对放置目标进行设置。而effectAllowed属性在ondragstart中针对被拖放的目标进行设置。
- 其他成员:addElement()/clearData()/setDragImage()/types等
- draggable属性:HTML5中的全局属性,规定元素是否可以被拖动。
媒体元素
- 针对HTML5中的<audio>和<video>元素。这两个元素的产生可以让我们减少使用FLASH插件等,更方便实现跨浏览器操作。
- 元素本身就拥有一些属性,且可以进行多个MIME类型和编解码器的选择。
- JS又规定了他俩的一些更加具体和详细的属性和事件,以减轻实现一些操作的繁琐的程序编写过程。
- 可以依赖play()或pause()实现自定义的媒体播放器,这只是代码编写的逻辑问题,比较简单。
- JS提供canPlayType()来检测编解码器的支持情况
- 注意到可能性probably>maybe>空值
- 所以传入MIME类型和编解码器的可能性大于只传入MIME类型的。很好理解。
- JS有原生的Audio构造函数,可以穿件audio实例并进行一些操作。
历史状态管理
- 针对“后退”和“前进”按钮失去作用,使得用户难以在不同的状态(页面状态)间进行切换。可以使用之前(13章)提到过的haschange事件监测状态的变化,以执行某些处理;或者使用HTML5中的历史状态管理API进行操作。
- haschange事件:URL参数列表(包括#后的所有字符串)发生变动的时候触发,主要用在Ajax中,用URL参数数列来保存状态或者导航信息。属性oldURL、newURL可以实现location.hash的功能。一般使用后者,因为支持oldURL和newURL的浏览器不多
- 状态管理API同样可以在不加载新页面的情况下改变浏览器的状态:history.pushState(),传入3个参数:状态对象,新状态标题和可选的URL,注意第二个参数至今不支持,所以可以写入空字符串,而第一个信息最好详尽的记录状态对象各方面的信息,以便随后只用。
- 在执行完这个方法后,新的状态信息会被加入历史状态栈。并且不会真正的向服务器发送请求。
- popstate事件:由于上述方法改变了历史栈,“后退”按钮可用了。在点击后退按钮的时候,触发popstate事件,其事件对象event包含pushState()第一个参数所指的状态对象(这就是为什么上面要求信息详尽的原因了)。注意到,浏览器加载第一个状态(页面)的时候,这个对象为null。
- replaceState():传入参数与pushState()的一样,然而不会在历史状态栈中创建新状态,指挥重写当前状态。
- 注意pushState()的第三个参数务必是实际的URL,不然刷新的时候会导致404错误。