上一篇后半部分写的不好,就是浅显的罗列语法。排序,下周补充其余6种… 这篇讲了几个js案例:开关灯,汉字自动播放,轮播图 看完之后你能学会dom操作以及成就感。
javascript 原生方法对dom节点的操作包括: 访问(查找)、创建、添加、删除、替换、插入、复制、移动等。
唉,等等等等??? 什么是dom???
js分为ECMAScript、DOM、BOM三部分,第一部分是语法,就是变量啊函数啊,操作符啊等等等等的,DOM是操作文档对象,BOM是浏览器对象
今天只看DOM,也就是咱们写的HTML文档对象,整个html都归DOM管, 就是说可以通过dom来任意修改html文档
文档乖乖躺好,咱们做点什么呐? 理论没意思,直接上案例,“开关灯”
html里面有两个button元素,所谓元素就是用标签和它肚子里的一坨代码,标签就是尖括号加单词,这两个元素都有id,就是唯一识别,跟身份证一样,id的属性值不可以与其它元素一样。 我们用id来唯一识别这个元素,在做css时可以用 # 也就是id选择器来选这个元素,修改样式,那么js也有相应的方法-------document.getElementById("*****"); 为什么前面要加上document???前面学了对象,我们把一类的方法,封装到一个对象里…而document就是大名鼎鼎的DOM对象(如果对面向对象不理解,后面还会讲) 总之我们通过id来拿一个元素的时候(一般做功能时用id拿),语法这样写:document.getElementById(“一个id”);
那么同理,通过class拿元素时是document.getElementsByClassName(“类名”); 只不过类名可以重复,所以我们拿到的是一个伪数组 [元素1,元素2,元素3] 伪数组用起来和和数组没什么不同,取值arr[i],遍历for循环,只不过它不是Array,所以不能直接用Array的方法。 为什么要加一个直接呐?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p></p> <p></p> <p></p> <p></p> <p></p> <p></p> <p></p> <script> var ps = document.getElementsByTagName("p"); Array.prototype.forEach.call(ps, function(value, index) { console.log(index + "_" + value); }); </script> </body> </html>就像上面所使用的的代码一样,我们在js里面有改变指针方向的方法,如果你不清楚什么是call,什么是bind什么是apply,那么只能说我写的上一篇偷懒了,后面会和面向对象编程一样,单独写一篇来讲清楚,这里仅仅介绍,js还有这么一个玩意。
至此我们使用document.getElementById("")拿到on和off两个按钮元素,使用document.getElementsByClassName("")[0]拿到页面里的第一个类名为box的元素 (由此可见,做功能时用id比较靠谱,数第几个,万一再来几个box,就容易乱了)
拿到之后绑定事件,我们在硬件上操作,敲键盘,这都被浏览器所监听,只要我们在js上写了事件对应的函数,浏览器就会在这个事件发生时,调用这个函数。 用到的事件名叫点击事件,有两种写法,我们用的是简单的写法,给onclick属性赋值,其中click这个单词是点击的意思,常见的属性还有onmouseleave,mouseleave是鼠标移开的意思,还有onfocus等等 精讲讲的是概念,就不会罗列了,罗列的话,其实也没要讲,讲了不一定记住,更不一定会用,而精讲就是为了让大家会用。 off.οnclick=function(){ 巴拉巴拉 } 元素的这个属性赋值为一个函数,剩下的都归浏览器管,事件触发时,调用这个函数
接下来我们来写事件所绑定的函数 box.style.backgroundColor="#9e9e9e"; 里面就写了一行代码,元素的一个叫做style的属性的一个backgroundColor属性,赋值为"#9e9e9e",看上去就是改颜色的 元素的style属性是一个对象,其实元素在内存中就是一个对象,对象是什么?是一种以键值对存储数据的数据类型,也是类的实例,类是对一类现实事物的抽象,对象代表其中一个 style里面存着很多信息,它们都跟样式有关 style对象都有啥属性? 它的属性就是css样式的属性啊,只不过写法不太一样,当一个属性有连接符时需要,需要用大写来表示,意思就是css的margin-left在style对象的属性里面是marginLeft 所以我们想要修改元素的样式时,只需要 元素.style.属性名=“属性值”; #9e9e9e是颜色的一种表示方法,之前的博客有讲过,那篇比较长,讲了全部css,这里重新说一下。
好了现在可以自己动手敲这么一个超级小的开关灯案例了 当然,这篇进度条告诉我们,这篇文章还有很…很长…
//查找节点 document.getElementById(“id”);// 通过id查找,返回唯一的节点 document.getElementsByClassName(“class”);// 通过class查找,返回值为nodeList类型 document.getElementsByTagName(“div”);// 通过标签名查找,返回值为nodeList类型
//创建节点 document.createDocumentFragment();//创建内存文档碎片 document.createElement();//创建元素 document.createTextNode();//创建文本节点
//添加节点 var ele = document.getElementById(“my_div”); var oldEle = document.createElement(“p”); var newEle=document.createElement(“div”); ele.appendChild(oldEle);
//删除节点 ele.removeChild(oldEle);
//替换节点 ele.replaceChild(newEle,oldEle);
//插入节点 ele.insertBefore(oldEle,newEle);//在newEle之前插入 oldEle节点
//复制节点 var cEle = oldEle.cloneNode(true);//深度复制,复制节点下面所有的子节点 cEle = oldEle.cloneNode(false);//只复制当前节点,不复制子节点
//移动节点 var cloneEle = oldEle.cloneNode(true);//被移动的节点 document.removeChild(oldEle);//删除原节点 document.insertBefore(cloneEle,newEle);//插入到目标节点之前
上面是知识的罗列,放在这里供你复习 我们只讲案例,不讲罗列的到底是什么
<script> var str = "今天是7月4日,哈哈哈哈,再过一个月,就要找乐子了,啦啦啦啦"; var len = str.length; var length = len; var 爱了爱了 = document.createElement("p"); 爱了爱了.addClassName = "爱了爱了"; 爱了爱了.innerText = "开始: "; document.getElementsByTagName("body")[0].appendChild(爱了爱了); var timer = setInterval(() => { var span = document.createElement("span"); span.innerText = str.charAt(length - len); 爱了爱了.appendChild(span); len--; if (len <= 0) { clearInterval(timer); } }, 200); </script>然后我们给他稍微加点特效,看不明白的可以去翻阅我之前的博客,有讲css 赋值粘贴就可以运行,这里文字一出来是模糊的,后来好了,这就是为什么要把每个字当做一个元素处理。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> span { text-shadow: 0 0 60px transparent; transition: text-shadow 1.5s; color: transparent; font-size: 30px; font-weight: 900; opacity: 0; } </style> </head> <body> <script> var str = "今天是7月4日,哈哈哈哈,再过一个月,就要找乐子了,啦啦啦啦"; var len = str.length; var length = len; var 爱了爱了 = document.createElement("p"); 爱了爱了.addClassName = "爱了爱了"; 爱了爱了.innerText = "开始: "; document.getElementsByTagName("body")[0].appendChild(爱了爱了); var timer = setInterval(() => { let span = document.createElement("span"); span.innerText = str.charAt(length - len); 爱了爱了.appendChild(span); lala(span) len--; if (len <= 0) { clearInterval(timer); } }, 200); function lala(span) { setTimeout(() => { span.style.textShadow = "0 0 0 black"; span.style.opacity = "1"; }, 300); } </script> </body> </html>我们创建了p元素,并把它添加到body元素肚子里, 我们创建了一个一个的字,然后加到p元素里, 当然,这里我们练习了定时器的使用,定时循环!
创建元素操作就是createElement(""); 添加元素是appendChild() 或者给innerHTML重新赋值(顾名思义,这是在修改里面的html代码) innerText则是修改里面的文字信息,修改TEXT_NODE节点信息 类操作就是操作class的属性
/** * obj:制定元素 * cn:对应类名 **/ //定义一个函数,来向一个元素添加类 function addClass(obj,cn){ if(!hasClass(obj,cn)) { obj.className+=" "+cn; } } //定义一个函数判断一个元素有没有这个类 function hasClass(obj,cn){ //创建一个正则表达式 var reg=new RegExp("\\b"+cn+"\\b"); return reg.test(obj.className) } //定义一个函数来删除对应元素中的类 function removeClass(obj,cn){ //创建一个正则表达式 var reg=new RegExp("\\b "+cn+"\\b"); //删除Class obj.className=obj.className.replace(reg,""); } //定义一个函数来切换一个类 function toggleClass(obj,cn){ //判断是否有这个类 if(hasClass(obj,cn)) { //如果有则删除 removeClass(obj,cn); } else { //没有则添加 addClass(obj,cn); } }这里正则的\b是单词边界,类名为a,不能把aa也算上 正则的test()方法很简单,匹配到符合规则的就返回true
定时器就是开的时候返回值保存一下,清空的时候传进去
再写一个js原生轮播图的案例,下午来写…
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } ul, ol, li { margin: 0; padding: 0; list-style: none; } .container { width: 900px; height: 500px; margin: 100px auto; } .slider { position: relative; min-width: 300px; width: 500px; height: 400px; margin: 0 auto; border: 5px solid black; border-radius: 20px; overflow: hidden; } ul { width: 600%; height: 100%; display: flex; position: absolute; } ul>li { flex: 1; height: 100%; border-radius: 10px; } ol { position: absolute; left: 50%; transform: translateX(-50%); top: 80%; width: 270px; height: 30px; } ol>li { width: 30px; height: 100%; float: left; position: relative; ; } ol>li:not(:last-child) { margin-right: 30px; } .heart:hover { animation-name: shake; animation-duration: .5s; animation-iteration-count: infinite; } .heart div { width: 100%; height: 100%; position: absolute; background: rgba(238, 23, 23, 0.449); } .heart:hover div { animation-name: shadow; animation-duration: .5s; animation-iteration-count: infinite; } .topLeft, .topRight { border-radius: 50% 50% 0 0; } .topLeft { transform: translate(-50%, 0) rotate(-45deg)scale(.8, .9); } .topRight { transform: translate(51%, 0) rotate(45deg)scale(.8, .9); } .bottom { transform: translate(5%, 55%) rotate(45deg) scale(.7, .8); } /* 定义动画 */ @keyframes shake { from { transform: scale(.9, .9); } to { transform: scale(1.1, 1.1); } } @keyframes shadow { from {} to { box-shadow: 0px 0px 50px red; } } .controls { position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 100%; height: 50px; display: none; } .left, .right { position: absolute; width: 50px; height: 50px; border-radius: 50%; top: -25px; } .right { right: 0; } ul>li:nth-child(1) { background-color: indigo; } ul>li:nth-child(2) { background-color: pink; } ul>li:nth-child(3) { background-color: yellow; } ul>li:nth-child(4) { background-color: green; } ul>li:nth-child(5) { background-color: blue; } ul>li:nth-child(6) { background-color: indigo; } </style> </head> <body> <div class="container"> <div class="slider"> <ul id="罪魁祸首"> <li> </li> <li> </li> <li> </li> <li> </li> <li> </li> <li> </li> </ul> <ol> <li class="heart d"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> <li class="heart d"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> <li class="heart d"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> <li class="heart d"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> <li class="heart d"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> </ol> <div class="controls"> <li class="heart left"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> <li class="heart right"> <div class="topLeft"></div> <div class="topRight"></div> <div class="bottom"></div> </li> </div> </div> </div> <script> var con = document.getElementsByClassName("controls")[0]; var slider = document.getElementsByClassName("slider")[0]; var 罪魁祸首 = document.getElementById("罪魁祸首"); var ol_lis = document.getElementsByClassName("d"); var left = document.getElementsByClassName("left")[0]; var right = document.getElementsByClassName("right")[0]; var index = 0; var timer; function 垃圾函数(index) { let target = -parseInt(index * (1 / 6) * (罪魁祸首.offsetWidth)); let current = parseInt(罪魁祸首.offsetLeft); clearInterval(timer); timer = setInterval(() => { current += target > current ? Math.ceil((target - current) / 10) : Math.floor((target - current) / 10); // 一行很丑的代码 罪魁祸首.style.left = current + "px"; if (target === current) { clearInterval(timer); } }, 30); } slider.onmouseenter = function() { con.style.display = "block"; } slider.onmouseleave = function() { con.style.display = "none"; } Array.prototype.forEach.call(ol_lis, function(value, i) { value.onclick = function() { ! function(i) { index = i; 垃圾函数(index); }(i); } }); left.onclick = function() { if (index === 0) { 罪魁祸首.style.left = -(5 / 6) * (罪魁祸首.offsetWidth) + "px"; index = 5; } index--; 垃圾函数(index); } right.onclick = function() { if (index === 5) { 罪魁祸首.style.left = 0; index = 0; } index++; 垃圾函数(index); } </script> </body> </html>轮播图嘛,似乎我又忘了做自动轮播了,,,希望好心的客人能在评论区补充上,自动轮播。 这里面的小特效就是鼠标移到按钮上,播放css动画,心变大变小,阴影模糊程度时高时低。 讲一讲那行很丑的代码吧: current += target > current ? Math.ceil((target - current) / 10) : Math.floor((target - current) / 10); 这行应该拆开写的,不好看,所以我说他丑。 current是没有单位的当前的定位的left的值 +=就是加一点,有可能是往左走,也有可能是往右走,所以右面用三元表达式分了两种情况 target>current?: 如果目标在现在右边,那么目标大(left值),那么所以:左边表达式的值就被+上去了 目标大,那么加的这一步是正数,取天花板(Math.ceil()),这样一来最小也是1px,另外px也不用小数,发光点一定大于1,除以10是为了一小步一小步的走 这样一来,每次走1/10,最小走1px;
这里有防抖处理,就是开启定时器之前先clearInterval(),把上一个定时器去除 如果不去除,那么两个一起跑,结果你自己试试就知道了。 节流、防抖这两个操作,回头还有机会再讲一遍。现在没有实际的场景,扯犊子没什么意思。 节流就是搞一个东西记录时间,判断两次点击之间时间差,太短了的话就return 某些网站的搜索功能是10s一次,不知道你有没有看过~~~~
下一篇会讲js开发一个小游戏