BOM——浏览器对象,使JavaScript有能力与浏览器对话,包括Window对象、History对象、Location对象。
window对象:
Window对象是内置对象,已经实例化为window,alert()即是window对象的方法,完整的写法是window.alert()。还包括:
confirm():有两个按钮,确定、取消,alert只有确定。确定返回值true,取消返回值false。
propmt():有一个文本输入框,确定返回输入框的内容,取消返回值为null。
open():打开一个新的浏览器窗口或查找一个已命名的窗口。
close():关闭浏览器窗口。
setInterval():按照指定的周期(以毫秒计)来调用函数或计算表达式,设定定时器。
clearInterval():取消由setInterval()设置的定时器。
setTimeout():在指定的毫秒数后调用函数或计算表达式。
clearTimeout():取消由setTimeout()方法设置的timeout。
scrollTo():把内容滚动到指定的坐标。
定时器举例:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="clock">
<input type="button" value="begin" onclick="begin_click();">
<input type="button" value="end" onclick="end_m();">
<script>
function mytime() {
var date_obj = new Date();
return date_obj.toLocaleString();
}
function begin_m() {
var stime = mytime();
var ret = document.getElementById("clock");
ret.value = stime;
}
var ID1;
function begin_click() {
begin_m();
ID1 = setInterval(begin_m,1000); //设置一个定时器
}
function end_m() {
clearInterval(ID1); //清除定时器
}
</script>
</body>
</html>
运行结果:
当点击begin按钮时,在文本框中每隔1秒执行一次begin_m,即显示一次时间,按end,停止。
有一个bug,就是点击多次begin后,end就不好用了,因为每次调用setInterval(),都会生成一个新的定时器,ID1变量保存的是最后一次点击begin按钮时生成的定时器,end结束的只是最后一次的定时器,前面几次的还在运行。修改:
var ID1;
function begin_click() {
if (ID1 == undefined){
//判断是否存在定时器了,如果没有存在,生成新的定时,否则只使用已生成的
begin_m();
ID1 = setInterval(begin_m, 1000); //设置一个定时器
}
}
function end_m() {
clearInterval(ID1); //清除定时器
ID1 = undefined;
//清除定时器的同时,将ID1置为undefined,下次按begin时可以重新开始
}
setTimeout使用:
History对象:
三种方法:forward()、back()、go()
举例,两个页面,第一个页面点击一个连接进入第二个页面,第二个页面点击后退回到前一个页面,第一个页面再点击前进,进入第二个:
第一个页面:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="前进" onclick="func1();">
<a href="history2.html">qqqqqqqqqqqq</a>
<script>
function func1(){
history.forward();
}
</script>
</body>
</html>
第二个:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="后退" onclick="func2();">
<script>
function func2() {
history.back();
}
</script>
</body>
</html>
属性length,保存了访问了多少历史页面
Location对象:
方法:reload(),重新加载,刷新页面的作用。
<input type=“button” value=“重载” οnclick=“history.reload();”>
DOM对象(DHTML):——Document Object Model
DOM定义了访问HTML和XML文档的标准:
W3C文档对象模型(DOM)是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。
W3C DOM标准被分为3个不同的部分:
- 核心DOM–针对任何结构化文档的标准模型
- XML DOM–针对XML文档的标准模型
- HTML DOM–针对HTML文档的标准模型
XML DOM定义了所有XML元素的对象和属性,以及访问它们的方法。
HTML DOM定义了所有HTML元素的对象和属性,以及访问它们的方法。
DOM节点:
HTML文档中的所有内容都是节点(NODE):
- 整个文档是一个文档节点(document对象)
- 每个HTML元素是元素节点(element对象)
- HTML元素内的文本是文本节点(text对象)
- 每个HTML属性是属性节点(attribute对象)
- 注释是注释节点(comment对象)
节点(NODE)对象有自身属性和导航属性:
节点(自身)属性:
- attributes – 节点(元素)的属性节点
- node Type – 节点类型
- node Value – 节点值
- node Name – 节点名称
- innerHTML – 节点(元素)的文本值
导航属性:
- parentNode – 节点(元素)的父节点(推荐)
- firstChild – 节点下第一个子元素
- lastChild – 节点下最后一个子元素
- childNodes – 节点(元素)的子节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<div>hello div</div>
<p>hello ppp</p>
</div>
<script>
var ele = document.getElementById("div1");
alert(ele);
</script>
</body>
</html>
变量el是HTMLDivElement对象。
所以找孩子的方法、属性似乎与我们想要的结果不符,很少使用。
找父节点是唯一的:
推荐使用以下属性:进行文档树导航
-
parentElement //父节点标签元素
-
children // 所有子标签
-
firstElementChild// 第一个子标签元素
-
lastElementChild //最后一个子元素标签
-
nextElementSibling // 下一个兄弟标签元素
-
previousElementSibling //上一个兄弟标签元素
var ele = document.getElementById(“div1”);
var ele2 = ele.firstElementChild;
alert(ele2.nodeName); // DIV
var ele3 = ele.lastElementChild;
alert(ele3.nodeName); // P
var eles4 = ele.children;
alert(eles4); //[object HTMLCollection]是一个集合了
alert(eles4.length); // 2
alert(eles4[0]); //[object HTMLDivElement]
alert(eles4[0].nodeName); //DIV
for(var i=0;i<eles4.length;i++){
console.log(eles4[i]);
}
var ele5 = document.getElementById(“div1”).firstElementChild;
var ele6 = ele5.nextElementSibling; //找到ele5的下一个兄弟标签元素
alert(ele6.nodeName); //就是P
访问HTML元素(节点),等同于访问节点
以不同的方式来访问HTML元素:
页面查找:
-
通过使用getElementById()方法
-
通过使用getElementsByTagName()方法
-
通过使用getElementsByClassName()方法
-
通过使用getElementsByName()方法
Title hellohello2hello3hello p
局部查找:
先选定一个元素,然后在这个元素里查找,即这个局部就是选定的这个元素内:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">hello
<div class="div2">hello2</div>
<div class="div3" name="abc">hello3
<p class="ddd" name="ccc">hello inner</p>
</div>
<p>hello p</p>
</div>
<script>
var ele = document.getElementsByClassName("div3");
var ele2 = ele[0].getElementsByTagName("p"); //只在div3下找p标签,通过tag
alert(ele2[0].innerHTML);// hello inner
// var ele3 = ele[0].getElementById("");//不支持ID
var ele4 = ele[0].getElementsByClassName("ddd");//通过class查找
alert(ele4[0].innerHTML); // hello inner
var ele5 = ele[0].getElementsByName("ccc");//不支持通过name查找
//以上是局部查找,不支持ID和name查找
</script>
</body>
</html>
HTML DOM Event(事件)
HTML4.0新特性之一是有能力使HTML事件触发浏览器中的动作(action),比如用户点击某个HTML元素时启动一段JavaScript代码。以下属性可插入到HTML标签来定义事件动作:
- onclick 当用户点击某个对象时调用的事件句柄
- ondblclick 当用户双击某个对象时调用的事件句柄
- onfocus 元素获得焦点 //光标进入输入框
- onblur 元素失去焦点 //应用场景:表单验证,用户离开某个输入框时,代表输入完成,进行验证
- onchange 域的内容被改变 //应用场景:用于表单元素,当元素内容被改变时触发(三级联动)
- onkeydown 某个键盘按键被按下 //应用场景:当用户在最后一个输入框按下回车键时,表单提交。
- onkeypress 某个键盘按键被按下并松开
- onkeyup 某个键盘按键被松开
- onload 一张页面或一副图像完成加载。
- onmousedown 鼠标按钮被按下
- onmousemove 鼠标被移动
- onmouseout 鼠标从某个元素移开
- onmouseover 鼠标移到某个元素之上
- onselect 文本被选中
- onsubmit 确认按钮被点击
事件的监听者是操作系统。
对于按键事件,keyCode属性声明了被敲击的键生成的Unicode字符码。对于keydown和keyup事件,它指定了被敲击的键的虚拟键盘码。虚拟键盘码可能和使用的键盘布局相关。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="press" onkeydown="fun1(event);">
<script>
function fun1(e) {
alert(e.keyCode);
}
</script>
</body>
</html>
onsubmit事件只能绑定到表单上。
绑定事件的另一种方法:
var obj = document.getElementsByClassName(“kkk”)[0];
obj.οnclick=function(){
语句;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="id1" onsubmit="return check();"> // 这里要注意,一定要加return才行
<input type="text" name="username">
<input type="submit" value="submit">
</form>
<script>
function check() {
alert("验证失败!");
return false;
}
//对于onsubmit事件的函数,需要有返回值,值为布尔型,true则提交,false则不提交
function check(e) {
e.preventDefault();//阻止默认动作,也可实现上面的阻止提交动作
}
//第二种绑定事件的方式
var form_1 = document.getElementById("id1");
form_1.onsubmit = function () {
alert("shibai");
return false;
}
//这种另外一种实现绑定的方式,比较常用
</script>
</body>
关于在form标签中直接使用onsubmit必须使用return的解释:
onsubmit属性就像是这个html对象的一个方法名,其值(一字符串)就是其方法体,默认返回true;
和Java一样,在该方法体中你可以写任意多个语句,包括内置函数和自定义函数,如
οnsubmit="
alert(‘haha’); // 内置函数
submitTest(); // 自定义函数
alert(this.tagName); // 用到了this关键词
…(任意多条语句)
return false;
"
就相当于
Form.prototype.onsubmit = function() {
alert(‘haha’); // 内置函数
submitTest(); // 自定义函数
alert(this.tagName); // 用到了this关键词
…(任意多条语句)
return false;
};
这样的话你就覆写了(override)其默认方法(默认返回true)
大家注意到方法体中可以用this这个关键词,这里即代表了的对象实例。
经过这样的分析后,以上情况就不难理解了:
事件传播:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#div1{
height: 200px;
width: 200px;
background-color: #84a42b;
}
#div2{
height: 100px;
width: 100px;
background-color: #336699;
}
</style>
</head>
<body>
<div id="div1" onclick="alert('div1');">
<div id="div2" onclick="alert('div2');"></div>
</div>
</body>
</html>
点击div2时,会先弹出alert窗口div2,后又弹出div1,这就是事件传播。
在div2中增加:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#div1{
height: 200px;
width: 200px;
background-color: #84a42b;
}
#div2{
height: 100px;
width: 100px;
background-color: #336699;
}
</style>
</head>
<body>
<div id="div1" onclick="alert('div1');">
<div id="div2" onclick="f1(event);"></div>
</div>
<script>
function f1(e) {
alert("div2");
e.stopPropagation(); //阻止事件传播
}
</script>
</body>
</html>
增删改查,node的CURD:
增:
createElement(name) 创建元素
appendChild() 将元素添加
删:
获得要删除的元素,获得它的父元素,使用removeChild()方法删除
改:
第一种方式:使用上面增和删结合完成修改
第二种方式:使用setAttribute()方法修改属性,使用innerHTML属性修改元素的内容
查:
使用之前的方法,如document的getElementsBy。。。方法
修改HTML DOM包括以下的方面:
-
改变HTML内容:最简单方法是使用innerHTML,innerText
-
改变CSS样式:document.getElementsBy。。。("").style.color=“red”;
-
改变HTML属性:elementNode.setAttribute(name,value)、elementNode.getAttribute(name)<---------------->elementNode.value(DHTML)
-
创建新的HTML元素:createElement(name)
-
删除已有的HTML元素:elementNode.removeChild(node)
-
关于class的操作:elementNode.className、elementNode.classList.add、elementNode.classList.remove
Title hello div2hello ppp
上面的字体变大变小有点问题,修改如下:
function big() {
var ele = document.getElementById("div2");
// ele.className="big1";
ele.classList.remove("small1");
ele.classList.add("big1");
}
function small() {
var ele = document.getElementById("div2");
// ele.className="small1";
ele.classList.remove("big1");
ele.classList.add("small1");
}
使用classList,只是添加,并且是添加到class列表中,所以添加后会一直存在,改变时需要删除。
关于Event对象:
Event对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。事件通常与函数结合使用,函数不会在事件发生前被执行!event对象在事件发生时系统已经创建好了,并且会在事件函数被调用时传递给事件函数,我们获得仅仅需要接收一下即可。
改变HTML属性:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="div1"> hello div1</div>
<input id="add" type="button" value="add">
<script>
var ele = document.getElementById("add");
ele.onclick = function () {
var ele1 = document.getElementsByClassName("div1")[0];
var img = document.createElement("img");
img.setAttribute("src","1.jpg");
// img.src="1.jpg"; //第二种设置元素属性方式,是DHTML语法
ele1.appendChild(img);
}
</script>
</body>
</html>
关于a标签的补充:
<a href=“javascript:viod(0)” οnclick=“del(this)”>hello
协议名:协议内容,将a标签自身功能阉割,取消跳转功能。
this参数:代表调用函数的元素本身。
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>hello1
<div onclick="show(this);">hello2</div>
<!-- //this代表<div onclick="show(this);">hello2</div>这个元素-->
<div>hello3</div>
</div>
<script>
function show(s) {
console.log(s.innerHTML); //hello2
}
</script>
</body>
</html>
模态对话框:
点击一个按钮,弹出一个对话框,背景变暗,除弹出的对话框,其他无法操作:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin: auto 0;
}
#div1{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 2000px;
background-color: #b4b4b4;
z-index: 1000;
}
#div2{
position: fixed;
width: 100%;
height: 2000px;
background-color: red;
opacity: 0.3;
z-index: 1001;
}
#div3{
height: 300px;
width: 300px;
background-color: #2459a2;
position: absolute;
top:50%;
left: 50%;
z-index: 1002;
margin-left: -150px;
margin-top: -150px;
}
.hide{
display: none;
}
</style>
</head>
<body>
<div id="div1">
<input type="button" value="click" onclick="show();">
</div>
<div id="div2" class="div hide"></div>
<div id="div3" class="div hide">
<input type="button" value="cancel" onclick="cancel();">
</div>
<script>
function show() {
var div_t = document.getElementsByClassName("div");
for(var i=0;i<div_t.length;i++){
div_t[i].classList.remove("hide");
}
}
function cancel() {
var div_t = document.getElementsByClassName("div");
for(var i=0;i<div_t.length;i++){
div_t[i].classList.add("hide");
}
}
</script>
</body>
</html>
结果画面:
二级联动:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<select id="province" onchange="func1(this);">
</select>
<select id="city">
</select>
<script>
var data_p={"北京":["朝阳","海淀"],"山东":["济南","烟台"],"河北":["石家庄","张家口"]}
//数据可以从数据库提取,以后动态形成
var pro = document.getElementById("province");
var city_t = document.getElementById("city");
for(var i in data_p){
var option_pro = document.createElement("option");
option_pro.innerHTML=i;
pro.appendChild(option_pro);
}
function func1(s) {
var pro_n = (s.options[s.selectedIndex]).innerHTML;
// for(var j=0;j<city_t.children.length;j++){
// city_t.removeChild(city_t.children[j--]);
// }//循环删除city下的option选项,要注意这个算法,options是动态的
//删除一个孩子,下一次判断时,即j<city_t.children.length;,Length减1
//实际还可以写成city_t.removeChild(city_t.children[0]);j=j-1
city_t.options.length = 0;
//在选择其他选项前,要把当前的选项清空,此方法简洁
for(var k in data_p[pro_n]){
var option_city = document.createElement("option");
option_city.innerHTML=data_p[pro_n][k];
city_t.appendChild(option_city);
}
}
//参数s是this对象,代表当前操作的元素,这里即id为province的select元素
//this.options即s.options是select下的所有option元素,相当于选select的所有child元素
//selectedIndex保存了本次选择的option项的索引,最后innerHTML取出省份名称
// function func1() {
// var pro = document.getElementById("province");
// console.log(pro.value);//显示选择项的value值
// }
</script>
</body>
</html>
左右选择:
html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#box_l,#choice,#box_r{
display: inline-block;
}
#choice{
margin-bottom: 80px;
}
</style>
</head>
<body>
<div id="box_l">
<select id="sele_left" multiple size="10">
<option>选项1</option>
<option>选项2</option>
<option>选项3</option>
<option>选项4</option>
<option>选项5</option>
<option>选项6</option>
</select>
</div>
<div id="choice">
<input type="button" value="------->" onclick="addsele();"><br>
<input type="button" value="====>" onclick="addall();"><br>
<input type="button" value="<-------" onclick="removesele();"><br>
<input type="button" value="<====" onclick="removeall();">
</div>
<div id="box_r">
<select multiple size="10" id="sele_right">
<option>选项7</option>
</select>
</div>
<script>
var right_se = document.getElementById("sele_right");
var left_se = document.getElementById("sele_left");
function addsele() {
var op = left_se.children;
for(var i = 0;i<op.length;i++){
if(op[i].selected==true){
op[i].selected=false;
right_se.appendChild(op[i]);
i--; //这一步的逻辑很重要,类似上例的
//右边添加的同时,左边的同时删除。
//appendChild是从一个元素向另一个元素中移动元素,注意是移动
}
}
}
function addall() {
var op = left_se.children;
for (var i=0;i<op.length;i++){
op[i].selected = false;
right_se.appendChild(op[i]);
i--;
}
}
function removesele() {
var op = right_se.children;
for(var i=0;i<op.length;i++){
if(op[i].selected == true){
op[i].selected=false;
left_se.appendChild(op[i]);
i--;
}
}
}
function removeall() {
var op = right_se.children;
for (var i=0;i<op.length;i++){
op[i].selected = false;
left_se.appendChild(op[i]);
i--;
}
}
</script>
</body>
</html>
正反选:实现如下功能,可以一个一个单选,可以反选,可以全选
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" value="全选" onclick="seleall();">
<input type="button" value="取消" onclick="cancelall();">
<input type="button" value="反选" onclick="reverseall();">
<hr>
<table border="1px" class="box">
<tr>
<td><input type="checkbox"></td>
<td>1111111</td>
<td>2222222</td>
<td>3333333</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>1111111</td>
<td>2222222</td>
<td>3333333</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>1111111</td>
<td>2222222</td>
<td>3333333</td>
</tr>
</table>
<script>
function seleall() {
var t1 = document.getElementsByClassName("box")[0];
var inputs = t1.children[0].getElementsByTagName("input"); //属于局部查找
//对于table标签,它的孩子是tbody,虽然我们没写,但浏览器会增加
for(var i in inputs){
inputs[i].checked=true;
}
}
function cancelall() {
var t1 = document.getElementsByClassName("box")[0];
var inputs = t1.children[0].getElementsByTagName("input");
for(var i in inputs){
inputs[i].checked=false;
}
}
function reverseall() {
var t1 = document.getElementsByClassName("box")[0];
var inputs = t1.children[0].getElementsByTagName("input");
for(var i in inputs){
if(inputs[i].checked){
inputs[i].checked = false;
}else{
inputs[i].checked = true;
}
}
}
</script>
</body>
</html>
js作用域:
js作用域类似python,if、while等控制语句并没有自己的作用域,而函数是有自己的作用域;
嵌套函数的作用域,先内后外。
闭包:
var city = "bj";
function func() {
var city = "sh";
function inner() {
// var city = "LF";
console.log(city);
}
return inner;
}
var ret = func();
ret(); //inner中的city=“LF”注释掉,这里结果就是sh,闭包,不注释,就是LF