[关闭]
@wangjialin 2016-04-12T22:39:51.000000Z 字数 5865 阅读 754

《JavaScript DOM 编码艺术》读书笔记(三)

读书总结


前面提到了使用JavaScript来修改文档的样式信息,但是随着浏览器的的不断升级更新,CSS的兼容性以及功能也越来越强大,所以总的来说使用CSS来改变样式依旧是最佳的选择,但是要想达到随着时间的变化而不断改变元素样式的话,CSS就没有办法了,而JavaScript可以很完美的实现,其中动画就是随着时间不断改变样式(元素位置)的例子之一

简单动画之定时改变元素位置

点击查看一个甜蜜的demo------demo
这个小动画就是按照随着时间不断改变元素位置的思想完成的,脚本很简单,具体代码查看demo,下面是核心代码:

  1. //采用绝对定位以及setTimeout来定时改变元素位置
  2. function moveElement(element, final_x, final_y, interval) {
  3. var elem = document.getElementById(element);
  4. var xpos = parseInt(elem.style.left);
  5. var ypos = parseInt(elem.style.top);
  6. if (xpos == final_x && ypos == final_y) return true;
  7. if (xpos < final_x) xpos++;
  8. if (ypos < final_y) ypos++;
  9. if (xpos > final_x) xpos--;
  10. if (ypos > final_y) ypos--;
  11. elem.style.left = xpos + "px";
  12. elem.style.top = ypos + "px";
  13. var repeat = function() {
  14. moveElement(element, final_x, final_y, interval);
  15. }
  16. setTimeout(repeat, interval);
  17. }
  18. //由于style只能返回内嵌样式,所以只能采用DOM初始化元素位置并调用moveElement()函数
  19. function positionmessage() {}

实用的动画

现如今,不光是JavaScript还有很多CSS3的属性可以做出来动画的效果,但是动画元素过多不仅容易引起用户的不满,而且会导致出现一些可访问性的问题,作者引用了W3C里面:

  • 除非浏览器允许用户“冻结”移动的内容,否则就应该避免让内容在页面中移动。如果页面上有移动的内容,就应该使用脚本或者插件的机制允许用户冻结这种移动或者动态更新行为

也就是说我们应该只在必须使用动画的时候或者用户可以自己控制动画的时候使用动画。
下面采用的实例是一个比较常见比较有用的动画,经常会在一些电商网站,类似taobao,JD之类的看到,效果类似首页中间的大广告一直在不停的切换,或者鼠标放上去就可以切换图片,这时就应该选择JavaScript脚本来实现动画。这里我们采用的实例是在一个包含链接的网页上面,实现用户鼠标扫过链接时预览链接对应的图片
首先我们需要完成大致的html结构,包含一个标题一个简短的段落以及一个有3个列表项的有序列表,非常简单的结构

  1. <h1></h1>
  2. <p></p>
  3. <ol>
  4. <li><a></a></li>
  5. ····
  6. </ol>

初始版本

回想一下之前做过的DOM练习,发现这个和构建图片库很相似,好像只需要把点击操作换onmouseover,仿照之前的例子来实现的话首先需要建立一个占位符,可以采取之间在 ol 之后添加一个图片的标签或者在脚本里面创造标签,基于分离的思想当然后者更好,但是首先我们要让程序先跑起来嘛~~~所以,偷懒使用第一种~来看我的demo------demo
核心代码如下:

  1. function prepareSlideshow() {
  2. //为图片应用样式以便后期使用
  3. var preview = document.getElementById("preview");
  4. preview.style.position = "absolute";
  5. //位置初始值
  6. preview.style.top = "0px";
  7. preview.style.left = "0px";
  8. //获取所有链接
  9. var linklist = document.getElementById("linklist");
  10. var links = linklist.getElementsByTagName("a");
  11. links[0].onmouseover = function() {
  12. moveElement("preview", -100, 0, 10);
  13. }
  14. links[1].onmouseover = function() {
  15. moveElement("preview", -200, 0, 10);
  16. }
  17. links[2].onmouseover = function() {
  18. moveElement("preview", -300, 0 , 10);
  19. }
  20. }

乍一看好像还不错,至少当我鼠标扫过每个链接的时候图片在切换,这里需要注意的是:
1. 如果每个链接对应不同的图片的时候,图片在加载的时候即使是高速网络也不免得有延迟。为避免在切换不同的图片的时候出现延迟而使得动画不够流畅,首先使用photoshop将图片拼接到一起在使用,其次为了可以分别显示每个图片则可以再img外围加一个div并设置其宽高,然后设置其溢出表现 overflow:hidden;,每个图片的位置则采用绝对定位的方法将图片移动并显示
2. 获取每一个 li,然后在图片上面确定扫过每个 li 之后图片的位置;为达到动画效果采用 moveElement 函数
嗯,还不错,可是当我扫了几下链接之后,发现图片在颤抖。。这是为什么呢?

改进版本

因为鼠标移动过快造成颤抖所以可以确定一定是由于 moveElement 函数造成的,所以我们先来分析一下 moveElement 函数里面的构成。

  1. function moveElement(element, final_x, final_y, interval) {
  2. if (!document.getElementById) return false;
  3. if (!document.getElementById(element)) return false;
  4. var elem = document.getElementById(element);
  5. //给elem增加一个属性来使每个元素在移动前都获得一个名为movement的属性来使img复位
  6. if (elem.movement) {
  7. clearTimeout(elem.movement);
  8. }
  9. //验证elem是否存在left和top属性,若没有该属性就直接赋值为初始值,此时可以将之前的赋值删去
  10. if (!elem.style.left) elem.style.left = "0px";
  11. if (!elem.style.top) elem.style.top = "0px";
  12. var xpos = parseInt(elem.style.left);
  13. var ypos = parseInt(elem.style.top);
  14. var dist = 0;
  15. if (xpos == final_x && ypos == final_y) {
  16. return true;
  17. }
  18. if (xpos < final_x) {
  19. dist = Math.ceil((final_x - xpos)/10);
  20. xpos += dist;
  21. }
  22. if (ypos < final_y) {
  23. dist = Math.ceil((final_y - ypos)/10);
  24. ypos += dist;
  25. }
  26. if (xpos > final_x) {
  27. dist = Math.ceil((xpos - final_x)/10);
  28. xpos-= dist;
  29. }
  30. if (ypos > final_y) {
  31. dist = Math.ceil((ypos - final_y)/10)
  32. ypos-=dist;
  33. }
  34. elem.style.left = xpos + "px";
  35. elem.style.top = ypos + "px";
  36. var repeat = function() {
  37. moveElement(element, final_x, final_y, interval);
  38. }
  39. //第一次移动之后elem即可获得movement属性
  40. elem.movement = setTimeout(repeat, interval);
  41. }

在这里我做了三处改变,一个就是修复之前的问题,另一个关于改变移动速度,最后给移动元素检验了是否含有left和top属性。

最终版本

开始时我偷懒在HTML结构里面创建了 divimg ,鉴于有一部分用户可能会吧JavaScript脚本屏蔽,那HTML里面加的元素就没有任何用处了,不如在脚本里面创建,点击查看这个最终版本的demo-----最终版本
核心代码如下:

  1. var imgelem = document.createElement("img");
  2. imgelem.setAttribute("id", "preview");
  3. imgelem.setAttribute("src", "../img/donghua.png");
  4. imgelem.setAttribute("alt", "beauty girl");
  5. var divelem = document.createElement("div");
  6. divelem.setAttribute("id", "slideshow");
  7. divelem.appendChild(imgelem);
  8. var linklist = document.getElementById("linklist");
  9. insertAfter(divelem, linklist);

insertAfter函数之前已经第一篇最后一部分讲到过,其余的就是DOM的核心方法了,可以把移动元素的其他CSS属性放置在外部CSS文件里面,这样每一部分的用处更加明显

总结

编者语:实现动画效果并不难,难在在实践中该不该使用动画。同样,写代码并不难,难在写出大家都看得懂的代码。
书中使用了这样一条语句:
var repeat = "moveElement('"+elementID+", "+final_x+", "+final_y+", "+interval+"')",怎么说呢,括号里面是在拼接字符串,又是单引号又是双引号的很容易出错,而且还有很多人不理解,参考提问,可以改写成

  1. elem.movement = setTimeout(function(){
  2. moveElement(elementID,final_x,final_y,interval);
  3. },interval);

或者更加清楚明了的

  1. var repeat = function() {
  2. moveElement(element, final_x, final_y, interval);
  3. }
  4. elem.movement = setTimeout(repeat, interval);

嗯,愿我们都能遵守规范,写出清楚易懂的代码,减少不必要的脚本和不那么需要的动画,让世界更美好~

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注