JavaScript组成
-
ECMASCRIPT (基础语法)
-
DOM(文档对象模型)
-
BOM(浏览器对象模型)
-
DOM(Document Object Model): 文档对象模型
- 其实就是操作 html 中的标签的一些能力
- 我们可以操作哪些内容
- 获取一个元素
- 移除一个元素
- 创建一个元素
- 向页面里面添加一个元素
- 给元素绑定一些事件
- 获取元素的属性
- 给元素添加一些 css 样式
- ...
-
DOM 的核心对象就是 docuemnt 对象
-
document 对象是浏览器内置的一个对象,里面存储着专门用来操作元素的各种方法
-
DOM: 页面中的标签,我们通过 js 获取到以后,就把这个对象叫做 DOM 对象
-
获取一个元素
- 通过 js 代码来获取页面中的标签
- 获取到以后我们就可以操作这些标签了
getElementById
- getElementById 是通过标签的 id 名称来获取标签的
- 因为在一个页面中 id 是唯一的,所以获取到的就是一个元素
<body>
<div id="box"></div>
<script>
var box = document.getElementById('box')
console.log(box) // <div></div>
</script>
</body>
- 获取到的就是页面中的那个 id 为 box 的 div 标签
getElementsByClassName
- getElementsByClassName 是用过标签的 class 名称来获取标签的
- 因为页面中可能有多个元素的 class 名称一样,所以获取到的是一组元素
- 哪怕你获取的 class 只有一个,那也是获取一组元素,只不过这一组中只有一个 DOM 元素而已
<body>
<div class="box"></div>
<script>
var box = document.getElementsByClassName('box')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 获取到的是一组元素,是一个长得和数组一样的数据结构,但是不是数组,是伪数组
- 这个一组数据也是按照索引排列的,所以我们想要准确的拿到这个 div,需要用索引来获取
getElementsByTagName
- getElementsByTagName 是用过标签的 标签 名称来获取标签的
- 因为页面中可能有多个元素的 标签 名称一样,所以获取到的是一组元素
- 哪怕真的只有一个这个标签名,那么也是获取一组元素,只不过这一组中只有一个 DOM 元素而已
<body>
<div></div>
<script>
var box = document.getElementsByTagName('div')
console.log(box) // [<div></div>]
console.log(box[0]) // <div></div>
</script>
</body>
- 和 getElementsByClassName 一样,获取到的是一个长得很像数组的元素
- 必须要用索引才能得到准确的 DOM 元素
querySelector
- querySelector 是按照选择器的方式来获取元素
- 也就是说,按照我们写 css 的时候的选择器来获取
- 这个方法只能获取到一个元素,并且是页面中第一个满足条件的元素
console.log(document.querySelector('div')) // 获取页面中的第一个 div 元素
console.log(docuemnt.querySelector('.box')) // 获取页面中第一个有 box 类名的元素
console.log(document.querySelector('#box')) // 获取页面中第一个 id 名为 box 的元素
querySelectorAll
- querySelectorAll 是按照选择器的方式来获取元素
- 这个方法能获取到所有满足条件的元素,以一个伪数组的形式返回
console.log(document.querySelectorAll('div')) // 获取页面中的所有的 div 元素
console.log(docuemnt.querySelectorAll('.box')) // 获取页面中所有有 box 类名的元素
- 获取到的是一组数据,也是需要用索引来获取到准确的每一个 DOM 元素
事件
-
什么是事件?
- 事件指的是一种行为动作: 比如 单击,双击,手指按压,滑动,移动,悬停。。。
-
事件三要素
- 事件源: 页面中的一个具体的标签
- 事件类型: 行为动作(单击,双击,悬停,滑动。。。)
- 事件处理程序: 事件发生后的一个结果
-
事件语法
- 事件源.事件类型 = 事件处理程序
-
注意: - 事件处理程序的本质就是一个函数。
-
事件类型:
- 单击onclick
- 双击ondblclick
-
事件处理程序中的this关键字
- 函数中的this指向的是外部构造函数指向的对象。
- 事件处理程序中的this指向的是当前事件源
-
事件-注册addEventListener
- 语法:可以多次注册事件,不会前后覆盖;
// 给按钮注册事件,点击的时候,输出 123 var btn = document.querySelector("#btn"); // // 给对象设置 方法名 onclick // btn.onclick = function() { // alert(1); // }; // // *------------------------------ // // 给对象设置 方法名 onclick,把上面覆盖了; // btn.onclick = function() { // alert(2); // } // 新的注册时间的方式:可以解决 多次注册同一个事件,覆盖问题; // 参数:事件类型(click)没有on,事件执行函数(匿名函数) btn.addEventListener("click", function() { alert(1); }); btn.addEventListener("click", function() { alert(2); });
DOM-事件-三个阶段-冒泡与捕获
// 规则需要记住,事件执行3个阶段:捕获、到达目标、冒泡
// 捕获:从根部节点一层一层往上找,直到找到我们刚才触发的那个节点,这个过程叫捕获;
// 到达目标:找到我们刚才触发的那个节点
// 冒泡:从找的目标节点,一层一层往往根节点找,这个过程叫冒泡;
// JS代码:注册事件 写不写这个代码,事件-三个阶段存在的;
var btn = document.querySelector("button");
btn.addEventListener("click", function() {
alert(1);
});
// 过程:点击btn后,信号从根部一层一层捕获到btn目标节点,发现btn 刚好注册了点击事件,函数被执行完,信号冒泡回到根节点;
DOM-事件-三个阶段-冒泡与捕获-02-多级注册
// 规则:事件默认是在冒泡阶段执行;在冒泡的阶段,发现父级节点们也注册和用户触发的行为一样的事件,这些事件函数被执行;
// 同样, 如果孙子没有点击事件,但是用户对孙子有点击行为,但是爷爷注册有点击事件,爷爷同样也会触发点击事件。
var box_3 = document.querySelector(".box_3");
box_3.addEventListener("click", function() {
alert(3);
});
// 父亲
var box_2 = document.querySelector(".box_2");
box_2.addEventListener("click", function() {
alert(2);
});
// 爷爷
var box_1 = document.querySelector(".box_1");
box_1.addEventListener("click", function() {
alert(1);
});
// 为什么事件默认是在冒泡阶段执行?用户体验好;让用户知道自己点的地方是正常;
// JS:控制执行过程;(了解) 已经在捕获阶段执行;
var box_3 = document.querySelector(".box_3");
box_3.addEventListener("click", function() {
alert(3);
}, true);
// 父亲
var box_2 = document.querySelector(".box_2");
box_2.addEventListener("click", function() {
alert(2);
}, true);
// 爷爷
var box_1 = document.querySelector(".box_1");
box_1.addEventListener("click", function() {
alert(1);
}, true);
DOM-事件-三个阶段-冒泡与捕获-03-阻止冒泡
// 体验:事件默认在冒泡阶段执行;
// 解决:阻止冒泡;
// 语法:需要在函数上设置形参e; e:事件对象;
// e.stopPropagation(); 阻止冒泡行为;
// 使用:
var box_3 = document.querySelector(".box_3");
box_3.addEventListener("click", function(e) {
alert(3);
// 阻止冒泡:冒泡行为没了,默认事件在冒泡阶段执行就不会出现了;
// e:形参!!!!!!!!!!!!!!!!!!!!!!事件对象;
// stop:停止,掐断;
// Propagation:传播,冒泡这条线;
e.stopPropagation();
});
// 父亲
var box_2 = document.querySelector(".box_2");
box_2.addEventListener("click", function(e) {
alert(2);
e.stopPropagation();
});
// 爷爷
var box_1 = document.querySelector(".box_1");
box_1.addEventListener("click", function() {
alert(1);
});
// 页面中以后写很多盒子,嵌套(父子),事件执行的三个阶段;
// 事件默认在冒泡阶段执行:父亲注册了和用户行为一样的事件,用户触发子元素,父亲也会跟着被触发;
DOM-事件对象-属性
- 语法:事件对象:有一些属性和方法,一些属性描述事件行为的位置的一个对象,这个对象就叫事件对象;
box.onclick = function(e) {
// 行为看成对象:对象,包含属性和方法,属性:描述鼠标点击的位置的属性;集合:事件对象;
// console.log(e);
// ------------------------------属性:
//
// console.log("x", "y");
// // 参照当前可视窗口左上角为基准点
// console.log(e.clientX, e.clientY);
// // 参照与body为左上角为基准点
// console.log(e.pageX, e.pageY);
// 点击是谁就是谁;
// console.log(e.target);
// current:当前,事件注册给谁就是谁;
// console.log(e.currentTarget);
// this: 事件注册给就是谁;
// 类型:对象 == 对象
// 值:地址
console.log(e.currentTarget == this); // true
}
DOM-事件对象-方法
- 语法
// ------------------阻止默认行为--------------------- // 鼠标右键事件 document.oncontextmenu = function(e) { // alert(1); e.preventDefault(); } // a标签:转跳; var a = document.querySelector("a"); a.onclick = function(e) { e.preventDefault(); }
DOM-事件-委托-引入
-
委托的优点
- 提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用
- 动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。
-
不友好:每次新的LI时候,都要重新获取全部LI,重新给每个LI都注册一次事件;性能不好;
// 需求1:点击btn。给ul 新增一个li;
// 新属性:innerHTML
var ul = document.querySelector("ul");
// 获取:内部HTML结构,字符串;
console.log(ul.innerHTML);
// 设置:设置内部HTML,
ul.innerHTML += '<li class="son">-------------------</li>';
// 分析:
// 1. 获取btn
var btn = document.querySelector("#btn");
// 2.注册点击
btn.onclick = function() {
// 新增li
ul.innerHTML = ul.innerHTML + '<li class="son">aa</li>';
}
// 需求2:给每个li,点击之后弹窗1;
// 分析:
// 1. 获取所有的li
var lis = document.querySelectorAll("li");
console.log(lis);
// 2. 循环 注册事件
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
alert(1);
}
}
// 需求3:所有的li(已经存在的或新的),都有弹窗1;
// 分析:
// 1.点击后,新增li;
// 2.在点击后,把所有的li获取,注册事件;
var btn = document.querySelector("#btn");
// 2.注册点击
btn.onclick = function() {
// 新增li
ul.innerHTML = ul.innerHTML + '<li class="son">aa</li>';
// 再次获取全部的li
var lis = document.querySelectorAll("li");
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
alert(1);
}
}
}
// 方式:性能不好;li被重复注册事件;
DOM-事件-委托-实现
-
e.target
-
事件默认在冒泡执行
-
什么是事件委托?
- 把事件注册在父级的元素身上,
- 利用事件冒泡执行,当事件传播到已经注册了事件的父级元素身上,
- 判断 触发事件的DOM (e.target)节点是否是指定的元素,e.target---->DOM节点;
- e.target.nodeName=="LI"
- e.target.className == "son"
什么时候用?当我们需要给动态创建(不是页面一开始写死的,是后期可能会变、被新增的DOM元素)的元素实现注册事件的效果的时候;
// 事件委托:
// 1.不是给子元素注册事件
// 2.给 父级注册事件
// 3. 事件默认在冒泡阶段执行,点击子元素,冒泡到父级上,父级的事件也会被触发;
// 委托:父级的事件 被 后代元素(判断是否是我们需要的后代元素即可) 代理;
// 分析:
// 1.点击后,新增li;
// 2.在点击后,把所有的li获取,注册事件;
var btn = document.querySelector("#btn");
// 2.注册点击
btn.onclick = function() {
// 新增li
ul.innerHTML = ul.innerHTML + '<li class="son">aa</li>';
}
// 性能:事件只是注册了一次;
// 问题:点击ul范围内所有地方,弹窗1
// 解决: JS知道自己点击的是LI就可以了
var ul = document.querySelector("ul");
// 属性:DOM.nodeName 返回大写的的标签名;
// console.log(ul.nodeName, btn.nodeName);
ul.onclick = function(e) {
// alert(1);
// e.target:点击是谁就是谁,LI DOM节点
// console.log(e.target.className);
// console.log(e.target.nodeName);
// li 赋值表达式,结果:"son"
// 如果输出的是son证明点击的就是li标签 弹出alert(1)
if (e.target.className == "son") {
alert(1)
}
}
DOM-事件-mousedown-mousemove-mouseup
// 鼠标在某个元素上 落下的时候,触发
box.addEventListener("mousedown", function() {
console.log(1);
});
// 鼠标在某个元素上 移动,触发
box.addEventListener("mousemove", function() {
console.log(2);
});
// 鼠标在某个元素上 弹起 触发
box.addEventListener("mouseup", function() {
console.log(3);
});
开关思想-抽奖
- 在全局设置变量,初始化没有点击
- 点击事件内部:
- 如果没有点击:旋转下,点击的证明;
- 点击过了:没有任何反应;
- 缺点:就是因为你设置的全局开关,在控制台可以获取到,可以重新设置;
// 抽奖:点击一次;
// 1.获取 DOM
var begin = document.querySelector(".begin");
var zhizhen = document.querySelector(".zhizhen");
// 开关思想:
var key = true;
begin.onclick = function() {
// 关的状态,不用继续执行代码
if (key == false) {
return;
}
var num = Math.random();
num = num * 360;
zhizhen.style.transform = "rotate(" + num + "deg)";
key = false;
}
// 问题:key全局变量,在console 控制台 可以获取和重新设置;
// 解决:下个知识;
DOM-事件-解绑-抽奖
var btn = document.getElementById('btn');
btn.onclick = function(){
btn.onclick = null;
console.log('谢谢惠顾');
}
var btn = document.getElementById('btn');
btn.addEventListener('click',function fn(){
// 解绑 当前的函数
btn.removeEventListener('click',fn);
console.log('抽奖了');
})
抽奖:
begin.onclick = function() {
var num = Math.random();
num = num * 360;
zhizhen.style.transform = "rotate(" + num + "deg)";
// 事件解绑,下一次再次触发的时候,就没有的JS注册事件;
begin.onclick = null;
}
innerHTML
- 获取元素内部的 HTML 结构
<body>
<div>
<p>
<span>hello</span>
</p>
</div>
<script>
var div = document.querySelector('div')
console.log(div.innerHTML)
/*
<p>
<span>hello</span>
</p>
*/
</script>
</body>
-
设置元素的内容
<body> <div></div>
'
- 设置完以后,页面中的 div 元素里面就会嵌套一个 p 元素
**innerText**
- 获取元素内部的文本(只能获取到文本内容,获取不到 html 标签)
```javascript
<body>
<div>
<p>
<span>hello</span>
</p>
</div>
<script>
var div = document.querySelector('div')
console.log(div.innerText) // hello
</script>
</body>
- 可以设置元素内部的文本
<body>
<div></div>
<script>
var div = document.querySelector('div')
div.innerText = '<p>hello</p>'
</script>
</body>
- 设置完毕以后,会把
<p>hello</p>当作一个文本出现在 div 元素里面,而不会把 p 解析成标签
操作表单属性
- value值
1. 获取表单控件中的值
<input type = 'text' value = '123'>
<script type="text/javascript">
var input = document.querySelector('input');
alert(input.value);
</script>
2. 设置表单控件的值
<script type="text/javascript">
var input = document.querySelector('input');
input.value = '值';
</script>
getAttribute
- 获取元素的某个属性(包括自定义属性)
<body>
<div a="100" class="box"></div>
<script>
var div = document.querySelector('div')
console.log(div.getAttribute('a')) // 100
console.log(div.getAttribute('class')) // box
</script>
</body>
setAttribute
- 给元素设置一个属性(包括自定义属性)
<body> <div></div> <script> var div = document.querySelector('div') div.setAttribute('a', 100) div.setAttribute('class', 'box') console.log(div) // <div a="100" class="box"></div> </script> </body>
removeAttribute
- 直接移除元素的某个属性
<body>
<div a="100" class="box"></div>
<script>
var div = document.querySelector('div')
div.removeAttribute('class')
console.log(div) // <div a="100"></div>
</script>
</body>
style
- 专门用来给元素添加 css 样式的
- 添加的都是行内样式
<body>
<div></div>
<script>
var div = document.querySelector('div')
div.style.width = "100px"
div.style.height = "100px"
div.style.backgroundColor = "pink"
console.log(div)
// <div style="width: 100px; height: 100px; background-color: pink;"> </div>
</script>
</body>
- 页面中的 div 就会变成一个宽高都是100,背景颜色是粉色
className
- 专门用来操作元素的 类名的
<body>
<div class="box"></div>
<script>
var div = document.querySelector('div')
console.log(div.className) // box
</script>
</body>
- 也可以设置元素的类名,不过是全覆盖式的操作
<style type="text/css">
.one {
width: 200px;
height: 200px;
background-color: red;
}
</style>
<body>
<input type="button" value="点我加样式">
<div>我是一个没有样式的div</div>
<script type="text/javascript">
//1. 获取按钮事件源
var btn = document.querySelector('input');
//2. 给按钮注册事件
btn.onclick = function () {
//3. 获取div
var div = document.querySelector('div');
//4. 给元素动态添加样式
div.className = 'one';
}
</script>
</body>
-
H5中新增的方式:
- Dom.classList.add() 添加类名
- Dom.classList.remove() 移除类名
- Dom.classList.toggle() 切换类名
- Dom.classList.contains() 是否包含