Dom和Bom
JS-Web-API
知识点
DOM
- DOM本质
- DOM节点操作
- DOM结构操作
- DOM性能
Q: DOM的本质
A: 了解HTML首先要描述xml的概念 xml, 是一种可扩展的标志性结构语言,是一棵树 html是一种特定的xml,规定了一些标签的名称 html是树型结构 dom的本质是从Html语言解析出的一颗树 可以认为 DOM 就是 JS 能识别的 HTML 结构,一个普通的 JS 对象或者数组。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>hello world</div>
</body>
</html>Q: 获取节点有哪些方法
A:
const a1 = document.getElementById('a1') // 通过元素id选择
const titleList = document.getElementsByClassName('.title') // 通过class选择
const pList = document.getElementsByTagName('p') // 选择所有p元素。返回的是一个集合
const divList= document.querySelectorAll('div') //TODO这里应该不对 选择所有p元素。返回的是一个集合getElementsByTagName方法返回的是HTMLCollection对象。
querySelectorAll方法返回的是NodeList对象。
两者的区别:
- getElementsByTagName 获取的是动态集合,querySelector获取的是静态集合。
- getElementsByTagName更快
Q; 什么是property?(引用小册)
A:
property: dom是一个对象。通过getxxxxbyxxx方法获取到对象以后,可以通过js修改一些属性,这些属性就是property。property是JS范畴的属性,符合JS的标准 如以下代码,style就是property
var pList = document.querySelectorAll('p')
var p = pList[0]
console.log(p.style.width) // 获取样式Q: 什么是attribute?(引用小册)
A:
attribute:
property 的获取和修改,是直接改变 JS 对象,而 attribute 是直接改变 HTML 的属性,两种有很大的区别。attribute 就是对 HTML 属性的 get 和 set,和 DOM 节点的 JS 范畴的 property 没有关系。
var pList = document.querySelectorAll('p')
var p = pList[0]
p.getAttribute('data-name')
p.setAttribute('data-name', 'juejin')
p.getAttribute('style')
p.setAttribute('style', 'font-size:30px;')Q: attribute和property的区别(引用课程)
A:
- property:修改对象属性,不会体现到html结构中
- attribute: 修改html属性,会改变html结构
- 两者都有可能引起DOM重新渲染
Q: 新增/插入节点
A:
// 创建节点,然后新增节点
const div = document.getElementById('div')
const span1 = document.createElement('span')
div.appendChild(span1)
// 如果选择已有节点,就是移动节点
const span2 = document.getElementById('span')
div.appendChild(span2)Q: 删除节点
A:
const ele = document.getElementById('title')
const child = ele.childNodes
ele.removeChild(child[0])Q: 获取子元素列表
A:
const ele = document.getElementById('title')
const child = ele.childNodesQ: 获取父元素
A:
const ele = document.getElementById('title')
const parent = ele.parentNodeQ: 优化Dom性能(引用)
- 避免频繁的操作Dom
- 可以对一些需要重复利用的做缓存
- 将频繁操作改为一次性操作
BOM
Q: 怎样获得用户用的哪个浏览器
A:
const uaInfo = navigator.userAgent
const isSafari = uaInfo.indexOf('Safari')Q: 如何获得屏幕的宽和高
A:
const screenWidth = screen.width
const screenHeight = screen.heightQ: location
A:
Q: 怎样让浏览器前进和后退
A:
history.back()
history.forward()题目
Q:一次性插入多个DOM节点,考虑性能
A:
利用document.createDocumentFragment(),把多次的操作转换为一次操作
const fragment = document.createDocumentFragment()
// 把三个节点放入fragment中
fragment.appendChild(span1)
fragment.appendChild(span2)
fragment.appendChild(span3)
// 放完之后,整体放入DOM树中
div.appendChild(fragment)事件绑定
知识点
- 事件绑定
- 事件冒泡
- 事件代理
Q: 如何进行事件绑定?
A:
const btn = document.getElementById('button')
btn.addEventListener('click', event => {
alert('clicked')
})Q: 什么是事件冒泡
A: 事件会像冒泡一样,顺着触发元素,一层一层往上冒 就是在上级能监听到,bindEvent其实只是监听 事件冒泡就是说,它的上级元素也能监听到那个事件
事件代理也是应用事件冒泡的机制
Q: 怎样阻止默认操作?
A: 阻止默认事件,例如阻止a的跳转
e.preventDefault // 阻止默认事件Q: 怎样阻止事件冒泡?
A:
e.stopPropagation() // 阻止事件冒泡Q: 什么是事件代理?
A: 事件代理,就是当不好确定事件绑定在哪里的时候, 可以统一绑定在父元素上 然后父元素上要加一些判断和操作, 一般用在瀑布流
它的好处是可以少写一些代码,因为不用每个标签都绑定事件, 所以也可以减少浏览器内存占用
题目
Q: 编写一个通用的事件监听函数
A:
function bindEvent(ele, type, selector, fn) {
// 如果是有三个参数的话,第三个参数就为fn
if(fn == null) {
fn = selector
selector =null
}
ele.addEventListener(type, event => {
const target = event.target
if(selector) {
// 代理绑定,用matched匹配元素
// 用call传入target绑定this
if(target.matches(selector)) {
fn.call(target, event)
} else {
fn.call(target, event)
}
}
})
}Q: 无限下拉的图片列表,如何监听每个图片的点击?
A:
- 使用事件代理
- 通过e.target获取触发元素
- 用matches来判断是否触发元素