JS复习1.0主要为js基础语法中较重要的知识如数组、日期、对象等:详见JavaScript复习1.0
JS复习2.0主要为Web APIs中的DOM(页面文档对象模型)
JS复习3.0主要为Web APIs中的BOM(浏览器对象模型)与offset、client、scroll家族系列:详见JavaScript复习3.0
文章目录
DOM
1. 利用DOM获取元素
获取普通元素
- 通过ID获取:
document.getElementById('')
- 通过标签名获取:
document.getElementsByTagName('')
注意返回的是一个伪数组,要获取具体的某个元素记得加下标 - 通过类名获取:
document. getElementsByClassName('')
返回伪数组 - 通过
querySelector
:document.querySelector('符号+选择器')
返回指定选择器的第一个元素对象,需要加符号. #
- 通过
querySelectorAll()
返回指定选择器的所有元素对象集合(返回伪数组)
获取特殊元素body、HTML
获取body 元素:document.body
获取html 元素:document.documentElement
2. 自定义属性操作
设置自定义属性:element.setAttribute('属性', '值')
获取自定义属性:element.getAttribute('属性')
移除自定义属性:element.removeAttribute('属性')
<div></div>
<script>
var div = document.querySelector('div')
div.setAttribute('myIndex',1);
console.log( div.getAttribute('myIndex'));//1
div.removeAttribute('myIndex');
console.log( div.getAttribute('myIndex'));//null
</script>
自定义属性多用于给ul的li设置index值
H5的自定义属性:H5规定自定义属性以data-开头
做为属性名并且赋值
H5自定义属性可以用element.getAttribute('属性')
获取,也可以用element.dataset.属性名(即data-后面的值)
或者 element.dataset['属性名']
获取(这两种方法IE11才支持)
若H5自定义属性名有多个-链接的单词,获取时采取驼峰命名法
<div data-index="1" data-list-name="f"></div>
<script>
var div = document.querySelector('div');
console.log(div.getAttribute('data-index'));//1
console.log(div.getAttribute('data-list-name'));//f
// dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.dataset.list-name);//NaN
console.log(div.dataset.listName);//f
console.log(div.dataset['listName']);//f
</script>
3.节点操作
父节点
获取父节点:node.parentNode
,返回某节点最近的一个父级节点,如果找不到父节点就返回为 null
<div class="grandpa">
<div class="father">
<span class="son"></span>
</div>
</div>
<script>
var son = document.querySelector('.son');
console.log(son.parentNode); //返回father节点
console.log(son.parentNode.parentNode);//返回grandpa节点
</script>
子节点
parentNode.childNodes
返回包含指定节点的子节点的集合,包括元素节点,文本节点等(几乎不用)
parentNode.children
返回所有子元素节点集合(伪数组形式),重点掌握
兄弟节点
node.nextSibling
:返回当前元素的下一个兄弟节点,含所有的节点(少用)
node.previousSibling
:返回当前元素上一个兄弟节点,包含所有的节点(少用)
node.nextElementSibling
返回当前元素下一个兄弟元素节点
node.previousElementSibling
: 返回当前元素上一个兄弟元素节点
创建节点
document.createElement(‘tagName’)
通过
createDocumentFragment或innerHTML
批量操作dom会使性能更好
innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
使用innerHTML :
function fn() {
var str = '';
for (var i = 0; i < 1000; i++) {
str +=`<a href="">使用innerHTML</a>`
}
document.body.innerHTML = str
//建议先把所有字符串拼接好再一次性赋值给元素,这样性能比每次都赋值好
}
使用Document.createDocumentFragment():先在fragment中添加好所有的节点再赋值给父元素添加
DocumentFragments 是 DOM 节点。它们不是主 DOM 树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到 DOM 树。在 DOM 树中,文档片段被其所有的子元素所代替。
因为文档片段存在于内存中,并不在 DOM 树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
function fn2() {
var fragment = document.createDocumentFragment()
for (var i = 0; i < 1000; i++) {
var li = document.createElement('li')
li.innerHTML = `<a href="">使用innerHTML</a>`
fragment.appendChild(li)
}
document.body.appendChild (fragment)
}
添加节点
node.appendChild(要添加的节点) :将一个节点添加到指定父节点的子节点列表末尾
var ul = document.querySelector('ul');
ul.appendChild(li)
node.insertBefore(child, 指定元素):将一个节点添加到父节点的指定子节点前面
var li = document.createElement('li');
li.innerHTML = '我会加在ul的第二个子元素位置'
ul.insertBefore(li, ul.children[1]);
element.insertAdjacentHTML(position, text): `insertAdjacentHTML() `方法将指定的文本解析为 Element 元素,并将结果节点插入到 DOM 树中的指定位置。它不会重新解析它正在使用的元素
position:表示插入内容相对于元素的位置,并且必须是以下字符串之一
beforebegin:元素自身的前面
afterbegin:插入元素内部的第一个子节点之前。
beforeend:插入元素内部的最后一个子节点之后。
afterend:元素自身的后面。
<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
text:要被解析为 HTML 或 XML 元素,并插入到 DOM 树中的 DOMString
// 原为 <div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');
// 此时,新结构变成:
// <div id="one">one</div><div id="two">two</div>
删除节点
node.removeChild()从 DOM 中删除一个子节点,返回删除的节点
克隆节点
node.cloneNode() 克隆节点node
如果括号参数为空或者为 false 则是浅拷贝,即只复制第一层标签不复制里面的内容
如果括号参数为 true 则是深度拷贝,会复制节点本身以及里面所有的子节点(包括文本节点等)
<ul>
<li>1 <a href="">点击</a></li>
<li>2</li>
</ul>
<script>
var ul = document.querySelector('ul');
var li = ul.children[0].cloneNode(true);
ul.appendChild(li);
var li2 = ul.children[0].cloneNode()
ul.appendChild(li2)
</script>
效果如下,浅拷贝时只克隆了li标签:
替换节点
parentNode.replaceChild(newChild, oldChild),用指定的节点替换当前节点的一个子节点,并返回被替换掉的节点。
节点操作综合案例
制作一个简单的发布留言案例
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul></ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul')
//添加节点函数
function add(value) {
let li = document.createElement('li');
console.log(value);
li.innerHTML = `${value}<a href="#">删除</a>`;
ul.prepend(li);
}
btn.onclick = function () {
let value = text.value;
if (!value) {
alert('发布内容不能为空');
return;
}
add(value)
text.value ='';
text.focus();
let deletValue = document.querySelectorAll('a');
let cloneValue = document.querySelectorAll('.clone');
//删除操作
for (let i = 0; i < deletValue.length; i++) {
deletValue[i].onclick = function () {
this.parentNode.remove();
};
}
};
</script>
4. 与事件相关内容
onclick
注册事件具有唯一性
:同一个元素同一个事件只能设置一个处理函数,以最后注册的那个函数为主
删除事件:eventTarget.onclick = null
addEventListener()
eventTarget.addEventListener(type, listener[, useCapture])
type:事件类型字符串,比如 click、blur等
listener:事件处理函数,事件发生时会调用该监听函数
useCapture:可选参数,是一个布尔值。如果是 true表示在事件捕获阶段(从外到内)调用事件处理函数函数;如果是 false(默认false)表示在事件冒泡阶段(从内到外)调用事件处理函数
同一个元素同一个事件可以注册多个监听器,按注册顺序依次执行
删除事件:eventTarget.removeEventListener(type, listener[, useCapture]);
事件对象
e.target :返回的是触发事件的对象(元素),如点击哪个元素则返回哪个
this: 返回的是绑定事件的对象(元素),如哪个元素绑定了点击事件则返回哪个
点击ul的li:
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
console.log(this); // ul 绑定了事件 ,故this 就指向ul
console.log(e.currentTarget);//支持默认为冒泡,指向target的父元素ul
console.log(e.target);//点击的是li,故 e.target 指向的是li
})
阻止默认行为(事件):
若用addEventListener方法: e.preventDefault()
若用onckick等方法:return false
阻止事件冒泡: e.stopPropagation()
事件委托
原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
如给 ul 注册点击事件,然后利用e.target 找到当前点击的 li
作用:只操作了一次 DOM ,提高了程序的性能
ul.addEventListener('click',function(e){
e.target.style.color = 'red'
})
鼠标事件
e.client: 鼠标在可视区的x和y坐标,返回的值是相对于屏幕可见区域的坐标,如果页面有滚动条,被滚动条隐藏的部分不进行计算
e.page: 鼠标在页面文档的x和y坐标,文档的左上角为(0,0),向右为正,向下为正
e.screen: 鼠标在电脑屏幕的x和y坐标
e.offset返回的是元素距离带有定位的最近父元素的位置,若没有定位的父元素就是body
注意:以上四种方法返回的均为数值,不带单位
键盘事件
keypress :按键按下的时候触发 不能识别功能键 比如 ctrl shift 左右箭头(此事件官网说明已弃用)
警告:由于此事件已被弃用,您应该使用beforeinput或keydown代替
keydown :按键按下的时候触发 能识别功能键
keyup: 按键弹起的时候触发
注意:onkeydown 和 onkeyup 不区分字母大小写
KeyboardEvent.keyCode:返回的ASCII码值,可用来来判断用户按下了哪个键(不再推荐使用此功能,应该使用KeyboardEvent.code
)
KeyboardEvent.code:该属性表示键盘上的物理键,返回一个不会被键盘布局或修饰键状态改变的值,要确定所按键盘的键字符需用KeyboardEvent.key
属性,此方法区分大小写
当您希望根据输入设备上的物理位置而不是与这些键关联的字符来处理键时,此属性很有用;这在编写代码以处理使用键盘上的键模拟类似游戏手柄的环境的游戏输入时尤其常见。但是请注意,您不能使用 报告的值KeyboardEvent.code来确定击键生成的字符,因为键码的名称可能与键上打印的实际字符或按下键时计算机生成的实际字符不匹配.
document.addEventListener('keydown', function(e) {
console.log(e.key);
console.log(e.code);
})
效果如图,输出的为按键的物理位置键:
案例:完成按下s键聚焦搜索框后按回车键搜索功能(回车键ASCII码值为13,s键ASCII码为83):
<input type="search">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup', function(e) {
// 用e.keyCode方法
// if(e.keyCode === 83){
// search.focus()
// }
// if (e.keyCode === 13) {
// window.location.href = `https://www.baidu.com/s?&wd=${search.value}`
// }
//用KeyboardEvent.code方法
if(e.code === 'KeyS'){
//这里用e.code是因为s有大小写,都在同个地方KeyS,也可写成e.key === 'S'||e.key ==='s'
search.focus()
}
if (e.key==='Enter') {
//这里用e.key是因为回车键均为Enter,但位置不同,也可写成e.code === 'Enter'||e.code === 'NumpadEnter'
window.location.href = `https://www.baidu.com/s?&wd=${search.value}`
}
})
</script>
参考资料
MDN createDocumentFragment
MDN element.insertAdjacentHTML
MDN KeyboardEvent.code