美文网首页
《JavaScript DOM编程艺术》笔记

《JavaScript DOM编程艺术》笔记

作者: 柠檬果然酸 | 来源:发表于2018-11-13 17:27 被阅读0次

做笔记是一个好习惯,做笔记不等于抄书,书上的内容不是一眼就能够看懂的,我们需要将书上的内容做一个“翻译”,翻译成自己一眼就能够读懂的文字。

P23

==与===的区别

var a = false;
var b = '';
a == b;//结果为true
a === b;//结果为false

区别:== 只进行值的比较,而 === 除了判断值相等,还会判断类型是否相等。这里flase和''具有相同的含义,但是它们类型不同,一个是boolean一个是String。

:!= 与 !== 同理

P28

规范:变量用下划线分割各个单词,函数用驼峰命名法。这样便于一眼看出哪些是变量哪些是函数。

变量作用域:在函数内部,用var声明的变量是局部变量,反之则是全局变量。

function square(num) {
  total = num * num;
  return total;
}

var total = 50;
var number = square(20);
alert(total);//答案是400

P42

自己实现一个 getElementsByClassName 方法

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Shopping list</title>
    </head>
    <body>
        <h1>What to buy</h1>
        <p title="a gentle reminder">Don't forget to buy this stuff.</p>
        <ul id="purchases">
            <li>A tin of beans</li>
            <li class="sale">Cheese</li>
            <li class="sale important">Milk</li>
        </ul>
        <script>
            function getElementByClassName(node, classname) {
                var results = new Array();
                var elems = node.getElementsByTagName("*");
                for (var i = 0; i < elems.length; i++) {
                    if (elems[i].className.indexOf(classname) != -1) {
                        results[results.length] = elems[i];
                    }
                }
                
                return results;
            }
            
            var saleList = getElementByClassName(document, 'sale');
        </script>
    </body>
</html>

P51

事件处理函数的工作机制:给某个a标签添加onclick事件,onclick双引号里面的js代码返回true或false,如果返回的是true,那么onclick事件处理函数就会认为这个链接被点击了;反之,如果返回false,onclick事件处理函数就会认为这个链接没被点击。

可以通过下面的代码去验证这一结论:

<a href="http://www.baidu.com" onclick="return false;">Click me</a>

踩坑

<a href="http://baidu.com" onclick="show()">百度</a>
<script>
function show() {
    alert("我没跳转");
    return false;
}
</script>

执行完以上代码你会深刻领悟到js 的坑。
首先你要知道 当 onclick 后面的事件不是一个函数名时,它会被包裹到一个匿名函数中执行。
以上就相当于是

obj.onclick = function() {show();}

当点击链接的时候执行 onclick 里面的代码,而不是把show()当作事件处理程序,return false 只是在 show() 这个函数中返回了并没有在 onclick 事件中返回。

因此还会发生跳转

重点在这里:在事件处理函数的工作机制中,当在给某元素添加事件处理函数后,一旦事件发生,相应JavaScript代码就会执行,所调用的JavaScript代码的返回值被传递给事件处理函数。当我们给a标签添加onclick事件处理函数并点击a触发其后,如果相应JavaScript代码返回true,onclick事件处理函数就会认为这个链接被点击了,同样的若返回false即会认为链接未被点击。

所以 可以这样写

<a href="http://www.baidu.com" onclick="myjs(); return false;">百度 </a>
<a href="http://www.baidu.com" onclick="return false;">百度</a>

P70

对象检测:检测浏览器是否支持某个方法。

if (!getElementById || !getElementsByTagName) return false;

备注:对象检测是用来向下兼容浏览器的,由于我只是单纯的学习js,所以没必要考虑兼容性的问题。

P72

尽量少访问DOM
只要是查询DOM中的某些元素,浏览器都会搜索整个DOM树。

尽量减少文档中的标记数量
过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树的时间。

P73

合并js脚本
尽量把多个js脚本合并成一个,这样可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。

<script>标签放置位置
一般是放在文档末尾,这样能够保证页面加载完毕后才开始下载脚本文件,网页的流畅度大大提升。

压缩脚本
把脚本中不必要的字节如空格和注释之类的统统删掉,缩减文本的大小。
有的精简程序甚至会重写你的部分代码,使用更短的变量名,从而减少整体文件大小。如

function showPic(whichpic) {
    //取得图片的href属性
    var source = whichpic.getAttribute('href');
    //取得占位符
    var placeholder = document.getElementById('placeholder');
    //更新占位符
    placeholder.setAttribute('src', source);
    //使用图像的title属性更新文本描述
    var text = whichpic.getAttribute('title');
    var description = document.getElementById('description');
}

压缩之后的代码会变成下面这样

function showPic(a) {var b = a.getAttribute('href');document.getElementById('placeholder').setAttribute('src', b);a.getAttribute('title');document.getElementById('description');}

压缩代码工具
Douglas Crockford 的 JSMin
雅虎的 YUI Compressor
谷歌的 Closure Compiler

P79

原则:如果想用JavaScript给某个网页添加一些行为,就不应该让JavaScript代码对这个网页结构有任何依赖。
笔记:低耦合带来的好处是代码的适用性大大提高。

结构化程序设计中的一条原则:函数应该只有一个入口和出口。
但是不要过分拘泥于这项原则,否则的话代码会变得难以阅读。

P82

改良后的图片库

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <h1>Snapshots</h1>
    <ul id="imagegallery" placeholder="placeholder">
        <li>
            <a href="images/fireworks.jpg" title="A fireworks display">Fireworks</a>
        </li>
        <li>
            <a href="images/coffee.jpg" title="A cup of black coffee">Coffee</a>
        </li>
        <li>
            <a href="images/rose.jpg" title="A red, red rose">Rose</a>
        </li>
        <li>
            <a href="imagess/bigben.jpg" title="The famous clock">Big Ben</a>
        </li>
    </ul>
    <img id="placeholder" src="images/placeholder.gif" alt="my image gallery"/>
    <script>
        function prepareGallery() {
            if (!document.getElementsByTagName) return false;
            if (!document.getElementById) return false;
            if (!document.getElementById('imagegallery')) return false;

            var gallery = document.getElementById('imagegallery');
            //获取 gallery 关联的 placeholder
            var placeholder = document.getElementById(gallery.getAttribute('placeholder'));
            var links = gallery.getElementsByTagName('a');

            for (var i = 0; i < links.length; i++) {
                links[i].onclick = function () {
                    showPic(this, placeholder);
                    return false;
                }
            }
        }

        function showPic(whichpic, placeholder) {
            var source = whichpic.getAttribute('href');
            placeholder.setAttribute('src', source);
        }
        
        prepareGallery();
    </script>
</body>
</html>

用法:在<ul>标签上添加id="imagegallery",然后再调用prepareGallery()就将图片库初始化成功。

属性
placeholder 指定图片展示的位置

P82

网页加载完毕的时候执行某个函数

window.onload = prepareGallery;

执行多条函数

window.onload = function () {
    firstFunction();
    secondFunction();
}

这里还有一个弹性最佳的解决方案——不管你打算在页面加载完毕时执行多少个函数,它都可以应付自如。

function addLoadEvent(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function () {
            oldonload();
            func();
        };
    }
}

如果这个处理函数上还没有绑定任何函数,就像平时那样把新函数添加给它。
如果这个处理函数上已经绑定了函数,就把新函数追加到现有指令的末尾。

补充

typeof:运算符把类型信息当作字符串返回。

下表总结了 typeof 可能的返回值

类型 结果
Undefined 'undefined'
Null 'object'
Boolean 'boolean'
Number 'number'
String 'string'
Symbol (ECMAScript 6 新增) 'symbol'
宿主对象(由JS环境提供) Implementation-dependent
函数对象 'function'
任何其他对象 'object'

示例

// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
typeof Number(1) === 'number'; // 但不要使用这种形式!

// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof总是返回一个字符串
typeof String("abc") === 'string'; // 但不要使用这种形式!

// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!

// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';

// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined'; 

// Objects
typeof {a:1} === 'object';

// 使用Array.isArray 或者 Object.prototype.toString.call
// 区分数组,普通对象
typeof [1, 2, 4] === 'object';

typeof new Date() === 'object';

// 下面的容易令人迷惑,不要使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String("abc") === 'object';

// 函数
typeof function(){} === 'function';
typeof class C{} === 'function'
typeof Math.sin === 'function';
typeof new Function() === 'function';

null

typeof null === 'object'; // 从一开始出现JavaScript就是这样的

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签也成为了 0,typeof null 就错误的返回了'object'

以上内容从此处摘抄

判断一个变量是否存在

这得说一下变量的几种状态(变量的生命周期?)

a; // 未声明
var b; // 声明但未赋值(类型为 undefined)
var c = null; // 赋值(虽然这个值是 null,但其类型为 object)

用 if 语句判断变量是否存在

if(!a){
    alert("通过")
}
if(!b){
    alert("通过")
}
if(!c){
    alert("通过")
}

第一个直接报错,第二、三个都会弹出“通过”,所以 undefinednull 在 if 语句中,都会转换为 false。如果将判断的条件换成一下这样

if(typeof a != 'undefined'){
    alert("通过")
}
if(typeof b != 'undefined'){
    alert("通过")
}
if(typeof c != 'undefined'){
    alert("通过")
}

结果只有第三个弹出“通过”,结论就是 nullundefined 值相同但类型不相同。

null == undefined // true
null === undefined // false

P93

  • getElementById
  • getElementsByTagName
  • getAttribute
  • setAttribute

这些方法都是 DOM Core 的组成部分。它们并不专属于 JavaScript。它们可以用来处理任何一种标记语言(比如 XML)编写的文档。

P108

在已有的元素前插入一个新元素
parentElement.insertBefore(newElement, targetElement);
我们不必搞清楚父元素到底是哪个,因为 targetElement 元素的 parentNode 属性值就是它。

var gallery = document.getElementById('imagegallery');
gallery.parentNode.insertBefore(placeholder, gallery);

将 placeholder 元素插入到 gallery 元素之前

在已有的元素后插入一个新元素
没有 insertAfter() 这个方法,我们得自己写一个

function insertAfter(newElement, targetElement) {
    var parent = targetElement.parentNode;
    if (parent.lastChild == targetElement) {
        parent.appendChild(newElement);
    } else {
        parent.insertBefore(newElement, targetElement.nextSibling);
    }
}

P115

XMLHttpRequest对象:Ajax技术的核心。这个对象充当浏览器中的客户端与服务器之间的中间人角色。以往的请求都由浏览器发出,而JavaScript通过这个对象可以自己发送请求,同时也自己处理响应。

创建 XMLHttpRequest 对象

IE浏览器(而且不同的版本创建方式也不同)
var request = new ActiveXObject('Msxml2.XMLHTTP.3.0');
其他浏览器
var request = new XMLHttpRequest();

为了兼容所有浏览器,我们需要一个脚本

function getHTTPObject() {
    if (typeof XMLHttpRequest == 'undefined') { // IE浏览器
        XMLHttpRequest = function() {
            try {
                return new ActiveXObject('Msxml2.XMLHTTP.6.0');
            } catch (e) {
            }
            try {
                return new ActiveXObject('Msxml2.XMLHTTP.3.0');
            } catch (e) {
            }
            try {
                return new ActiveXObject('Msxml2.XMLHTTP');
            } catch (e) {
            }
            return false;
        }
    }
    return new XMLHttpRequest();
}

XMLHttpRequest 对象中有许多方法。其中最有用的是 open 方法。

open(method, url, async)
作用:初始化 HTTP 请求参数。
method:指定请求类型,如GET、POST 或 SEND。
url:请求路径。
async:是否异步方式发送和请求。

通过 Ajax 请求本地文件 example.txt

function getNewContent() {
    var request = getHTTPObject();
    if (request) {
        request.open('GET', 'example.txt', true);
        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                var para = document.createElement('p');
                var txt = document.createTextNode(request.responseText);
                para.appendChild(txt);
                document.getElementById('new').appendChild(para);
            }
        };
        request.send(null);
    } else {
        alert('Sorry, your browser doesn\'t support XMLHttpRequest');
    }
}

onreadystatechange 是一个事件处理函数,它会在服务器给 XMLHttpRequest 对象送回响应的时候被触发执行。

我们给它指定了一个处理函数:
request.onreadystatechange = doSomething

注意:在为 onreadystatechange 指定函数引用时,不要在函数名后面加括号。因为加括号标识立即调用函数,并且把函数执行结果赋值给 onreadystatechange,而我们在此只想把函数自生的引用(而不是函数结果)赋值给 onreadystatechange 属性。

只要 readyState 属性的值变成了4,就可以访问服务器发送回来的数据了。

访问服务器发送回来的数据:
responseText 保存文本字符串形式的数据
responseXML 保存 Content-Type 头部中指定为"text/xml"的数据,其实是一个 DocumentFragment 对象。

注意:在使用 Ajax 时,千万要注意同源策略。使用 XMLHttpRequest 对象发送的请求只能访问与其所在的 HTML 处于同一个域中的数据,不能向其他域发送请求。还有在谷歌浏览器中使用 Ajax 请求 file:// 协议的文件会报 Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https. 的错误消息,只需右键谷歌浏览器的快捷图标,然后点击属性并且在目标后面添加 --allow-file-access-from-files 就能够解决问题。

补充

XMLHttpRequest.send()
该方法的作用是发送 HTTP 请求。

一般情况下,使用 Ajax 提交的参数多是些简单的字符串,可以直接使用 GET 方法将要提交的参数写到 open 方法的url参数中,此时send方法的参数为null。如:

request.open('GET', 'login.jsp?user=XXX&pwd=XXX', true);
request.send(null);

此外,也可以使用 send 方法传递参数。使用 send 方法传递参数使用的是 POST 方法,需要设定 Content-Type 头信息,模拟 HTTP POST 方法发送一个表单,这样服务器才会知道如何处理上传的内容。参数的提交格式和 GET 方法中 url 的写法一样。设置头信息前必须先调用 open 方法。

request.open('POST', 'login.jsp', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
request.send('user=' + username + '&pwd=' + password);

readyState 状态说明
(0)未初始化
此阶段确认 XMLHttpRequest 对象是否创建,并为调用 open() 方法进行未初始化作好准备。值为0表示对象已经存在,否则浏览器会报错--对象不存在。
(1)载入
此阶段对 XMLHttpRequest 对象进行初始化,即调用 open() 方法,根据参数(method,url,true)完成对象状态的设置。并调用 send() 方法开始向服务端发送请求。值为1表示正在向服务端发送请求。
(2)载入完成
此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示已经接收完全部响应数据。并为下一阶段对数据解析作好准备。
(3)交互
此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的 MIME 类型把数据转换成能通过 responseBody 、responseText 或 responseXML 属性存取的格式,为在客户端调用作好准备。状态3表示正在解析数据。
(4)完成
此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过 XMLHttpRequest 对象的相应属性取得数据。

概而括之,整个 XMLHttpRequest 对象的生命周期应该包含如下阶段:
创建-初始化请求-发送请求-接收数据-解析数据-完成

简化版的 readyState 状态说明
(0)未初始化:XMLHttpRequest 对象已经创建,但还没有调用 open() 方法。
(1)载入:已经调用 open() 方法,但尚未调用 send() 方法。
(2)载入完成:send() 方法已调用。
(3)交互:服务器正在发送响应。
(4)完成:服务器完成发送响应。

DocumentFragment 节点
DocumentFragment 节点不属于文档树。
当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。

P159

获取下一个元素节点

function getNextElement(node) {
    if (!node.nextSibling) return null;
    if (node.nextSibling.nodeType == 1) return node.nextSibling;

    return getNextElement(node.nextSibling);
}

P168

添加 class 属性

function addClass(element, value) {
    if (!element.className) {
        element.className = value;
    } else {
        newClassName = element.className;
        newClassName += ' ';
        newClassName += value;
        element.className = newClassName;
    }
}

P203

Modernizr
一个开源的 JavaScript 库。Modernizr 不会给你添加浏览器不支持的特性。

P206

实现当鼠标移到图片上时恢复彩色,鼠标离开图片时变为灰色的效果

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <img id="avatar" title="Jeffrey Sambells" alt="My Avatar" src="images/avatar.png"/>
    <script>
        function convertToGS(img) {
            // 存储原始的彩色版
            img.color = img.src;
            //创建灰度版
            img.grayscale = createGSCanvas(img);
            
            img.onmouseover = function() {
                this.src = this.color;
            }
            
            img.onmouseout = function() {
                this.src = this.grayscale;
            }
            
            img.onmouseout();
        }
        
        function createGSCanvas(img) {
            var canvas = document.createElement('canvas');
            canvas.width = img.width;
            canvas.height = img.height;
            
            var ctx =canvas.getContext('2d');
            ctx.drawImage(img, 0, 0);
            
            var c = ctx.getImageData(0, 0, img.width, img.height);
            for (i = 0; i < c.height; i++) {
                for (j = 0; j < c.width; j++) {
                    var x = (i * 4) * c.width + (j * 4);
                    var r = c.data[x];
                    var g = c.data[x+1];
                    var b = c.data[x+2];
                    c.data[x] = c.data[x+1] = c.data[x+2] = (r + g + b) / 3;
                }
            }
            
            ctx.putImageData(c, 0, 0, 0, 0, c.width, c.height);
            
            return canvas.toDataURL();
        }
        
        window.onload = function() {
            convertToGS(document.getElementById('avatar'));
        }
    </script>
</body>
</html>

P210

在每个影片容器中,音频和视频轨道都使用不同的编解码器来编码。编解码器决定了浏览器在播放时应该如何解码音频和视频。编解码器的核心就是一个算法,用于压缩和存储视频,以减少原始文件的大小,同时可能会也可能不会损失品质。

P212

用 html5 在页面上制作一个视频播放器

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>My Video</title>
    <style>
        .video-wrapper {
            overflow: hidden;
        }
        
        .video-wrapper .controls {
            position: absolute;
            height: 30px;
            width: 30px;
            margin: auto;
            background: rgba(0, 0, 0, 0.5);
        }
        
        .video-wrapper button {
            display: block;
            width: 100%;
            height: 100%;
            border: 0;
            cursor: pointer;
            font-size: 17px;
            color: #fff;
            background: transparent;
        }
        
        .video-wrapper button[paused] {
            font-size: 12px;
        }
    </style>
</head>
<body>
    <div class="video-wrapper">
        <video id="movie" controls>
            <source src="108478173_b67d02eae28fad85c96c5a38e460a847_1aeb3523af66_2.mp4"/>
            <!--
            <source src="movie.webm" type="video/webm; codecs='vp8, vorbis'"/>
            <source src="movie.ogv" type="video/ogg; codecs='theora, vorbis'"/>
            -->
            <p>
                Download movie as
                <a href="108478173_b67d02eae28fad85c96c5a38e460a847_1aeb3523af66_2.mp4">MP4</a>,
                <!--
                <a href="movie.webm">WebM</a>,
                or
                <a href="movie.ogv">Ogg</a>.
                -->
            </p>
        </video>
    </div>
    
    <script>
        function createVideoControls() {
            var vids = document.getElementsByTagName('video');
            for (var i = 0; i < vids.length; i++) {
                addControls(vids[i]);
            }
        }
        
        function addControls(vid) {
            vid.removeAttribute('controls');
            
            vid.height = vid.videoHeight;
            vid.width = vid.videoWidth;
            vid.parentNode.style.height = vid.videoHeight + 'px';
            vid.parentNode.style.width = vid.videoWidth + 'px';
            
            var controls = document.createElement('div');
            controls.setAttribute('class', 'controls');
            
            var play = document.createElement('button');
            play.setAttribute('title', 'Play');
            play.innerHTML = '&#x25BA';
            
            controls.appendChild(play);
            
            vid.parentNode.insertBefore(controls, vid);
            
            play.onClick = function() {
                if (vid.ended) {
                    vid.currentTime = 0;
                }
                if (vid.paused) {
                    vid.play();
                } else {
                    vid.pause();
                }
            }
            
            vid.addEventListener('play', function() {
                play.innerHTML = '&#x2590;&#2590;';
                play.setAttribute('paused', true);
            }, false);
            
            vid.addEventListener('pause', function() {
                play.innerHTML = '&#x25BA;';
                play.removeAttribute('paused');
            }, false);
            
            vid.addEventListener('ended', function() {
                vid.pause();
            }, false);
        }
        
        
        window.onload = function() {
            createVideoControls();
        }
    </script>
</body>
</html>

P217

检查浏览器是否支持某个输入类型的控件

function inputSupportsType(type) {
    if (!document.createElement) return false;
    
    var input = document.createElement('input');
    input.setAttribute('type', type);
    if (input.type == 'text' && type != 'text') {
        return false;
    } else {
        return true;
    }
}

P218

检查某元素是否有某属性

function elementSupportsAttribute(elementName, attribute) {
    if (!document.createElement) return false;
    
    var elem = document.createElement(elementName);
    return ( attribute in elem );
}

如果浏览器不支持 placeholder 属性

if (!elementSupportsAttribute('input', 'placeholder')) {
    var input = document.getElementById('first-name');
    
    input.onfocus = function() {
        var text = this.placeholder || this.getAttribute('placeholder');
        if (this.value == text) {
            this.value = '';
        }
    }
    
    input.onblur = function() {
        if (this.value == '') {
            this.value = this.placeholder || this.getAttribute('placeholder');;
        }
    }
    
    input.onblur();
}

P268

内容分发网络
对于库来说,如果有很多站点要使用同一个库,那么最好是把这个库托管到一个公共服务器上,以便所有站点共享和访问。这样,当用户从一个站点跳到另一个站点时,他们就不用再重复下载相同的文件了。

内容分发网络(CDN, Content Delevery Network)可以解决分布共享库的问题。CDN 就是一个由服务器构成的网络,这个网络的用途就是分散存储一些公共的内容。CDN 中的每台服务器都包含库的一份副本,这些服务器分布在世界上不同的国家和地区,以便达到利用带宽和加快下载的目的。浏览器访问库的时候使用一个公共的 URL,而 CDN 的底层则通过地理位置最近、速度最快的服务器提供相应的文件。

总结

这本书到尾声了,这是我看的第一本真正意义上的 JavaScript 书籍。我最初学习 js 的时候看的那些教材只是简单的讲解了一些 js 的语法,没有什么深度。虽然这本书中提到知识点不多,但是却讲了一些使用 JavaScript 时的良好的规范,这些都是编程里最重要的东西。好像有句话叫“代码规范是编程思想的体现”来着,具体在哪看到的我忘了。

平稳退化
这本书提到的一个非常重要的规范,就是在浏览器不支持 JavaScript 的情况下保证页面能够正常运行而不至于崩掉。虽然现在的浏览器对 js 的支持都非常的棒,但是万一用户禁用了 JavaScript,那么页面会发生什么我也不知道,因为我从来没有禁用过 JavaScript。我之前写的 js 代码能够实现一些炫酷的效果,但是我从来都没有校验过浏览器是否支持那些方法,因为它们在我的浏览器上都能正常的运行-_-||。我以前还为那些炫酷的效果洋洋自得,现在看来这些都是些糟糕的代码。我个人觉得要做到平稳退化还是挺难的,脱离了 JavaScript 的页面岂不是变得很单调。

渐进增强
在浏览器不支持 JavaScript 的情况下要保证网页的基本功能不受影响,然后再在这个基础上使用 JavaScript 来增强交互性。如果你的网页一开始就是基于 JavaScript 构建的,那这不是一个好的网页结构。

总之,养成良好的编码规范会使人终生受益。

相关文章

网友评论

      本文标题:《JavaScript DOM编程艺术》笔记

      本文链接:https://www.haomeiwen.com/subject/qkjltqtx.html