技术栈

主页 > 前端开发 >

JS权威指南读书笔记(四)

第十三章 Web浏览器中的JavaScript

在HTML里嵌入JavaScript

在HTML文档里嵌入客户端JavaScript代码有4种方法:

  1. 内联,放置在<script></script>标签对之间。
  2. 放置在由<script>标签的src属性指定的外部文件中。
  3. 放置在HTML事件处理程序中,该事件处理程序由onclick这样的HTML属性值指定。
  4. 放在一个URL里,这个URL使用特殊的"javascript:"协议。

现在大部分项目使用的是第二种方法,也就是通过src的方式引入脚本,使用该方法有以下优点:

  • 可以把大量的JS代码从HTML文件删除,有助于保持内容和行为的分离。
  • 如果多个Web页面共用相同的JS代码,用src属性就可以很方便的引入脚本。而且不需要重复写脚本。
  • 如果一个脚本由多个页面共享,那么只需要下载一次。其他的页面可以在浏览器缓存中读取。
  • 可以使用其他web服务器提供的脚本代码。很常用的做法就是引入第三方库的时候,一般使用百度或者谷歌提供的cdn地址。

URL中的JavaScript

javascript:URL 这个字符串是会被JS解释器运行的JS代码。它被当做单独的一行代码对待,这意味着语句之间必须用分号隔开,而//注释必须换成/* */.
javascript:URL能识别的“资源”是转换成字符串的执行代码的返回值。如果代码返回undefined,那么这个资源就是没有内容的。
javascript:URL可以用在可以使用常规URL的任意地方:比如<a>的href属性,<form>的action属性,甚至window.open()方法的参数。

如果要确保javascript:URL不会覆盖当前文档,可以用void操作符强制函数调用或给表达式赋予undefined值。比如:

<a href="javascript:void;"></a>

第14章 Window对象

浏览器定位和导航

Window对象的location属性引用的是Location对象,表示该窗口中当前显示的文档的URL,Document对象的location属性引用的也是Location对象,所以两者是恒等的(在浏览器内):

window.location === document.location
// 返回true

Document对象也有一个URL属性,是文档首次载入后保存该文档的URL的静态字符串。如果定位到文档中的片段标识符,Location对象会做相应的更新,而document.URL属性却不会改变。

以下是google首页https://www.google.com.hk/?hl=zh-CN&gws_rd=ssl的window.location的具体属性。

DOMStringList {length: 0}
assign:ƒ ()
hash:""
host:"www.google.com.hk"
hostname:"www.google.com.hk"
href:"https://www.google.com.hk/?hl=zh-CN&gws_rd=ssl"
origin:"https://www.google.com.hk"
pathname:"/"
port:""
protocol:"https:"
reload:ƒ reload()
replace:ƒ ()
search:"?hl=zh-CN&gws_rd=ssl"
toString:ƒ toString()
valueOf:ƒ valueOf()
Symbol(Symbol.toPrimitive):undefined

下面说几个比较重要的属性:
Location对象的href属性是一个字符串,后者包含URL的完整文本。Location对象的toString()方法返回href属性的值,因此在会隐式调用toString()的情况下,可以使用location代替location.href。所以以下代码是等价的:

window.location.href = 'https://www.google.com'
window.location = 'https://www.google.com'

search属性返回的是问号之后的URL(包括问号?),一般是用来查询的字符串,最常用的用法就是使用search在不同页面之间传递不敏感的信息,比如id之类的。标准的search参数是形如?key=value&key=value,在笔者开发的项目中,导出文件就是使用search参数通过get请求向后台传递参数,有一个问题就是在实际的生产环境(edas环境)中,传递中文参数会报错,所以前端还需要将value使用encodeURI()进行编码。

window.location.replace()在载入新文档之前会从浏览历史中把当前文档删除。如果检测到用户的浏览器不支持某些新特性,那么就可以使用该方法来载入polyfill版本。

if (!ifSupport) {
    window.location.replace('your page');
}

如果replace()的参数是一个相对URL,那么就会相对于当前页面所在的目录来解析。

执行window.location.reload()会刷新当前页面。

浏览器和屏幕信息

Navigator对象

Window对象的navigator属性引用的是包含浏览器厂商和版本信息的Navigator对象。下面是MacBook Air的主要window.navigator属性:

appCodeName:"Mozilla"
appName:"Netscape"
appVersion:"5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
cookieEnabled:true
language:"zh-CN"
languages:(4) ["zh-CN", "zh", "en", "fr"]
maxTouchPoints:0
onLine:true
platform:"MacIntel"
product:"Gecko"
productSub:"20030107"
usb:USB {onconnect: null, ondisconnect: null}
userAgent:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
vendor:"Google Inc."

appName:

Web浏览器的全称。在旧版本IE中,就是"Microsoft Internet Explorer"。为了兼容现存的浏览器嗅探代码,其他浏览器(包括新版的IE)通常也取名为"Netscape"。

appVersion:

此属性通常以数字开始,并跟着包含浏览器厂商和版本信息的详细字符串。前面的数字通常是4.0或者5.0,表示是第4代或第5代兼容的浏览器。但是该字符串没有标准的格式,无法来判断浏览器类型。通常使用的是userAgent属性。

userAgent:

浏览器在它的USER-AGENT HTTP头部发送的字符串。这个属性通常包含appVersion中的所有信息,并且常常可能包含其他细节,虽然没有标准格式,但是由于包含绝大部分信息,因此使用该属性判断浏览器类型。
下面是一个判断浏览器类型的通用方法:

function getExplore() {
    var sys = {},
        ua = navigator.userAgent.toLowerCase(),
        s;
    (s = ua.match(/rv:([d.]+)) like gecko/)) ? sys.ie = s[1]:
        (s = ua.match(/msie ([d.]+)/)) ? sys.ie = s[1] :
        (s = ua.match(/edge/([d.]+)/)) ? sys.edge = s[1] :
        (s = ua.match(/firefox/([d.]+)/)) ? sys.firefox = s[1] :
        (s = ua.match(/(?:opera|opr).([d.]+)/)) ? sys.opera = s[1] :
        (s = ua.match(/chrome/([d.]+)/)) ? sys.chrome = s[1] :
        (s = ua.match(/version/([d.]+).*safari/)) ? sys.safari = s[1] : 0;
    // 根据关系进行判断
    if (sys.ie) return ('IE: ' + sys.ie)
    if (sys.edge) return ('EDGE: ' + sys.edge)
    if (sys.firefox) return ('Firefox: ' + sys.firefox)
    if (sys.chrome) return ('Chrome: ' + sys.chrome)
    if (sys.opera) return ('Opera: ' + sys.opera)
    if (sys.safari) return ('Safari: ' + sys.safari)
    return 'Unknown'
}

onLine:
表示浏览器当前是否连接到网络。可以根据这个布尔值状态来进行一些操作。

Screen对象

Window对象的screen属性引用的是Screen对象。以下是chrome 62的window.screen属性的具体属性:

availHeight:797
availLeft:0
availTop:23
availWidth:1440
colorDepth:24
height:900
pixelDepth:24
width:1440

属性width和height指定的是以像素为单位的窗口大小。属性availWidth和availHeight指定的实际可用的显示大小。属性colorDepth指定的是显示的BPP(bits-per-pixel)值,典型的值由16、24和32。
可以用Screen对象来确定Web应用是否运行在一个小屏幕的设备上。

打开和关闭窗口

window.open()用来打开一个新的浏览器窗口。该方法指定的URL到新的或已存在的窗口中,并返回代表那个窗口的Window对象。open()有4个可选的参数
第一个参数是要在新窗口显示的URL。如果省略这个参数,那么空页面的URL为about:blank
第二个参数是新打开窗口的名字。如果指定一个已经存在的窗口的名字,那么会直接使用(跳到)已存在的窗口。否则,会打开新的窗口,并且将指定的名字赋值给新窗口。如果省略此参数,那么新窗口的name为''。(chrome 62)查看新窗口的name可以通过window.name来获取到,该属性是可读可写的,脚本可以随意设置。
第三个参数是一个以逗号分隔的列表,包含大小和各种属性,用来表明新窗口如何打开。比如,要打开允许改变大小的浏览器窗口,并且包含状态栏、工具栏和地址栏,可以这样:

window.open("https://www.google.com.hk","someName","width=400,height=350,status=yes,resizable=yes");

然后就会打开一个指定宽高,但是没有状态栏、工具栏,可以缩放窗口。在chrome 62测试后,不论status值为true或false,新窗口都没有工具栏,不论resizable值为何,都可以改变窗口大小。
第三个参数是非标准的,HTML5规范也主张浏览器忽略。
第四个参数只有在第二个参数命名的是一个存在的窗口时才有用。该参数是一个布尔值,声明了由第一个参数指定的URL是替换掉当前URL(true),还是在新窗口新建一个URL(false),默认值为false。

第15章 脚本化文档

节点列表和HTML集合

getElementsByName()getElementsByTagName都返回NodeList对象,而类似document.imagesdocumemnt.forms的属性为HTMLCollection对象。
NodeList和HTMLCollection对象都是只读的类数组对象。具有leng属性,也具有索引(只读)。所以可以使用for循环进行迭代。
但是他们不是真正的数组,所以不能直接在两个集合上面调用Array的方法,可以通过以下方式来调用:

var tag = document.getElementsByTagName('*') 
var content = Array.prototype.map.call(tag,function(e) {
    return e.innerHTML;
});
//下面的方法是使用了ES6的数组方法from(),该方法将类数组转化为真正的数组。
let array = Array.from(tag);

NodeList和HTMLCollection对象不是历史文档状态的静态快照,而是实时的。如果在一个不存在div元素的文档中插入一个新的<div>元素,那么getElementsByTagName('div')length属性会由0变为1.

通过CSS选择器选取元素

与CSS3选择器的标准化一起的另一个称做“选择器API”的W3C标准定义了获取匹配一个给定选择器的元素的JS方法。该API的关键的Document方法querySelectorAll()。接受包含一个CSS选择器的字符串参数,返回一个表示文档中匹配选择器的所有元素的NodeList对象。

需要注意的是,querySelectorAll()返回的NodeList不是实时的。只包含调用时刻选择器所匹配的元素,不更新后续变化。如果没有匹配的元素,将返回一个空的NodeList对象([])。如果选择器字符串非法,将抛出异常。

类似的还有querySelector()方法。但是与querySelectorAll()不同的是,querySelector()只返回第一个匹配的元素,如果没有匹配的元素那么就返回null。

在CSS中,伪元素匹配文本节点的一部分而不是实际元素。如果和querySelector()querySelectorAll()一起使用它们是不匹配的。而且很多浏览器会拒绝返回":link"等伪类的匹配结果,因为会泄露用户的浏览历史记录。jQuery的$()querySelectorAll()就是等效的。

文档结构和遍历

Document对象、Element对象和Text对象都是Node对象。Node定义了以下重要的属性:

parentNode
该节点的父节点。如果一个节点没有父节点,那么将会返回null。

childNodes
只读的类数组对象,它是该节点的子节点的实时表示

firstChild、lastChild
该节点的子节点中的第一个和最后一个,如果没有则返回null。

nextSibling、previousSibling
该节点的兄弟节点的前一个和下一个。如果没有则返回null。

nodeType
该节点的类型。具体值见下表(参考于MDN)

常量描述
Node.ELEMENT_NODE1一个元素节点,例如<p>和<div>
Node.TEXT_NODE3Element或者Attr中实际的文字
Node.PROCESSING_INSTRUCTION_NODE7一个用于XML文档的 ProcessingInstruction ,例如<?xml-stylesheet ... ?>声明。
Node.COMMENT_NODE8一个 Comment 节点。
Node.DOCUMENT_NODE9一个 Document 节点。
Node.DOCUMENT_TYPE_NODE10描述文档类型的 DocumentType 节点。例如 <!DOCTYPE html> 就是用于 HTML5 的。
Node.DOCUMENT_FRAGMENT_NODE11一个 DocumentFragment 节点

为什么值不是连续的,因为1-12中没有的值已经被废弃了,无需了解。

nodeValue
Text节点或Comment节点的文本内容。

nodeName
元素的标签名,以大写形式表示。

属性

表示HTML文档元素的HTMLElement对象定义了读/写属性,它们映射了元素的HTML属性。HTMLElement定义了通用的HTTP属性(比如id)的属性。特定的Element子类型为其元素定义了特定的属性。例如:

var image = document.getElementById("id");
var imgUrl = image.src;//获取图片的URL
var id = image.id;//获取节点的id属性

HTML属性名不区分大小写,但是JS属性名则大小写敏感。如果属性名包含不止一个单词,那么应该采用驼峰命名来书写js属性名。

有些HTML属性名在JS中是保留字。一般规则是为JS属性名加上前缀html。比如,HTML的for属性(<label>元素)在JS中变为htmlFor属性。HTML的属性class变为className

数据集属性

在HTML5文档中,任意以"data-"为前缀的小写的属性名字都是合法的。HTML5还在Element对象上定义了dataset属性。比如:

var node = document.getElementById('id');
node.dataset.x = 'x';
//node.dataset.x保存的就是data-x属性的值。

node.dataset.nameTest = 'test';
// node.dataset.nameTest驼峰式命名保存的是data-name-test属性的值。

dataset属性是实时、双向接口。

元素的内容

未完待续。。。

责任编辑:admin  二维码分享:
本文标签: 属性URLsys浏览器节点对象
点击我更换图片

评论列表