【JavaScript从入门到精通】第四课初探JavaScript魅力-04
第四课初探JavaScript魅力-04
style与className
之前我们已经讲过,style用于在JS里控制元素的样式,通过style可以选中元素的各种css属性。此外,我们也提到过,JS用className控制元素的class。这两者之间,是否会产生什么矛盾吗?
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
#div1 {width:200px; height:200px; border:1px solid black;}
.box {background:red;}
</style>
<script>
function toRed()
{
var oDiv=document.getElementById('div1');
oDiv.style.background='red';
}
</script>
</head>
<body>
<input type="button" value="变红" onclick="toRed()" />
<div id="div1"></div>
</body>
</html>
这段代码的作用不必多说,点击变红按钮后,div1块的背景颜色会变为红色。现在我们打开浏览器的控制台(F12),选中Div1,观察点击前后的变化:

可以看到,JS对div1的样式实际上是通过行间样式的方法进行控制的。实际上,通过JS的style方法加入的样式都是通过行间样式来控制的,而且通过style也只能读取到元素的行间样式。
我们来看看style和class之间的关系。要阐明这两者之间的关系,首先需要弄清楚css里的样式优先级。在css里,样式的优先级代表了css优先执行的代码。样式优先级的顺序如下(从高到低):
- 行间样式
- ID
- class
- 标签
- 通配符
行间样式具有最高的优先级。现在我们来看这个一个例子:
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
#div1 {width:200px; height:200px; border:1px solid black;}
.box {background:red;}
</style>
<script>
function toRed()
{
var oDiv=document.getElementById('div1'); oDiv.className='box';
}
function toGreen()
{
var oDiv=document.getElementById('div1'); oDiv.style.background='green';
}
</script>
</head> <body>
<input type="button" value="变红" onclick="toRed()" />
<input type="button" value="变绿" onclick="toGreen()" />
<div id="div1"></div>
</body>
</html>
执行结果如下:
上述代码先执行toRed函数再执行toGreen函数,程序可以正常运行;但如果先执行toGreen函数再执行toRed函数,toRed函数会失效。原因在于点击toGreen函数后,background为green属性的css添加到了行间,而点击toRed函数,虽然也能给元素添加含有background为red属性的class,但因为行间样式优先级比class高,所以优先执行行间样式的代码。我们可以得到如下结论:对于同一元素的同一属性,如果修改了其style,之后再修改其className不会再有效果。因此我们建议,对于同一个元素,在操作上保持一致性,要么只操作它的style,要么只操作它的className。
提取行间事件与匿名函数
我们之前使用的onclick="toGreen()"这一类写法就被叫做行间事件。然而,在我们实际工作的时候,一个页面通常是由多个人完成,如果将事件写在行间有可能会出现编辑的时候事件被删掉的情况。而且,当需要给大量元素增添功能相同的事件时,使用行间事件显得太过麻烦和重复。若元素的数量不固定,使用行间事件更是对代码无从下手。而采用提取行间事件的方法,可以很好地解决这些问题。
说到提取行间事件,我们首先得提到如何用JS给元素添加事件。可以看到,行间事件onclick的写法让onclick显得很像一个属性,那么是否可以通过操纵属性的方法将行间事件写到函数里呢?当然是可以的,我们将之前例子的一些代码进行修改:
var oBtn=document.getElementById('btn1');
function abc(){
	alert('a');
}
oBtn.onclick=abc;
效果和使用行间事件没有任何区别。这就是最简单的提取行间事件的方法。
在写网页代码的时候,如果代码量过大或者函数过多,取函数名是一件非常头疼的事情。在JS里,提供了一种匿名函数的形式,这种写法不用给函数取名,而函数体需要放在调用函数的地方。我们可以将上面的代码改成如下形式:
var oBtn=document.getElementById('btn1');
oBtn.onclick=function ()		//匿名函数
{
	alert('a');
};
实际工作中,大部分的事件都是通过这种匿名函数的方式完成的,这样非常方便,不会出现忘记函数名的情况。
window.onload事件
JS代码在浏览器执行的时候,有一个特点:每读一行,执行一行。在我们上面的例子中,我们将script标签放在了body里,程序可以正常执行。但如果你试着将script标签放在head标签里,你会发现程序报错。原因在于,当浏览器读到oBtn.onclick这一行时,后面body的代码还没有被加载进来,因此实际上你是在给一个不存在的按钮添加onclick事件,自然就会出错了。如何解决这个问题呢?
这个问题可以用window.onload事件解决。这个事件代表的含义是,当页面加载完成的时候发生。我们在前面的代码外套加window.onload:
window.onload=function (){
	var oBtn=document.getElementById('btn1');
	oBtn.onclick=function ()
	{
	    alert('a');
	}
};
添加之后,window.onload内包裹的函数只在页面加载结束后执行,因此函数执行的时候btn1已结被加载了进来,这样程序就不会出错了。
行为,样式,结构三者分离
在前端领域来说,行为,样式,结构三者分别对应着JavaScript,css和HTML,而将行为,样式,结构三者分离,简单来说,就是避免添加行间样式和行间事件。我们之前采用提取行间事件的方法将写成函数就是这个目的,在今后的代码编写中,也建议大家尽量遵守这个原则。
获取一组元素
我们之前提到,如果页面需要给大量元素添加事件,使用我们之前的写法会让代码显得非常繁杂重复。使用getElementsByTagName方法获取元素可以避免这一点。和getElementById方法不同的是,getElementById一次只能获取一个元素(因为id在HTML里不可重复),而getElementsByTagName一次可以获取一组元素。
为了说明这个问题,我们再举一个小例子:
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
div {width:200px; height:200px; float:left; border:1px solid black; margin:10px;}
</style>
<script>
window.onload=function ()
{
var aDiv=document.getElementsByTagName('div');
alert(aDiv.length);
};
</script>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>
我们通过getElementsByTagName获得了所有标签名为div的元素,而此时aDiv不再是一个元素而是一个数组。数组的简单概念可以理解为一堆元素的集合。数组有一个最简单的属性:length,代表了数组长度(元素个数),因此上面的例子中最后会弹出div块的个数。因此结果如下:
同样的,如果我们想修改这些div的样式,是否可以直接利用getElementsByTagName获取后直接修改呢?:
var aDiv = getElementsByTagName('div');
aDiv.style.background = 'red';
这样的写法是会出错的。原因在于在JS里,一次只能对一个元素的属性进行设置,而aDiv是一个数组,内含多个元素,无法对其进行直接操作。为了对数组进行操作,我们需要了解如何获得数组内的单个元素。我们如果将上面的代码进行这样的修改:
var aDiv = getElementsByTagName('div');
aDiv[0].style.background='red';
可以看到,第一个div块变为了红色。aDiv[0]中的0被称为下标,代表数组中元素的位数,需要注意的是下标统一是从0开始,aDiv[0]代表了aDiv数组中的第一个元素。
var aDiv = getElementsByTagName('div');
aDiv[0].style.background='red';
aDiv[1].style.background='red';
aDiv[2].style.background='red';
aDiv[3].style.background='red';
这样就能把4个div块的颜色都进行改变,但设置元素样式的代码依旧非常繁琐,如果存在100个这样的div,是否就需要将这样的代码写100次?实际上是不需要的,为了能够把这些类似的代码合并掉,我们需要用到循环。
循环
说到循环,我们先来回忆一下我们学过的if语句。还记得if语句的格式如下:
if(条件){
  语句1
}
else{
  语句2
}
对于if语句来说,如果条件是成立的,会执行一次语句1,否则执行一次语句2。然而,如果我们想多次执行语句1呢?采用循环的方式便可以让一个语句进行多次执行。 第一种循环(while循环)的语句格式如下:
while(条件){
   语句
}
对于while循环来说,只要条件成立,语句会一直执行,直到条件不再成立。我们用例子说明:
var i = 0; //初始化
while (i < 5) { //条件
alert(i); //语句
i = i + 1 //自增
}
i=i+1的意思是将i的值加1再返回给自身,也就是说,循环每执行一次,i的大小就增加1。执行的结果如下:
当第一次执行完毕后,i的值变为了1,依然比5小,所以继续执行,这样再反复四次后,i的值变为了5,5=5,条件不再成立,所以跳出了循环。对于一个循环,通常需要包含四个部分:初始化,条件,语句,自增。值得一提的是,表示自增的时候,我们通常用i++来代i=i+1这种比较复杂的写法。
在很多情况下,使用while循环是一个比较麻烦的选择,因此我们有了第二种更方便的循环语句:for循环。for循环的语句格式如下:
for(初始化;条件;自增){
  语句
}
和while循环一样,for循环也包含这四个部分,只不过格式上更为简便。上面的代码可以改为:
for(var i = 0; i < 5;i ++){
	alert(i);
}
那么,回到我们的getElementsByTagName方法上来。通过循环的方式,我们可以很轻松的将代码进行简化:
var aDiv = getElementsByTagName('div');
for(i = 0;i < 4;i ++){
  //i->0,1,2,3
  aDiv[i].style.background='red';
}
这里还存在最后一个小问题,如果我的div个数发生了改变(例如邮箱,每个人邮箱里面的邮件个数都是不同的),而我在函数用i<4将div块的个数定为4个,那么会产生HTML和JS代码不一致的情况,每次执行都需要修改JS。实际上,这个例子里的div个数,就是aDiv这个数组的长度,因此我们可以使用用length属性来解决这个问题。
var aDiv = getElementsByTagName('div');
for(i = 0;i < aDiv.length;i ++){
  //i->0,1,2,3
  aDiv[i].style.background='red';
}
这样无论html代码如何修改div块的个数JS也可以自动适应了。
全选、反选、不选
全选、反选、不选是网页经常会用到的功能,它们分别是怎么实现的呢?
我们给网页添加button和多个checkbox,希望通过button来控制checkbox的选中情况。根据我们前面所学的知识,我们应该采取如下思路:通过getElementById选中button,然后给button添加onclick事件,然后通过getElementsByTagName选中input标签来操作checkbox。这里有一个小小的问题,因为checkbox和button属性的标签都是input,所以如果通过input标签来进行元素选择,会同时选中checkbox和button,产生一些问题。
这里可以采用一个小技巧解决这个问题。我们将所有checkbox放入一个id为div1的标签中,然后在JS采用如下写法:
var oDiv = document.getElementById('div1');
var aCh = oDiv.getElementById('input');
也就是说,getElementById前不一定是document,在本例中先选中了div1,再从div1中选中input,这样就避免了选中button的情况。
在HTML中,控制checkbox选中情况的属性为checked,同理在JS里,可以通过操纵checked属性来改变checkbox的选中情况(选中时checked属性为true,未选中时为false)。true/false在JS里被称为布尔值,具体概念以后再讲。
具体代码如下:
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<script>
window.onload=function ()
{
var oBtn1=document.getElementById('btn1');
var oBtn2=document.getElementById('btn2');
var oBtn3=document.getElementById('btn3');
var oDiv=document.getElementById('div1');
var aCh=oDiv.getElementsByTagName('input'); oBtn1.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
aCh[i].checked=true;
}
}; oBtn2.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
aCh[i].checked=false;
}
}; oBtn3.onclick=function ()
{
for(var i=0;i<aCh.length;i++)
{
if(aCh[i].checked==true)
{
aCh[i].checked=false;
}
else
{
aCh[i].checked=true;
}
}
};
};
</script>
</head> <body>
<input id="btn1" type="button" value="全选" /><br>
<input id="btn2" type="button" value="不选" /><br>
<input id="btn3" type="button" value="反选" /><br>
<div id="div1">
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
<input type="checkbox" /><br>
</div>
</body>
</html>
执行结果如下:
【JavaScript从入门到精通】第四课初探JavaScript魅力-04的更多相关文章
- 【JavaScript从入门到精通】第二课 初探JavaScript魅力-02
		第二课 初探JavaScript魅力-02 变量 说起变量,我们不得不提起我们有一部比较古老的电视剧叫<包青天>.包青天有一把非常厉害的宝剑叫“尚方宝剑”,见到尚方宝剑有如见到皇帝.某种程 ... 
- 【JavaScript从入门到精通】第一课 初探JavaScript魅力-01
		第一课 初探JavaScript魅力-01 JavaScript是什么 如今我们打开一个大型的网站,都会有很多JS效果的功能和应用.对于学过CSS+HTML的同学,即使是像淘宝那样的网站,用一两天时间 ... 
- 【JavaScript从入门到精通】第一课
		第一课 初探JavaScript魅力-01 JavaScript是什么 如今我们打开一个大型的网站,都会有很多JS效果的功能和应用.对于学过CSS+HTML的同学,即使是像淘宝那样的网站,用一两天时间 ... 
- 【JavaScript从入门到精通】第二课
		第二课 初探JavaScript魅力-02 变量 说起变量,我们不得不提起我们有一部比较古老的电视剧叫<包青天>.包青天有一把非常厉害的宝剑叫“尚方宝剑”,见到尚方宝剑有如见到皇帝.某种程 ... 
- 【JavaScript从入门到精通】第三课 初探JavaScript魅力-03
		第三课 初探JavaScript魅力-03 函数传参 上节课的时候我们已经讲了什么是函数,实际上,函数在功能上就类似于css的class一样,将一段代码包裹起来使用.为了让函数的功能更加的丰富和实用, ... 
- 【JavaScript从入门到精通】第三课
		第三课 初探JavaScript魅力-03 函数传参 上节课的时候我们已经讲了什么是函数,实际上,函数在功能上就类似于css的class一样,将一段代码包裹起来使用.为了让函数的功能更加的丰富和实用, ... 
- GPU 编程入门到精通(四)之 GPU 程序优化
		博主因为工作其中的须要,開始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识,鉴于之前没有接触过 GPU 编程.因此在这里特地学习一下 GPU 上面的编程.有志同道合的小伙伴 ... 
- JavaScript从入门到精通(转)
		JavaScript从入门到精通 转自: https://github.com/Eished/JavaScript_notes 视频连接:https://www.bilibili.com/video/ ... 
- Hibernate从入门到精通(四)基本映射
		映射的概念 在上次的博文Hibernate从入门到精通(三)Hibernate配置文件我们已经讲解了一下Hibernate中的两种配置文件,其中提到了两种配置文件的主要区别就是XML可以配置映射.这里 ... 
随机推荐
- BZOJ3560 DZY Loves Math V 数论 快速幂
			原文链接http://www.cnblogs.com/zhouzhendong/p/8111725.html UPD(2018-03-26):蒟蒻回来重新学数论了.更新了题解和代码.之前的怼到后面去了 ... 
- day 58 bootstrap -part1
			我们的bootstrap主要使用都是官网里面的内容,官网里面的都整理得很完备,有需要的时候就直接去里面找即可, 关于这个bootstrap,我所理解的就是,我们前面所学的那些,从html开始一直到后面 ... 
- Python dictionary 字典 常用法
			Python dictionary 字典 常用法 d = {} d.has_key(key_in) # if has the key of key_in d.keys() ... 
- scrapy安装
			1.scrapy的安装 -前提,最好用virtualenv 创建的虚拟环境安装 -windows -官方推荐用anaconda -自定已安装 -1.https://www.lfd.uci.edu/~g ... 
- 做项目单个功能的时候要理解需求和sql语句。
			做项目单个功能的时候要理解需求和sql语句.最好直接按照给出来的sql语句或者存储过程来写,避免有极其细微的差别所造成的不同. 做宜春国税二期的时候有个功能叫夜间开票情况,钻取明细时由于没理解sql语 ... 
- dp经典问题-最大连续子序列和  hdu1003
			题目描述: 这道题我先后做过三遍,结果每一遍都没有做出来.今天再仔仔细细的研究了一下,才发现用动态规划更好理解. 关于求最大连续子序列和的博文转载如下:https://www.cnblogs.com/ ... 
- Splay的初步学习
			具体是啥,qwq 有时间再补吧,贴一下代码: #include<iostream> #include<cstdio> #include<cstring> #incl ... 
- Why Did the Cow Cross the Road III HYSBZ - 4991 -CDQ-逆序数
			HYSBZ - 4991 题意: 第一列 1-n的排列 ,第二列 1-n的排列. 相同数字连边 ,问 有多少组 数字 是有交点的并且 绝对值之差>K思路:处理一下 1-n 在第一列的位置, ... 
- for循环以及数据类型
			一.for循环(迭代式循环) 了解:当我们在写代码时,如果代码是纯运算的代码,会占用大量的CPU,如果是I/O代码,则不会占用CPU. for i in range(10): #可以是任意类型(字符 ... 
- 杭电1024----Max Sum Plus Plus
			/* 这题还没有理解透彻.某个dalao也不写注释.只能自己理解了... 先求为i个元素(1<=i<=M)为一个区间的最大和,保证元素个数大于等于i个,递推到M个即可 借鉴原址:http: ... 
