查询元素
var dom=document;
document得到dom对象
var banner=document.getElementById('page-banner');
查找id="page-banner"的元素
var titles= document.getElementsByClassName('title');
查找class="title"的所有元素,返回一个list,titles[0]表示列表第一个元素
var lis = document.getElementsByTagName('li');
按照标签查找元素,返回一个list
循环遍历元素
for (let i = 0; i < titles.length; i++) {
console.log(titles[i]);
}
Array.from(titles).forEach(function (item) {
console.log(item);
});
forEach是js中循环遍历数组常用方法,但不能直接用于遍历dom集合,Array.from()可以将dom集合变化为普通数组
css选择器
const wrap = document.querySelector("#book-list li:nth-child(2) .name");
用css语法选择dom元素,注意:以上方法只返回匹配的第一个元素
var books = document.querySelectorAll("#book-list li .name");
返回匹配元素的集合
获取文本
var books = document.querySelectorAll("#book-list li .name");
Array.from(books).forEach(function (book) {
console.log(book.textContent);
});
.textContent获取元素的文本
修改文本
var books = document.querySelectorAll("#book-list li .name");
Array.from(books).forEach(function (book) {
book.textContent = "修改后的文本";
});
.textContent在等号左边表示修改文本
innerHTML
const bookList = document.querySelector("#book-list");
bookList.innerHTML = "<h2>more...</h2>";
.innerHTML可以修改dom元素
结点类型
const banner = document.querySelector("#page-banner");
console.log("#page-banner node type is ", banner.nodeType);
.nodeType返回节点的类型,用数字表示。以下是对照表https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
结点名字
const banner = document.querySelector("#page-banner");
console.log("#page-banner node name is ", banner.nodeName);
// #page-banner node name is DIV
是否有子结点
const banner = document.querySelector("#page-banner");
console.log("#page-banner has child nodes", banner.hasChildNodes());
// true
返回bool值
拷贝结点
const banner = document.querySelector("#page-banner");
const clonedBanner = banner.cloneNode(true);
console.log(clonedBanner);
//<div id="page-banner">
// <h1 class="title">Bookorama</h1>
// <p>Books for Ninjas</p>
// <form id="search-books">
// <input type="text" //placeholder="Search books..." />
// </form>
//</div>
banner.cloneNode(true)为深拷贝,拷贝该结点及其子结点,改为false则只拷贝当前结点
获取当前结点的父结点
- parentNode
const bookList = document.querySelector("#book-list");
console.log("the parent is :", bookList.parentNode);
//the parent is : <div id="wrapper">…</div><header>…</header><div id="book-list">…</div><form id="add-book">…</form></div>
- parentElement
const bookList = document.querySelector("#book-list");
console.log("the parent is :", bookList.parentElement);
两者在大部分情况下是相同的,在没有父元素时不同
document.documentElement.parentNode; // the document node
document.documentElement.parentElement; // null
获取子结点
const bookList = document.querySelector("#book-list");
console.log(bookList.childNodes);
// [text, h2.title, text, ul, text]
.childNodes返回子结点组成的数组,结点中包括换行符
const bookList = document.querySelector("#book-list");
console.log(bookList.children);
.children获取除了换行符的子结点
获取兄弟结点
const bookList = document.querySelector("#book-list");
console.log(bookList.nextSibling);
console.log(bookList.nextElementSibling);
.nextSibling和.nextElementSibling都返回相邻兄弟结点,后者不包含换行符。此外获取前面兄弟结点有.previousSibling和.previousElementSibling
事件
文档加载完毕触发事件
<body onload="checkCookies()"></body>
onload=在文档加载完执行
监听按钮点击
<button onclick="changeColor(this)">click to change</button>
onclick=设置点击事件处理函数
文本输入事件
<input type="text" oninput="textChange()" />
oninput=在文本输入时触发
鼠标事件
<div onmouseover="mOver(this)" onmouseout="mOut(this)">Mouse Over Me</div>
在鼠标悬浮和离开时触发
小结:设置监听器的三种方式
方法一:
<button onclick="changeColor(this)">click to change</button>
方法二:
element.addEventListener("event", function, useCapture);
方法三:
element.onclick=function(){}
键盘事件
// filter books
const searchBar = document.forms["search-books"].querySelector("input");
searchBar.addEventListener("keyup", (e) => {
const term = e.target.value.toLowerCase();
const books = list.getElementsByTagName("li");
Array.from(books).forEach((book) => {
const title = book.firstElementChild.textContent;
if (title.toLowerCase().indexOf(term) != -1) {
book.style.display = "block";
} else {
book.style.display = "none";
}
});
});
"keyup"代表键盘事件,.firstElementChild得到第一个子元素
// tabbed content
const tabs = document.querySelector(".tabs");
const panels = document.querySelectorAll(".panel");
tabs.addEventListener("click", (e) => {
if (e.target.tagName == "LI") {
const targetPanel = document.querySelector(e.target.dataset.target);
Array.from(panels).forEach((panel) => {
if (panel == targetPanel) {
panel.classList.add("active");
} else {
panel.classList.remove("active");
}
});
}
});
监听事件删除结点
var btns = document.querySelectorAll("#book-list .delete");
Array.from(btns).forEach(function (btn) {
btn.addEventListener("click", function (e) {
const li = e.target.parentElement;
li.parentElement.removeChild(li);
});
});
e.target是触发事件的元素,removeChild(li)指定删除的结点
阻止默认事件
const link = document.querySelector("#page-banner a");
link.addEventListener("click", function (e) {
e.preventDefault();
});
阻止a元素跳转事件
Event Bubbling
const list = document.querySelector("#book-list ul");
list.addEventListener("click", function (e) {
if (e.target.className == "delete") {
const li = e.target.parentElement;
list.removeChild(li);
}
});
监听每个li元素效率较低,较好的做法是监听它们父元素
submit事件
var forms = document.forms;
document.forms返回所有表单的列表,可以通过id或者下标获得单个form元素,如:forms[0],forms['add-book']
点击提交按钮后会刷新页面,监听提交事件(submit)可以阻止页面刷新
const addForm = document.forms["add-book"];
addForm.addEventListener("submit", function (e) {
e.preventDefault();
const value = addForm.querySelector("input[type='text']").value;
console.log(value);
});
.value获得input的值
屏幕滚动事件
window.onscroll = function (){}监听屏幕滚动
属性 | 说明 |
---|---|
document.documentElement.offsetHeight | html可视区高度 |
element.offsetHeight | 元素的css高度 (自身高度、边框、内边距和元素的水平滚动条),不包括伪元素,隐藏元素为0 |
element.offsetWidth | 元素css宽度(自身宽度height、边框、内边距、竖直方向滚动条) |
element.clientHeight | 元素内部高度(自身高度height、内边距,不包括滚动条、边框、外边距)。内联元素和没有css样式的为0 |
element.clientWidth | 元素内部宽度(自身高度、内边距,不包括滚动条、边框、外边距)。内联元素和没有css样式的为0 |
document.documentElement.scrollTop | 文档顶部到可视区顶部距离(文档向上超出可视区高度) |
element.scrollTop | 元素顶部到可视区顶部距离 |
document.body.scrollHeight | body元素在没有滚动条时高度 |
element.scrollHeight | 元素在没有滚动条下高度 |
window.innerHeight | 窗口可视区高度 |
window.innerWidth | 窗口可视区宽度 |
判断元素是否滚动到底
element.scrollHeight - element.scrollTop === element.clientHeight
DOM操作
添加元素到dom中注意三项内容:dom元素、样式、内容
添加元素
const addForm = document.forms["add-book"];
addForm.addEventListener("submit", function (e) {
e.preventDefault();
const value = addForm.querySelector("input[type='text']").value;
// create elements
const li = document.createElement("li");
const bookName = document.createElement("span");
const deleteBtn = document.createElement("span");
// add content
deleteBtn.textContent = "delete";
bookName.textContent = value;
// append to document
li.appendChild(bookName);
li.appendChild(deleteBtn);
const list = document.querySelector("#book-list ul");
list.appendChild(li);
});
.createElement创建元素,.appendChild添加结点,document.createTextNode("some text")创建文本结点
插入结点位置
var parent = document.getElementById("div1");
var p2 = document.getElementById("p2");
var p1 = document.getElementById("p1");
parent.insertBefore(p2, p1);
.insertBefore(p2, p1)在p2前面插入p1元素
替换结点
var parent = document.getElementById("div1");
var p2 = document.getElementById("p2");
var p1 = document.getElementById("p1");
parent.replaceChild(p1, p2);
.replaceChild(new, old)
删除元素
parent.removeChild(p1);
.removeChild(ele)删除元素ele
改变结点样式
.style获取元素所有样式
var li = document.querySelector("li:last-child");
li.style.color = "red";
li.style.marginTop = "60px";
.style.attr=用于修改结点样式,属性名用驼峰命名法
其他写法:
.style.cssText="color:blue;"
.setAttribute("style", "color:blue;")
var li = document.querySelector("li:last-child");
li.className = "test1";
.className= 用于修改类名,会覆盖之前类型
const addForm = document.forms["add-book"];
addForm.addEventListener("submit", function (e) {
e.preventDefault();
const value = addForm.querySelector("input[type='text']").value;
// create elements
const li = document.createElement("li");
const bookName = document.createElement("span");
const deleteBtn = document.createElement("span");
// add content
deleteBtn.textContent = "delete";
bookName.textContent = value;
// add classes
bookName.classList.add("name");
deleteBtn.classList.add("delete");
// append to document
li.appendChild(bookName);
li.appendChild(deleteBtn);
const list = document.querySelector("#book-list ul");
list.appendChild(li);
});
.classList.add() 在原来基础上添加新的类名,删除用.classList.remove()
属性
var book = document.querySelector("li:first-child .name");
console.log(book.getAttribute("class"));
.getAttribute()得到结点属性值
var book = document.querySelector("li:first-child .name");
book.setAttribute("class", "name-2");
console.log(book.getAttribute("class"));
.setAttribute(attr, value)设置结点属性
var book = document.querySelector("li:first-child .name");
console.log(book.hasAttribute("class"));
.hasAttribute()判断元素是否具有某种属性
var book = document.querySelector("li:first-child .name");
book.removeAttribute("class");
.removeAttribute(attr)删除属性
checkbox
const hideBox = document.querySelector("#hide");
hideBox.addEventListener("change", function (e) {
if (hideBox.checked) {
list.style.display = "none";
} else {
list.style.display = "initial";
}
});
.checked()判断多选框是否选中
自定义属性的值
使用 data-* 属性来嵌入自定义数据
<element data-属性名="somevalue">
<ul class="tabs">
<li data-target="#about" class="active">About</li>
<li data-target="#contact">Contact</li>
</ul>
const tabs = document.querySelector(".tabs");
const panels = document.querySelectorAll(".panel");
tabs.addEventListener("click", (e) => {
if (e.target.tagName == "LI") {
const targetPanel = document.querySelector(e.target.dataset.target);
console.log(e.target.dataset);
Array.from(panels).forEach((panel) => {
if (panel == targetPanel) {
panel.classList.add("active");
} else {
panel.classList.remove("active");
}
});
}
});
e.target.dataset获取被点击元素的所有自定义数据,e.target.dataset.target获取属性名为data-target的值
注意:以上例子也说明,不要给子项每一个设置监听器,而应该把监听任务交给父元素
DOM加载完成后执行JS
js在dom加载完成之前执行会引发许多问题,如不能获取dom元素,解决方法之一是在body最后引入js文件,另一种方法如下
document.addEventListener('DOMContentLoaded', function(){
// Write your code here ...
}
JS动画
<button onclick="myMove()">Click Me</button>
function myMove() {
var elem = document.getElementById("myAnimation");
var pos = 0;
var id = setInterval(frame, 10);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
setInterval(frame, 10),每10秒执行一次frame,该函数返回id,clearInterval(id)用于清除定时器
JS帧动画
var item = document.getElementById('item');
item.animate([
{ transform: 'scale(1)', background: 'red', opacity: 1, offset: 0 },
{ transform: 'scale(.5) rotate(270deg)', background: 'blue', opacity: .5, offset: .2 },
{ transform: 'scale(1) rotate(0deg)', background: 'red', opacity: 1, offset: 1 },
], {
duration: 2000, //milliseconds
easing: 'ease-in-out', //'linear', a bezier curve, etc.
delay: 10, //milliseconds
iterations: Infinity, //or a number
direction: 'alternate', //'normal', 'reverse', etc.
fill: 'forwards' //'backwards', 'both', 'none', 'auto'
});
.animate(frame,params)第一个参数是一个数组,里面是每一帧形态,offset表示该帧持续时间占总时间比例
JS继续上一次动画
window.requestAnimationFrame()告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
element.style.left = Math.min(progress / 10, 200) + 'px';
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
Window
window.addEventListener('resize', update);
var x = window.document.getElementById("demo");
update();
function update() {
x.innerHTML = "Browser inner window width: " +
window.innerWidth + ", height: " + window.innerHeight + ".";
}
resize'在窗口缩放时触发,window.innerWidth是浏览器的宽度
网页跳转
window.open("www.jianshu.com");
alert、confirm、prompt
alert("I am an alert box!");
if (window.confirm("Press a button!")) {
console.log("You pressed OK!");
} else {
console.log("You pressed Cancel!");
}
var person = prompt("Please enter your name", "123");
Cookies、Local Storage、Session Storage
localStorage.setItem('lunch', 'cereal');
console.log(localStorage.getItem('breakfast'));
localStorage.removeItem('lunch');
localStorage.clear();
sessionStorage.setItem("run", "done");
sessionStorage.getItem("run");
sessionStorage.removeItem("run");
sessionStorage.clear();
document.cookie = "hello=true";
document.cookie = "doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT";
document.cookie = "person=beau; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/"
document.cookie = "person=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
console.log(document.cookie)
history
alert(window.history.length)
历史记录的长度
history.back()
后退一条历史记录
history.go(-1)
前进或后退历史记录
history.replaceState('code', null, 'http://codepen.io/');
console.log(history.state)
改变浏览器地址,不会加载页面,但会替换当前这条历史
history.pushState(null, null, "codepen");
改变浏览器地址,不会加载页面,但会写入浏览历史