《JavaScript DOM编程艺术》笔记

作者 Loaln 日期 2019-07-09
《JavaScript DOM编程艺术》笔记

初次更新:2019-07-09
最新更新:2019-07-22

前言


大三期间,自己根据视频简单地学习了JavaScript,通过阅读这本书,对知识内容进行补充记录。

传送门:
学习视频:【极客学院】Javascript入门教程
自己练习记录:https://loaln.github.io/WebFont-end_Practice/

第一章 JavaScript简史


第二章 JavaScript语法


2.1 准备工作

  • 引用js最好的做法是把<script>标签放到HTML文档的最后,</body>标签之前,这样能使浏览器更加快地加载页面(第五章有详解)。

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>demo</title>
    </head>
    <body>
    hhhh
    <script src="demo.js"></script>
    </body>
    </html>
  • 程序设计语言分为解释型和编译型两大类,JavaScript属于解释型。

  • JavaScript允许程序员直接对变量赋值而无需事先命名,但最好不要。
  • 驼峰式命名:删除中间的空白(下划线),后面的每个新单词改用大写字母开头,是函数名、方法名和对象属性名命名的首选格式。如:

    var myMood = "Happy";

    注:函数命名多加下划线以区分。

2.3 算术操作符

  • 加号(+)是一个比较特殊的操作符,它既可以用于数值,也可以用于字符串。甚至可以把数值和字符串拼接在一起。因为JavaScript是一种弱类型语言,此时,数值将被自动转换成字符串。例如:

    var message = "I am feeling" + "good";
    var year 1997;
    var message = "This year is" + year; //这里year被转换成字符串
  • 符号(+=),它可以一次完成“加法和赋值”。

    var year = 2019;
    var message = "This year is";
    message += year; //其中打印结果:This year is 2019

2.4 条件语句

  • ==和===区别:全等操作符(===)不仅比较值,还会比较变量的类型。!=和!==一样的道理。

2.7 对象

  • 对象里的数据可以通过两种方式访问——属性(property)和方法(method)。
    var lennon = Object();
    lennon.name = lennon;
    lennon.age = 18;
    lennon.meoth();

for/in循环(8.4.2创建标记中提及)

  • 遍历关联数据时可以采用for/in循环该方式,这是由于数组的下标不再是数字,而是人为的命名。其语法如下:
    for (variable in arry)
    在进入第一次循环是,变量variable将被赋值为数组array的第一个元素的下标值;在进入第二次循环时,变量variable将被赋值为数组array的第二个元素的下标值;依此类推,直到遍历完数组array里面的所有元素为止。

第三章 DOM


3.4 节点

  • 元素节点:DOM属下的各类标签,如:<body><p><ul>等之类的元素。
  • 文本节点:文本节点总是被包含在元素节点的内部。如:<p>nihaoma</p>中的“nihaoma”就是本文节点。
  • 属性节点:属性节点用来对元素做出更具体的描述。如:<p title="a demo">nihaoma</p>中的title就是属性节点。
  • getElementById返回一个对象,该对象对应着文档里的一个特定的元素节点。
  • getElementByTagName的参数:不仅类名的实际顺序不重要,就算元素还带有更多的类名也没有关系。
  • getElementByTagName和getElementByClassName将返回一个对象数组,他们分别对应着文档里的一组特定的元素节点。
  • 获取和设置属性:object.getAttribute(attribute)和object.setAttribute(attribute,value)。

第四章 案例研究:JavaScript图片库


4.3 应用这个JavaScript函数

  • 事件处理函数:onclick:注意return true和return false在其中的应用。

4.4 对这个函数进行扩展

  • childNodes属性用来获取任何一个元素的所有子元素,返回的是数组。返回的数组包含所有类型的节点,而不仅仅是元素节点。
  • nodeType属性总共有12种可取值,但其中仅有3种具有实用价值:
    • 元素节点的nodeType属性值是1;
    • 属性节点的nodeType属性值是2;
    • 文本节点的nodeType属性值是3.
  • nodeValue属性用来获取一个节点的值。
  • firstChild和lastChild属性,分别是childNodes返回数组中的第一个和最后一个。

第五章 最佳实践


5.2 平稳退化

  • 假设用户禁用浏览器的JavaScript,用户仍然能浏览大部分内容。
  • “javascript:”伪协议(待了解清楚,但似乎不建议用)。

5.5 向后兼容

  • 对象检测:检测浏览器是否支持该函数。例如:
    如果有一个使用了getElementById()方法的函数,就可以在调用getElementById()方法之前先检查用户所使用的浏览器是否支持该方法。在使用对象检测之前,一定要删除方法名后面的圆括号,如果不删除掉,测试的将是方法的结果,无论方法是否存在。

    function myFunction(){
    if(document.getElementById){
    statement using getElementById
    }
    }
  • 浏览器嗅探技术:指通过提取浏览器供应商提供的信息来解决向后兼容的问题。

5.6 性能考虑

  • 尽量少访问DOM和尽量减少标记。
    因为不管什么时候,只要是查询DOM中的某些元素,浏览器都会搜索整个DOM树,从中查询可能匹配的元素。
  • 放置脚本。
    一般来说,根据HTTP规范,浏览器每次从同一个域名中最多只能同时下载两个文件。而在下载脚本期间,浏览器不会下载其他任何文件,即使是来自不同域名的文件也不会下载,所有其他资源都要等到脚本功能加载完毕后才能下载。
    所以,把所有<script>标签都放到文档的末尾,</body>标记之前,就可以让页面变得更快。即使这样,在加载脚本是,window对象的load事件依然可以执行对文档进行各种操作,防止加载未完成。
  • 压缩脚本。
    多数情况下,应该有两个版本,一个是包含注释的脚本,一个是删去注释和各类不必要的换行和空格的精简版本,通常会在文件命名加上min字样。
    推荐代码压缩工具:

第六章 案例研究:图片库改进版


6.3.2 共享onload事件(addLoadEvent)

  • addLoadEvent事件可以帮助解决文档加载完调用多个函数的问题。它不是DOM自带事件,需人为添加。下面进行简单的介绍:
    addLoadEvent函数将要完成的操作:
    • 把现有的window.onload事件处理函数的值存入到oldonload中;
    • 如果在这个处理函数上还没有绑定任何函数,就将该函数添加给它;
    • 如果在这个处理函数上已经绑定了一些函数,就把该函数追加到现有指定的末尾。
function addLoadEvent(func){
var oldonload=window.onload;//将现有的事件处理函数的值存入变量中
if(typeof window.onload!='function'){
window.onload=func;//如果这个事件处理函数没有绑定任何函数,就把新函数添加给它
}else{
window.onload=function(){
onload();
func();//如果已经绑定了函数,就把新函数追加到现有指令的末尾
}
}
}

    最后,只需要在js脚本最后添加如下,便能在脚本完成后调用多个函数。
    注意,一定在要脚本最后加入,因为要等待其他函数加载完成后才能调用到。

addLoadEvent(firstFunction);
addLoadEvent(secondFunction);
...

addLoadEvent学习参考链接:
https://www.cnblogs.com/yangtoude/p/4753306.html
https://www.imooc.com/wenda/detail/336004

第七章 动态创建标记


7.2 DOM方法

  • createElement()方法:创建元素节点。
  • createTextNode()方法:创建文本节点。
  • appendChild()方法:将创建的节点插入某一节点中。语法为:parent.appendChild(child)
  • insertBefore()方法:在已有元素前插入一个新元素。
    • 新元素:你插入的元素(newElement);
    • 目标元素:你想把这个新元素插入到哪个元素(targetElement)之前;
    • 父元素:目标元素的父元素(parentElement)。
      语法为:parentElement.insertBefore(newElement,targetElement)
  • DOM没有直接提供在已有元素后插入一个新元素的方法。编写insertAfter函数:
function insertAfter(newElement,targetElement) {
var parent = targetElement.parentNode;
if (parent.lastChild == targetElement) {
parent.appendChild(newElement);
} else {
parent.insertBefore(newElement,targetElement.nextSibling);
//targetElement.nextSibling为目标元素的下一个兄弟元素
}
}

7.4 Ajax(自行查找补充)

Ajax部分转载链接:总结 - Ajax工作原理和实现步骤

(1) Ajax简介

  • Ajax与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。
  • Ajax的主要优势就是对页面的请求以异步方式发送到服务器,从而进行页面的局部刷新,不影响用户的浏览体验。

(2) Ajax所包含的技术

大家都知道ajax并非一种新的技术,而是几种原有技术的结合体。它由下列技术组合而成。

  1. 使用CSS和XHTML来表示。
  2. 使用DOM模型来交互和动态显示。
  3. 使用XMLHttpRequest来和服务器进行异步通信。
  4. 使用javascript来绑定和调用。

AJAX 的核心是 XMLHttpRequest 对象。
不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。
IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 JavaScript 内建对象。

(3) Ajax的工作原理

  1. 浏览器捕获用户的操作,并进行相应的处理,然后把用户的操作反馈到服务器。
  2. 服务器接收浏览器端传来的用户操作,然后再把用户操作分发到其他浏览器端。
  3. 浏览器接收由服务器端分发下来的用户动作,并进行相应的处理。

(4)XMLHttpRequest对象的三个常用属性

  1. onreadystatechange属性:该属性存有处理服务器响应的函数。
xmlHttp.onreadystatechange=function(){
//填写我们需要执行的函数代码块
}
  1. readyState属性:该属性存有服务器响应的状态信息。每当readyState改变时,onreadystatchange函数就会被执行。
    readyState属性可能的值:
状态 描述
0 未初始化。请求未初始化(在调用 open() 之前)
1 正在加载。请求已提出(调用 send() 之前)
2 已加载。请求已发送(这里通常可以从响应得到内容头部)
3 交互中。请求处理中(响应中通常有部分数据可用,但是服务器还没有完成响应)
4 完成。请求已完成(可以访问服务器响应并使用它)

我们要向这个 onreadystatechange 函数添加一条 If 语句,来测试我们的响应是否已完成(意味着可获得数据):

xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
//从服务器的response获得数据
}
}
  1. responseText属性:该属性用来取回由服务器返回的数据。
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
document.myForm.time.value = xmlHttp.responseText;
}
}
  1. 其他属性。

(5)xmlhttprequst的方法

  1. open()方法:open() 有三个参数。第一个参数定义发送请求所使用的方法,第二个参数规定服务器端脚本的URL,第三个参数规定应当对请求进行异步地处理。
    xmlHttp.open("GET","test.php",true);
  2. send()方法:send() 方法将请求送往服务器。如果我们假设 HTML 文件和 PHP 文件位于相同的目录,那么代码是这样的:
    xmlHttp.send(null);
  3. 其他方法。

(6)Ajax编程步骤

  1. 创建XMLHttpRequest对象。
  2. 设置请求方式。
  3. 调用回调函数。
  4. 发送请求。
  1. 创建XMLHttpRequest对象。
    创建XMLHttp对象语法:var xmlHttp=new XMLHttpRequest();
    如果是IE5或者IE6浏览器,则使用ActiveX对象,创建方法:
    var xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
    一般我们手写AJAX的时候,首先要判断该浏览器是否支持XMLHttpRequest对象,如果支持则创建该对象,如果不支持则创建ActiveX对象。JS代码如下:
//第一步:创建XMLHttpRequest对象

var xmlHttp;
if (window.XMLHttpRequest) { //非IE
xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) { //IE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
}
  1. 设置请求方式。
    在web开发中,请求有get和post两种,区别如下。这是W3C的解释。
    注意:GET主要用于查询,PUT、POST、DELETE用于修改。
    GET & POST
//第二步:设置和服务器端交互的相应参数,向路径http://localhost:8080/JsLearning3/getAjax准备发送数据

var url = "http://localhost:8080/JsLearning3/getAjax";
xmlHttp.open("POST", url, true);
  1. 调用回调函数。
    回调函数就是上述属性onreadystatechange属性,并用此创建一个匿名方法。
//第三步:注册回调函数

xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var obj = document.getElementById(id);
obj.innerHTML = xmlHttp.responseText;
} else {
alert("AJAX服务器返回错误!");
}
}
}

xmlHttp.status是服务器返回的结果,其中200代表正确。404代表未找到页面,所以这里我们判断只有当xmlHttp.status等于200的时候才可以继续执行。
AJAX状态码说明:
    1–:请求收到,继续处理
    2–:操作成功收到,分析、接受
    3–:完成此请求必须进一步处理
    4–:请求包含一个错误语法或不能完成
    5–:服务器执行一个完全有效请求失败

  1. 发送请求。
    如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头。然后在 send() 方法中规定您希望发送的数据。
//第四步:设置发送请求的内容和发送报送。然后发送请求

var params = "userName=" + document.getElementsByName("userName")[0].value + "&userPass=" + document.getElementsByName("userPass")[0].value + "&time=" + Math.random(); // 增加time随机参数,防止读取缓存
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8"); // 向请求添加 HTTP 头,POST如果有数据一定加加!!!!
xmlHttp.send(params);

第八章 充实文档的内容


思路:

  1. 获取元素集合;
  2. 遍历集合,获取元素特定属性或子元素;
  3. 将各类数据存储在数组里;
  4. 创建标记;
  5. 为标记增添上述获取内容;
  6. 将标记添加到文档。

主要充实内容:

  • 显示“缩略语列表”:
    <abbr>标签和定义列表(<dl>)由一系列“定义标题”(<dt>)和相应的“定义描述”(<dd>)构成。
  • 显示“文献来源链接表”:
    <blockquote cite="http://baidu.com">获取其中的cite属性。
  • 显示“快捷键清单”:
    属性accesskey,不同值对应不同的快捷键。如:<a href="index.html" accesskey="1">Home</a>
  • 检索和添加信息。

第九章 CSS-DOM


9.2 style属性

  • 当需要引用一个中间带减号的CSS属性时,DOM要求你用驼峰式命名法。如:CSS属性font-family变为DOM属性fontFamily。element.style.fontFamily
    注意:通过style属性获取样式有很大的局限性。style属性只能返回内嵌样式。换句话说,只有把 CSS style属性插入到标记里,才可以用 DOM style属性去查询那些信息。
  • style对象的属性值永远是一个字符串,它必须放在引号里,单引号或双引号均可。para.style.color='black'
    注意:如果忘记使用引号,JavaScript会把等号右边的值解释为一个变量。且如果前面未定义变量名,搞语句将无法工作。

9.3 何时该使用DOM脚本设置样式

  • 为什么这么做:
    其一,CSS无法让我们找到想要处理的目标元素;
    其二,是用CSS寻找目标元素的办法还未得到广泛的支持。
  • 根据元素在节点树里的位置来设置样式。通过CSS声明样式的具体做法主要有三种。
    1. 标签元素。p{font-size:1em;}
    2. 为有特定class属性的所有元素统一声明样式。.fineprint{font-size:1em;}
    3. 为有独一无二的id属性的元素单独声明样式。#intro{font-size:1em}
    4. 也可以为有类似属性的多个元素声明样式。input[type*="text"]{font-size:1em}
    5. 在现代浏览器中,甚至可以根据元素的为hi声明样式。p:first-of-tye{font-size:1em}
      注:CSS2引入了很多与位置相关的选择器,如::first-child 和 :last-child ,而CSS3则定义了诸如 :nth-child() 和 :nth-of-type() 之类的位置选择器。

第十章 用JavaScript实现动画效果


10.1 动画基础知识

  • setTimeout函数的第一个参数为字符串,记住!movement=setTimeout("moveMessage(),10");
  • 关于对var repeat = “moveElement(‘“+elementID+”‘,”+final_x+”,”+final_y+”,”+interval+”)”;的理解:(这里还是理解得不是很清楚)
function moveElement(elementID,final_x,final_y,interval) {
if (!document.getElementById) return false;
if (!document.getElementById(elementID)) return false;
var elem = document.getElementById(elementID);
var xpos = parseInt(elem.style.left);
var ypos = parseInt(elem.style.top);
if (xpos == final_x && ypos == final_y) {
return true;
}
if (xpos < final_x) {
xpos++;
}
if (xpos > final_x) {
xpos--;
}
if (ypos < final_y) {
ypos++;
}
if (ypos > final_y) {
ypos--;
}
elem.style.left = xpos + "px";
elem.style.top = ypos + "px";
var repeat = "moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
movement = setTimeout(repeat,interval);
}
  1. 计时器第一个参数尽量不要用字符串,而是匿名函数(需要传入参数)或者直接要执行的函数名称(对于不需要参数的),字符串是用eval执行的,存在xss漏洞并且效率低。
  2. setTimeout第一个参数如果是字符串,那么如果你传递的是变量,就是var repeat = “moveElement(elementID,final_x,final_y,interval)你这种形式,那么变量必须要是window作用域下的(虽然eval执行,但是需要变量是wiindow作用域下的,这个和eval有区别,是当前作用域内的变量可以访问到),访问不到此时传入的参数,会报错。
  3. “+value+”为传递变量如果没有++就是传递字符串了,两个加号之间的变量可以解析,由于elementID是字符串,必须要变为引号括起。

参考链接:关于dom编程艺术动画部分一句代码的解释问题https://blog.csdn.net/qq_39148344/article/details/83350911https://blog.csdn.net/ysc612/article/details/48766875

10.2 实用的动画

  • 为了消除动画的滞后现象,可以用 clearTimeout 函数清除积累在 setTimeout 队列里的事件。clearTimeout(movement);
  • 为了进行判断是否执行 clearTimeout 函数,可将movement设置为元素的一个属性。

第十一章 HTML5


推荐工具:Modernizr
注:该工具能提供一些不同的CSS类名以及特性检测属性。引用该脚本是,需要将其置于<head>标签中。

11.3.2 音频和视频

  • 为了确保HTML5的最大兼容性,至少要包含一列三个版本:
    • 基于H.264和ACC的MP4;
    • WebM(VP8+Vorbis);
    • 基于Theora视频和Vorbis音频的Ogg文件。

11.4 HTML5其他特性

第十二章 综合实例


案例链接:https://loaln.github.io/WebFont-end_Practice/html/20190724/index.html

附录 JavaScript库


A.1 选择合适的库

  • 它具备你需要的所有功能吗?
  • 它的功能是否比你想要的还多?
  • 它是模块化吗?
  • 它的支持情况怎么样?
  • 它有文档吗?
  • 他的许可合适吗?

A.1.1 有代表性的库

A.3.1

不同库对下述选择器的支持情况各不相同,注意查阅相应库的文档了解详细用法。

  • 除了使用ID、类名和标签以为,在多数库中都可以使用的高级的选择器:
    $('*') ,
    $('tag') ,
    $('tagA tagB') ,
    $('tagA,tagB,tagC') ,
    $('#id')$('tag#id') ,
    $('.className')$('tag.className').
  • 使用组合选择器,用空格隔开:$('#myList li') , $('ul li a.selectMe')等。
  • jQurey还支持下列 CSS 2.1 属性选择器:$('tag[attr]')……
  • 使用子选择器或同辈选择器:$('tagA>tagB') , $('tagA+tagB') , $('tagA~tagB') .
  • 使用一些伪类和伪元素选择器:$('tag:root')……

A.7 动画和效果

文章作者:Loaln
文章链接:https://loaln.github.io/2019/07/09/web-note-1/
版权声明:本文由Loaln原创,采用署名-非商业性使用-相同方式共享(CC BY-NC-SA)4.0 国际许可协议
转载请保留原文链接及作者。