第11章 客户端JavaScript实践
绩效
章节 | 代码量(行) |
---|---|
11.1 | 303 |
11.1 样式
对样式进行操作指的是对页面的外观进行操作,而不是页面的内容。只要设计出合适的样式,就能够创建出易读、清晰、美观的 Web 应用程序。话虽如此,易读和美观主要由设计师负责,属于静态设计的范畴,需要 CSS 方面的知识。而借助 JavaScript,则能够动态地变更样式,增强页面的可读性。
JavaScript 实现了动态样式变更,其目的是为用户提供视觉反馈。例如,针对可被点击的元素,如果在鼠标指针移动至该元素上方时改变其图标,并改变 DOM 元素的颜色,就能够向用户传达该元素可被点击的信息。当鼠标指针位于 DOM 元素之上时,将触发 mouseover 事件。只需准备一个能够改变鼠标指针以及 DOM 元素色彩的事件侦听器,并将其注册至该事件,就能够实现这一效果。
11.1.1 样式的变更方法
可以通过以下这些方法对样式进行变更。
- 通过 className 属性更改 class 名
- 通过 classList 属性更改 class 名
- 更改 style 属性
- 直接更改样式表
以上任意一种方法都能够实现样式的变更。根据不同的用途选择合适的方法即可。
通过 className 属性更改 class 名
通过更改 DOM 元素的 class 名来改变样式是一种最为简单的做法。即事先通过 CSS 定义好对应于更改前与更改好的 class 名的样式,并在JavaScript 中替换 class 名。可以通过 className 属性设定 class 名,如代码清单 11.1 所示。在这个例子中,当点击时,字符的颜色与背景色将会调换。
代码清单 11.1 通过 className 属性更改 class 名
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>通过 className 属性更改 class 名</title> <style> .hzh1 { color: red; } .hzh2 { color: orange; } .hzh3 { color: yellow; } .hzh4 { color: green; } .hzh5 { color: cyan; } .hzh6 { color: purple; } .hzh7 { color: blue; } .hzh8 { color: limegreen; } .hzh9 { color: palevioletred; } .hzh0 { color: dodgerblue; } </style> </head> <body> <h1 id="hzh" class="hzh1">点击这个会切换文字颜色</h1> <script> var hzh = document.getElementById('hzh'); hzh.onclick = function huangzihan() { this.className = ("hzh" + Math.floor(Math.random()*10)) console.log("在控制台输出目前的类名:"); console.log("hzh" + Math.floor(Math.random()*10)); } </script> </body> </html>
在更改 class 名时应该注意并清楚了解的是,如果更改了 class 名,到底有哪些元素将会受到影响。例如对于代码清单 11.2 的情况,如果更改了 1 个元素的 class 名,其相邻元素与子孙元素的样式也会一起改变。这时,如果需要改变的元素过多,则可能出现性能上的问题。不过,如果要考虑性能的话,指定了相邻元素与子元素的CSS 的写法本身就是有问题的。最好对这些元素分别设定不同的 class 名并进行式样操作。
代码清单 11.2 在更改 class 名后相关元素的样式也会改变
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>在更改 class 名后相关元素的样式也会改变</title> <style> .hzh-before { background-color: white; color: black; } .hzh-before p { text-decoration: none; } .hzh-before + div { text-decoration: none; } .hzh-after { background-color: black; color: white; } .hzh-after p { text-decoration: underline; } .hzh-after + div { text-decoration: line-through; } </style> </head> <body> <div id="hzh" class="hzh-before"> <p>hzh1</p> <p>hzh2</p> <p>hzh3</p> <p>hzh4</p> </div> <div> 黄子涵 </div> <script> var hzh = document.getElementById('hzh'); hzh.onclick = function toggleStyle() { this.className = (this.className === 'hzh-before') ? 'hzh-after' : 'hzh-before'; }; </script> </body> </html>
通过 classList 属性更改 class 名
还可以通过对在 HTML5 中新增的 classList 属性进行操作,来更改 class 名。与通过对 className 属性进行操作以更改 class 名相比,这种方法更加容易理解(代码清单 11.3)
代码清单 11.3 在更改 class 名后相关元素的样式也会改变
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>在更改 class 名后相关元素的样式也会改变</title> <style> .hzh-before { background-color: white; color: black; } .hzh-before p { text-decoration: none; } .hzh-before + div { text-decoration: none; } .hzh-after { background-color: black; color: white; } .hzh-after p { text-decoration: underline; } .hzh-after + div { text-decoration: line-through; } </style> </head> <body> <div id="hzh" class="hzh-before"> <p>hzh1</p> <p>hzh2</p> <p>hzh3</p> <p>hzh4</p> </div> <div> 黄子涵 </div> <script> var hzh = document.getElementById('hzh'); hzh.onclick = function toggleStyle() { this.classList.toggle('hzh-before'); this.classList.toggle('hzh-after'); }; </script> </body> </html>
表 11.1 总结了可以使用 classList 属性的方法。classList 属性是一种对 DOM TokenList 接口的实现。
表 11.1 可以使用 classList 属性的方法
方法名 | 说明 |
---|---|
contains(clazz) | 判断在 class 名中是否含有 clazz |
add(clazz) | 向 class 名中添加 clazz |
remove(clazz) | 从 class 名中删除 clazz |
toggle(clazz) | 如果在 class 名中含有 clazz 则将它删除,否则向 class 名中添加 clazz |
更改 style 属性
可以直接更改 DOM 元素的 style 属性的值以实现样式的更改。这与更改 class 名的情况不同,样式更改的范围被明确地限定于这个元素。另外,通过 style 属性指定的内容的应用优先级将仅次于 CSS 中被标记为 !important 的元素。
style 属性中的各个属性名是由在 CSS 中所指定的属性名演变而来的,其更改之处为去除了属性名中的连字符(-)并将连字符之后的字母改为了大写形式。例如,对于 CSS 中的 margin-top 属性,在 JavaScript 中则可以通过 marginTop 的名称使用。之所以要将连字符去除,是因为连字符在 JavaScript 将被识别为减号。此外,由于 float 在 JavaScript 中是作为保留字使用的,因此 float 属性不能直接使用。如果要在 JavaScript 中更改 float 属性,则需要通过 cssFloat 属性来进行操作。
在代码清单 11.4 中是一个更改 style 属性更改的例子。
代码清单 11.4 更改 style 属性
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>更改style属性</title> <style> #hzh { background-color: white; color: black; } </style> </head> <body> <div id="hzh">黄子涵。请点击这里。</div> <div id="huangzihan">黄子涵是帅哥!</div> <script> var hzh = document.getElementById('hzh'); hzh.onclick = function toggleStyle() { var style = this.style; if(!style.cssFloat) { style.cssFloat = 'left'; style.backgroundColor = 'black'; style.color = 'white'; } else { style.cssFloat = ''; style.backgroundColor = 'white'; style.color = 'black'; } }; </script> </body> </html>
直接更改样式表
还可以直接对是否应用样式表进行设定。如果将 link 元素与 style 元素的 disabled 属性设为 true,相应的样式表就将被禁用(代码清单11.5)。
代码清单 11.5 直接更改样式表
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>直接更改样式表</title> <link rel="stylesheet" type="text/css" href="hzh1.css" id="hzh1" disabled="true"> <link rel="stylesheet" type="text/css" href="hzh2.css" id="hzh2" disabled="true"> <style id="hzh3" disabled="true"> #hzh { background-color: #999; } </style> <script> function change(id, enable) { // 在勾选了复选框之后启用样式 document.getElementById(id).disabled = !enable; } window.addEventListener('load', function () { // 在初始化处理中禁用所有样式 var style = document.styleSheets; for (var i = 0; i < style.length; i++) { style[i].disabled = true; } }, false); </script> </head> <body> <div id="hzh">黄子涵</div> <input type="checkbox" onchange="change('hzh1', this.checked)"> <input type="checkbox" onchange="change('hzh2', this.checked)"> <input type="checkbox" onchange="change('hzh3', this.checked)"> </body> </html> <!-- /* hzh1.css的内容*/ #hzh { font-size: x-large; } /* hzh2.css的内容*/ #hzh { text-decoration: underline; } -->
需要更改整个页面的样式时,就可以采用这种切换样式表启用禁用状态的方式。例如,对于已经事先准备了一些样式主题,需要让用户选择自己喜欢的主题以显示页面内容的情况,就可以通过这种方式实现。
如果不需要切换整个主题,则没有必要专门通过启用或禁用样式表来实现样式的更改。直接更改 class 名,或更改 style 属性的值即可。
11.1.2 位置的设定
在更改样式时,诸如文字大小或背景颜色等方面的更改操作理解起来并不难,但如果要更改 DOM 元素的位置,则必须知道更多的信息。学会如何将 DOM 元素设置于任意的位置,将有助于实现复杂的网页布局。
在设定位置时,最为关键的两点是 position 属性与鼠标指针的位置。另外则是要对如何处理 DOM 元素的宽度和高度有所了解。
position 属性
position 属性可以被指定为以下几种值之一。
• static • fixed • absolute •relative
如果在此设定了 static 以外的值,就能够设置 top、bottom、left、right 属性。
static
position 属性的默认值。将根据 HTML 中所写的标签来决定元素的配置。这种情况下无法通过 top 或 left 之类的属性来指定元素的位置。
fixed
如果将 position 属性指定为 fixed,则将会以浏览器窗口为基准来确定元素的相对位置。由于是相对于浏览器窗口的位置,因此即使对页面进行了滚动操作,元素在画面上的位置也不会发生改变。也就是说元素将始终保持在同一位置。
该值无法在 Internet Explorer 6 中使用。
absolute
如果将 position 属性指定为了 absolute,则可以对该元素与含有该元素的元素之间的相对位置进行设定。通常情况下都是元素与 body 元素之间的相对位置,不过如果嵌套了非 static 值的其他元素,则将以该元素为基准确定相对位置。
relative
如果将 position 属性指定为了 relative,则会在根据 HTML 中所写的标签进行配置的基础上,对元素的相对位置进行设置。
不过,如果已经指定了 relative 值,一般也就不会再设置 top 或 left 之类的值了。通常的做法是,以被设定为 absolute 的元素为标准来进行位置设定。根据对 absolute 的说明可以知道,被设定为 absolute 属性的元素,是以含有该元素的元素中 position 属性没有被设定为 static 的元素为基准来确定位置的。而被设定为 relative 的元素的位置与其被设定为 static 时的情况并没有什么不同,将会被动态地置于正确的位置。这样一来,就能够按照期望的那样,根据其与被设定为 relative 值的元素的相对位置来配置该元素的位置。
11.1.3 位置
如果要实现在鼠标点击位置附近显示一个框这样的效果,则必须要知道点击位置。在 MouseEvent 被触发时,相应的 Event 对象提供了多个属性来获取这一位置。这时的问题在于,需要知道点击的位置是以什么为基准来表示的。
function onclick(event) { // 通过 event 对象获取鼠标指针的位置,并进行相应的处理 }
屏幕坐标
可以通过 screenX 和 screenY 属性来获取屏幕坐标。屏幕坐标是一种以计算机显示器的左上角为原点的坐标系。不过由于这只是屏幕上的位置坐标,因此能够对其进行有效利用的情况很少。
窗口坐标
可以通过 clientX 和 clientY 属性来获取窗口坐标。窗口坐标是一种以浏览器的显示范围的左上角为原点的坐标系。这一坐标系与文档、元素的滚动情况无关,其坐标值仅由内容的显示位置决定。
文档坐标
可以通过 pageX 和 pageY 属性来获取元素在文档中的位置。文档坐标是一种以文档页面的左上角为原点的坐标系。与窗口坐标不同,其坐标值与显示位置无关,是由元素在整个文档中的位置决定的。
DOM 对 screenX 与 clientX 进行了定义,但没有定义 pageX。这一坐标系是由浏览器自定义实现的。Internet Explorer 8 以及更早版本无法使用这一坐标。
在特定元素内的相对坐标
通过 layerX 与 layerY,或 offsetX 与 offsetY 属性,可以获取触发了事件的元素内的相对坐标。这些属性没有在 DOM 中被定义,是由浏览器自定义实现的功能。
Element.getBoundingClientRect()
虽然不能直接取得相对坐标,但也能实现类似的功能。该方法是在 CSSOMView Module 这一与文档显示方式有关的标准中被定义的。通过使getBoundingClientRect()
,能够获取元素范围信息的窗口坐标。这里的范围信息指的是,距离左侧的距离(left)、距离上方的距离(top)、宽度(width)与高度(height)。可以像代码清单 11.6 中这样,将这些值与 clientX 和 clientY 结合使用以获取元素内的相对坐标。
而代码清单 11.7 是一个完整的例子,它将在点击的位置显示元素。
代码清单 11.6 在元素内取得相对坐标
function onclick(event) { var hzhX = event.clientX; // 窗口坐标系中鼠标指针的x坐标 var hzhY = event.clientY; // 窗口坐标系中鼠标指针的y坐标 var hzhR = event.target.getBoundingClientRect(); // 窗口坐标系中被点击元素的范围信息 hzhX -= hzhR.left; // 鼠标指针在被点击元素内部的x坐标 hzhY -= hzhR.top; // 鼠标指针在被点击元素内部的y坐标 }
代码清单 11.7 一个在点击位置显示元素的例子
<!DOCTYPE html> <html lang="zh"> <head> <title>一个在点击位置显示元素的例子</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="hzh" style="width: 2000px; height: 2000px; position: relative;"> <div id="message" style="position: absolute; background: lightgray; width: 100px;">黄子涵</div> </div> <script> var hzh = document.getElementById('hzh'); function getPosition(event) { var hzhX = event.clientX; // 窗口坐标系中鼠标指针的x坐标 var hzhY = event.clientY; // 窗口坐标系中鼠标指针的y坐标 var hzhR = event.target.getBoundingClientRect(); // 窗口坐标系中被点击元素的范围信息 hzhX -= hzhR.left; // 鼠标指针在被点击元素内部的x坐标 hzhY -= hzhR.top; // 鼠标指针在被点击元素内部的y坐标 return { x: hzhX, y: hzhY }; } hzh.addEventListener('click', function (event) { var message = document.getElementById('message'); if (event.target === message) { // 如果点击 message, 则不进行操作 return; } var hzhPos = getPosition(event); message.style.left = hzhPos.hzhX; message.style.top = hzhPos.hzhY; }, false); </script> </body> </html>
这里暂时没有做出效果,标记一下。
11.2 AJAX
AJAX 是 Asynchronous JavaScript + XML 的简称。AJAX 一词的实际含义为“不发生页面跳转、异步载入内容并改写页面内容的技术”。在实际操作中,AJAX 不仅仅会使用 XML 数据,很多时候也会对 JSON 或纯文本进行操作。AJAX这个词是由 Jesse James Garrett 在 2005 年命名的。不过,在那之前就已经有使用 AJAX 的网站。众所周知,Google 的 Gmail 就是一个利用了AJAX 的优秀范例。如今,AJAX 正在全世界范围内迅速地得到普及。
异步处理的优点
AJAX 的关键在于它是以异步的方式执行的。异步处理的优点是不会让用户白白等待。对于同步处理来说,在处理完来自服务器的响应之前,用户无法进行任何其他操作,只能等待。如果服务器的响应发生了延迟,会让用户误以为页面失去了响应。在优先考虑用户体验时,与同步处理相比,采用异步处理的方式更为合适,这一点是显而易见的。JavaScript 是一种事件驱动程序设计语言,在很多地方都会用到异步处理,所以要理解异步处理并不是一件难事。
XMLHttpRequest
如果要通过 JavaScript 动态地向服务器发送请求,则需要使用 XMLHttpRequest 对象。不过在这里要稍微提醒一下大家,XMLHttpRequest 目前尚未被制定为标准。之所以说是“稍微”,是因为那些现代的浏览器自然不必多说,即使是Internet Explorer 也在 7 以及之后的版本里全都使用了通用的 API,因此它已经成为了一种事实标准。考虑到这点,尚未标准化也就不是什么问题了。问题在于 Internet Explorer 6。不过它也仅仅是在对象的创建方式上有所不同,对象所含有的方法与其他浏览器中的实现是通用的。
基本的处理流程
XMLHttpRequest 对象的创建
发送请求
readyState的含义
同步通信
超时
响应
跨源限制
所谓跨源限制指的是,对源不同的通信进行限制。而这里的源指的是由 URL 的协议(http: 或 https: 等)、主机名、端口号所构成的元素。在 Web 领域,为了确保安全性,只有同源的通信才能被允许进行,这称为同源策略。
虽然可以在 HTML 中使用 iframe 以实现在一个页面中同时显示来自不同域的文档,不过 JavaScript 仍然只能访问同一个源的文档。如果文档的 URL 和 iframe 的不同,则无法通过文档中所包含的 JavaScript 对 iframe 内的 DOM 进行操作,而 iframe 内的 JavaScript 也无法操作文档中的 DOM。如果不这样,就会发生诸如不同域的 Cookie 能够相互访问等安全问题。
对于 XMLHttpRequest 来说,同源策略的含义是,一个 XMLHttpRequest 对象只能发送至一个特定的服务器,即提供了使用该 XMLHttpRequest 对象的文档的下载的那个服务器。不过,只要让服务器转发该请求,就能够将请求发送至不同域的服务器。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本