52、BOM & DOM

前端基础 / 2021-02-05

一、前言

参考:博客园-JsonJi,https://www.cnblogs.com/Dominic-Ji/p/9121560.html。

上一节的学习中,我们学习到了JavaScript的基础语法,但这跟浏览器、web页面貌似没什么关联!其实JavaScript分三部分内容:

  • 上一节的JavaScript语法基础
  • BOM
  • DOM

二、BOM

BOM,Browser Object Model,即浏览器对象模型,实现JavaScript操作浏览器!下面开始学习如何使用JavaScript操作浏览器:

2.1、window及其子对象

Window,窗口,指的是浏览器的窗口。window对象是JavaScript对象的祖师爷,在调用window对象的方式和属性时,可以简化掉window的书写,比如:window.document简写成document,这就有点类似Python的class默认继承object。

来看看window都有哪些神通:

2.1.1、常用方法
window.innerHeight  // 获取当前浏览器窗口高度
150
window.innerWidth  // 当前窗口宽度
1536
window.open('https://blog.sanxi.info','',[50,300])  // 以指定大小打开指定地址,第1个参数是目标地址,2留空,3是大小与位置。
window.close() // 关闭当前窗口
2.1.2、navigator对象

navigator,领航员,用于获取浏览器相关信息!

// 获取当前浏览器名称
navigator.appName
"Netscape"
// 获取浏览器项目名称
navigator.appCodeName
"Mozilla"
// 获取浏览器厂商和版本详细信息
navigator.appVersion
"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
// 获取浏览器所在的操作系统平台
navigator.platform
"Win32"
// 获取浏览器详细信息
navigator.userAgent
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"

在上面的演示中,appVersion和userAgent的结果非常相似,但其实还是有一定区别的!userAgent,表示当前是否是一个浏览器,常被用于防爬虫的最简单手段,即检验来访者是通过代码访问还是真实的浏览器访问。

之所以说是最简单的手段,因为对付此手段仅需在代码中加上user-agent配置即可,后续课程再详细介绍。

2.1.3、history对象

用于浏览历史的对象,比如用户在当前页面的浏览记录;但它是无法获取真实的URL,只能简单地前进或后退一页。

  • history.back(),退后一页。
  • history.forward(),前进一页。
2.1.4、location对象(重要)
// 获取当前页面URL
location.href
"file:///E:/Note/Python%E5%AD%A6%E4%B9%A0/Untitled-1.html"
// 跳转至指定网址
location.href = 'https://blog.sanxi.info'
// 重载当前页面
location.reload()
2.1.5、弹出框

后面会介绍配合函数、事件等完成非常有意思的动作!

警告框

alter常用于确保用户得到某些重要信息,当弹出警告框后,用户必须点击确定才能继续操作。

alert('hello,world!')alert
确认框

当弹出确认框后,用户必须点击确定或者取消才能继续操作;confirm有两个按钮,点击确认则返回true,取消返回false;比如说访问网站提示是否允许收集cookie。

confirm('请确认您的信息是否有误')
true
提示框

prompt,能拿到用户在弹出的框里所输内容

prompt('chrystal')
"beautiful"
2.1.6、计时器相关
单次触发

setTimeout即定时执行函数任务。伪语法结构如下:

var t=setTimeout("JS语句",毫秒)

setTimeout方法会返回一个值,如果需要取消任务,则用其来指定
括号内第一个参数为JavaScript语句,通常为函数;第二个参数为定时的时间,单位为毫秒。

代码演示

function timer(){alert('这是一次性定时任务')}
setTimeout(timer,2000)
2
取消单次定时

取消定时任务需要用到cleartimeout

let time = function timer(){alert('这是一次性定时任务')};
setTimeout(timer,2000)
clearTimeout(time)  // 上面的定时任务还没到触发就会被这条语句所取消
循环触发

每隔一段时间循环触发;可以通过函数嵌套,指定弹窗次数

let timer2 = setInterval(function timer2(){alert('呼死你')},3000);
clearInterval(timer2)  // 取消循环定时任务

三、DOM

3.1、DOM简介

DOM,document object model,即文档对象模型。当web页面被加载时,浏览器会创建该页面的DOM。DOM模型通常被构造为对象的树,下面是一张引用自博客园json的图片,原博客地址:https://www.cnblogs.com/Dominic-Ji/p/9121560.html

所有标签都可以称之为节点,具体可自行搜索查阅,因为我们是Python全栈开发,并不要求对前端有深刻的了解。

DOM功能很强大,它可以改变页面的所有HTML元素和属性、CSS样式、对所有事件作出反应!DOM操作的是标签,而一个HTML页面上的标签有很多,所以我们需要先学如何查找标签,再学DOM操作标签。

DOM操作需要用关键字document,地位相当于bom的window!

3.2、查找标签

按照JavaScript的规范,当你用变量名指代标签对象的时候,一般推荐书写成XXXEl,比如divEle。

3.2.1、直接查找
id查找
document.getElementById('d1')  // 括号内填标签的id值即可
类查找
document.getElementsByClassName('.c1')  // 括号内填标签的class值即可
标签查找
document.getElementsByTagName('div')  // 括号内填标签名即可获取标签的合集
HTMLCollection(3) [div, div.cover, div.modal]
3.2.2、间接查找

间接查找,顾名思义,要通过媒介才能进行查找,在这里是要先为变量名赋予标签对象再进行查找的意思。

let inputEle = document.getElementById('d2');
parentElement

找所有祖辈

pEle.parentElement
children

找所有后代

pEle.children
HTMLCollection(2) [p#d4, p, d4: p#d4]
firstchildren

找大儿子

pEle.firstElementChild
<p id="d4"></p>
lastchildren

找小儿子

pEle.lastElementChild
<p></p>
nextElementSibling

找弟弟

pEle.nextElementSibling
<p></p>

3.3、DOM节点操作

通过DOM操作,可以动态地创建img标签,并且给标签加属性,最后将标签添加到文本中。节点即是标签。

3.3.1、创建节点
let imgEle = document.createElement('img');
3.3.2、为节点加属性
let pEle = document.getElementById('d4');"https://blog.sanxi.info/upload/2021/01/0-_7_-c98f8c96538e473bbdc517247ec8a8bd.png"
imgEle.name = '回龙山云海';  // 第一种添加属性方式
"回龙山云海"
imgEle.setAttribute('name','cloud')  // 第二种
undefined
imgEle
<img src="https://blog.sanxi.info/upload/2021/01/0-_7_-c98f8c96538e473bbdc517247ec8a8bd.png" name="cloud">
3.3.3、添加节点
插入标签内尾部
let divEle = document.getElementById('d3');  // 将img标签插入div的尾部
undefined
divEle.appendChild(imgEle);
<img src="https://blog.sanxi.info/upload/2021/01/0-_7_-c98f8c96538e473bbdc517247ec8a8bd.png" name="cloud">
插入指定标签的前面
let pEle = document.getElementById('d4');  // 把img标签插入div内的p标签前面
undefined
divEle.insertBefore(imgEle,pEle);
<img src="https://blog.sanxi.info/upload/2021/01/0-_7_-c98f8c96538e473bbdc517247ec8a8bd.png">
3.3.4、删除节点

通过父标签调用remove方法来移除子节点标签

divEle.removeChild(imgEle);
<img src=​"https:​/​/​blog.sanxi.info/​upload/​2021/​01/​0-_7_-c98f8c96538e473bbdc517247ec8a8bd.png">​
3.3.5、替换节点标签

替换掉父标签内指定的节点标签

divEle.replaceChild(imgEle,pEle);
<p id="d4"></p>
3.3.6、属性节点操作
获取节点文本
let divEle = document.getElementById('d3');
undefined
divEle.innerText  // 获取标签内部所有文本内容
"我是div"
divEle.innerHTML  // 获取标签内部的所有文本、标签信息
"我是div
            <p id="d4"></p>
            <p></p>
        "
设置节点文本
divEle.innerText = '改下文本'
"改下文本"
divEle.innerText
"改下文本"
divEle.innerHTML = '<p>老色批了</p>'  // 因为HTML能识别标签信息,所以会替换标签
"<p>老色批了</p>"
divEle.innerHTML
"<p>老色批了</p>"
divEle
<div id="d3"><p>老色批了</p></div>
获取/设置属性
divEle.setAttribute('name','sanxi');  // 设置标签属性值
undefined
divEle.getAttribute('name');  // 获取标签属性值
"sanxi"
divEle.removeAttribute('name');  // 移除属性
undefined
divEle.getAttribute('name');
null
3.3.7、获取值操作

适用于input、select、textarea标签。

// input标签
let inputEle = document.getElementById('d5');
undefined
inputEle.value  // 获取用户所输入数据
"sanxi666"
// select标签
let selectEle = document.getElementById('d6');
undefined
selectEle.value
"chrystal"
// textarea
let textEle = document.getElementById('d7');
undefined
textEle.value
"这个很懒,什么都没留下。"

3.4、class操作

class增删查改
let classEle = document.getElementById('d3');
classEle.classList.add('name');  // 为标签添加类属性
classEle.className  // 查看标签所有类属性
"name"
classEle.classList.remove('name');  // 移除指定类属性
undefined
classEle.classList.contains('name');  // 判断是否存在指定类属性
false
classEle.classList.toggle('name');  // 存在指定类属性则删除,不存在则添加
true
classEle.classList.toggle('name');
false
style操作
let divEle = document.getElementById('d3');
undefined
divEle.style.height = '100px';
"100px"
divEle.style.width = '100px';
"100px"

3.5、事件

事件即满足某个事先设定的条件,则自动触发预设的动作,这就是事件,跟zabbix的trigger还是很类似的。

onclick        当用户点击某个对象时调用的事件句柄。
ondblclick     当用户双击某个对象时调用的事件句柄。

onfocus        元素获得焦点。               // 练习:输入框
onblur         元素失去焦点。               应用场景:用于表单验证,用户离开某个输入框时,代表已经输入完了,我们可以对它进行验证.
onchange       域的内容被改变。             应用场景:通常用于表单元素,当元素内容被改变时触发.(select联动)

onkeydown      某个键盘按键被按下。          应用场景: 当用户在最后一个输入框按下回车按键时,表单提交.
onkeypress     某个键盘按键被按下并松开。
onkeyup        某个键盘按键被松开。
onload         一张页面或一幅图像完成加载。
onmousedown    鼠标按钮被按下。
onmousemove    鼠标被移动。
onmouseout     鼠标从某元素移开。
onmouseover    鼠标移到某元素之上。

onselect      在文本框中的文本被选中时发生。
onsubmit      确认按钮被点击,使用的对象是form。
3.5.1、绑定事件的两种方式

script标签既可以放在head内,也可以放在body内,通常都是放在body内的最底部,这样可以等待页面加载完毕后再执行代码。

方式一

函数中的this为实参,指代触发事件的标签;函数定义过程的ts为形参

<div id="d3" onclick="changeColor(this);">点我更改颜色</div>
<script>
    function changeColor(ts) {
    ts.style.backgroundColor='blue'
}
</script>
方式二
<script>
let divEle = document.getElementById('d3');
divEle.onclick=function upgrade() {
alert('是兄弟就来砍我')
}
</script>

3.6、事件案例

开关灯案例
<style>
    .c1 {  // 画圆
    border: 0px;
    height: 100px;
    width: 100px;
    border-radius: 50%;
    }
    .bg_green{  // 圆圈背景色
    background-color: green;
    }
    .bg_red {
    background-color: red;
    }
</style>
<body>
    <div id="d1" class="c1 bg_red bg_green"></div>
    <button id="b1">变色</button> 
        
    <script>
        let divEle = document.getElementById('d1')
        let btnEle = document.getElementById('b1')
        btnEle.onclick=function () {  // 鼠标点击按钮时触发动作去更改标签的背景色
            divEle.classList.toggle('bg_red')
        }        
    </script>
</body>
input框获取焦点失去焦点案例
<body>
    <input type="text" id="i1" value="由字母数字组成">
        
    <script>
        let inputEle = document.getElementById('i1')
        inputEle.onfocus=function(){inputEle.value=''}  // 获取焦点后执行函数代码
        inputEle.onblur=function(){inputEle.value='不要走,决战到天亮'}  // 失去焦点后执行函数代码
    </script>
</body>
模拟选择省市

文本域变化事件,即change事件

<script>
    let provinceEle = document.getElementById('s1')
    let cityEle = document.getElementById('s2')
    data = {
        '广东':['广州','深圳','佛山'],
        '湖南':['长沙','郴州','株洲'],
        '福建':['福州','泉州','厦门']
    }
// 给下拉框循环添加option
    for (let key in data) {
        let optionEle = document.createElement('option')
        optionEle.innerText = key
        optionEle.value = key
        provinceEle.appendChild(optionEle)
    }
    provinceEle.onchange = function () {
        // 获取用户选择的省份
        let province = provinceEle.value
        console.log(province)
        // 获取用户选择的城市
        let citylist = data[province]
        // 清除select中所有option,否则城市会混乱在一起
        cityEle.innerHTML=''
        // 循环取值,将省份对应的市渲染到第二个select框中
        for (let index = 0; index < citylist.length; index++) {
            // 创建option标签
            let city = citylist[index]
             // 创建option标签
            let optionEle = document.createElement('option')
            // 设置文本
            optionEle.innerText=city
            // 设置value
            optionEle.value=city
            // 将创建好的option添加到第二个select中
            cityEle.appendChild(optionEle)
        }
    }
</script>
世间微尘里 独爱茶酒中