上一篇后半部分写的不好,就是浅显的罗列语法。排序,下周补充其余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开发一个小游戏