¶API
API(Application Programming Interface应用程序编程接口),是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而无需源码,或理解内部工作机制的细节
¶WEB API
是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM), 现阶段主要针对于浏览器讲解常用的API,主要针对浏览器做交互效果,MDN详细API:https://developer.mozilla.org/zh-CN/docs/Web/API
¶DOM
¶简介
-
文档对象模型(Document Object Model),是W3C组织推荐的处理可扩展标记语言(html或者XML)的标椎
-
编程接口.通过DOM接口可以改变网页的内容、结构和样式
-
文档:一个页面就是一个文档,DOM中使用document表示
-
元素:页面中的所有标签都是元素,DOM中使用element表示
-
节点:网页中的所有页面都是节点(标签、属性、文本、注释等),DOM中使用node
¶获取元素
通过以下方式获得:
-
根据ID获取:getElementById()方法获取带有ID的元素对象:
由于元素的 ID 在大部分情况下要求是独一无二的,这个方法自然而然地成为了一个高效查找特定元素 的方法。返回的是一个匹配ID的DOM的Element对象,若没有找到,就返回null,例如:
1
2
3
4
5
6<div id="time">2021</div>
<script>
//页面是从上向下加载的,所以先得有标签,才能在运行script中的内容
var timer=document.getElementById('time'); //参数必须是字符串类型
console.log(timer.value);//最后结果输出(完整标签)<div id="time">2021</div>
</script>console.dir(timer)//打印 div#timer 属性和方法
-
根据标签获取:
getElementsByTagName()方法可以返回带有指定标签名的对象的集合,返回过来的是 获取过来元素对象的集合 以伪数组的形式存储
例如:
1
2
3
4
5
6
7
8
9
10
11<ul>
<li>hello1</li>
<li>hello2</li>
<li>hello3</li>
<li>hello4</li>
<li>hello5</li>
</ul>
<script>
var cnt=document.getElementsByTagName('li');
console.log(cnt[0]);//打印出 <li>hello1</li>
</script>循环打印出所有li标签的内容
1
2
3
4
5
6
7for(var i=0;i<(cnt.length);i++){
console.log(cnt[i])
}
//或
for(var t in cnt){
console.log(cnt[t])
}还可以获取某个元素(父元素)内部所有指定标签名的子元素:
例如: 如何获取ol中的li,而不获取ul中的li?
1 | <ul> |
父元素必须是单个对象(必须指明是哪一个元素对象),获取的时候不包含父元素自己
以上方法为传统方式
-
通过HTML5新增的方法获取:
1
2
3getElementsByClassName('类名'); //根据类名返回元素对象集合
querySelector('选择器'); //根据指定选择器返回第一个元素对象,注意只能返回第一个元素对象,里面的选择器需要加符号(.demo #demo),也可以是标签选择器
querySelectorAll('选择器'); //根据指定选择器返回所有元素对象,集合 -
特殊元素获取(body,html):
获取body:document.body 不带参数
获取html:document.documentElement 不带参数
¶事件基础
事件三要素/事件三部分:事件源、事件类型、事件处理程序
- 事件源:事件被触发的对象,谁->按钮
- 事件类型:如何触发,什么事件->鼠标点击(onclick) 鼠标经过 键盘按下 滑轮滚动等
- 事件处理程序:通过一个函数赋值的方式完成
例如一个简单的事件:
1 | <button id="btn">example</button> |
执行事件的步骤:
- 获取事件源 var div=document.getSelecetor(‘div’)
- 注册事件(绑定事件) div.onclick
- 添加事件处理程序(采取函数赋值形式) div.onclick=fcuntion(){}
常见的鼠标事件:
- onclick:左键触发
- onmouseover:经过触发
- onmouseout:离开触发
- onfocus:焦点触发
- onblur:失去焦点触发
- onmousemove:移动触发
- onmouseup:弹起触发
- onmousedown:按下触发
¶操作元素
DOM可以改变网页的内容、结构和样式,利用DOM操作元素来改变元素里面的内容、属性等
直接调用时是获取元素的文本内容,例如demo.innerText
-
改变元素内容:
element.innerText:从起始位置到终止位置的内容,但它去除HTML标签,同时空格和换行也会去掉,用的较少
element.innerHTML:起始位置到终点位置的全部内容,包括HTML标签,同时保留空格和换行,用的较多
上述只是对普通的盒子进行的,要想对表单元素进行设置,需要调用value,例如:input.value=‘xxx’
1 | var div=document.querySelector('div'); |
innerText输入的是文本,不能识别HTML,并且能够去除空格和标签;而innerHTML能够识别HTML,同时保留空格和换行
例如:div.innerHTML='<strong>今天是:</strong>2021'
推荐使用innerHTML(是一种标准)
-
常用元素的属性操作:
1、innerText、innerHTML改变元素内容(普通盒子如div),innerHTML更常用
2、src href
3、id alt title图片切换小项目
1 | <button id="a">one</button> |
-
表单元素的属性操作:
利用DOM可以操作如下表单元素的属性: type value checked selected disabled(被禁用)
表单里面的值 文字内容是通过value来修改的
1 | example.value='xxxx'; |
-
样式属性操作:
通过JS修改元素的大小、颜色、位置等样式
1
2element.style //行内样式操作
element.className //类名样式操作行内样式操作
修改的样式很少时使用
里面的属性名采用驼峰命名法,比如backgroundColor、fontSize等
JS修改的style样式操作,产生的是行内样式,css权重比较高
1
2
3
4var dic=document.querySelector('div');
div.onclick=function(){
this.style.backgroundColor='purple'
}小项目1:循环精灵图
1
2
3
4
5
6
7<script>
var lis=document.querySelectorAll('li');
for(var i=0;i<lis.length;i++){
var index=i*44;
lis[i].style.backgroundPosition = '0 -'+index+'px';
}
</script>小项目2:显示隐藏文本框内容
当修改的样式太多时,使用行内样式显得比较复杂
类名样式操作
先将要修改的样式提前声明一个样式类,然后再调用声明的样式this.className=‘change’
className会直接更改元素的类型,会覆盖原先的类名
如果想要保留原先的类,则:
this.className=‘first change’
在实际开发中,更推荐使用类名样式,这样在后期的维护中只需要修改类名中的内容即可,而不用去修改JS
小项目:密码框格式提示错误信息:
两种方式均可
5.排他思想
当页面有多个按钮时,为每个按钮设置一个onclick会显得繁琐,这时最好用循环来做
1 | <script> |
小项目1:百度换肤
小项目2:表格隔行变色的效果,不难,就不写了
小项目3:表单全选取消全选
6.自定义属性的操作
第一种方式只能用于标签自带的属性值,而第二种可以调用用户自定义的属性
1 | //index为自定义属性,id为标签自带属性 |
设置属性值:
提倡标签自带的属性用第一种写,自定义的用第二种,只是提倡
移除属性:
小项目:tab栏切换,京东做法 重要
getAttribute是没有兼容性问题的,第二种ie11才开始支持
注意一点:
1 | <div data-list-name='xxx'></div> |
data-list-name–>驼峰命名法–>listName
如果自定义属性里面有多个-链接的单词,我们获取属性的时候要采取驼峰命名法
¶节点操作
- 父级节点
- 子节点
实际开发中更提倡使用上面一种方式,第一种方式包含了无用的节点
获取指定的节点:
上面的方式会包含无用的节点
上面的方式不包含无用的节点,但有兼容性问题,解决方案如下(实际开发中的):
小项目:新浪下拉菜单
- 兄弟节点
获取的是上、下一个兄弟节点,包括元素节点或者文本节点等等
- 创建节点
后面追加元素
例如
1 | <ul></ul> |
1 | ul.insertBefore(li,ul.children[0]); |
小项目:简单版发布浏览案例
- 删除节点
小项目:删除留言案例
1 | <a href='javascript:void(0);'> </a> |
不要忘记后面的分号
- 复制节点
这样只是复制了一份节点,还需要将其放到结构中去
1 | var ul=document.querySelector('ul'); |
可以用appendChild或者insertBefore
小项目:动态生成表格
循环数组对象
1 | { |
- 三种动态创建元素的区别
相当于重新创建并加载一个新的页面,在实际开发中不常用
1 | //拼接字符串的效率很低,大约3100毫秒左右 |
1 | //利用数组存取,然后再join,效率很高,大约7毫秒左右 |
1 | //比innerHTML拼接字符串的方法效率高很多,但比innerHTML数组连接相比效率低,大约需要20毫秒左右 |
面试时可能会问到
¶DOM重点核心(总结)
¶
¶DOM事件高级
¶注册事件(绑定事件)
1 | // var hello=function(){ |
addEventListener()同一个元素同一个事件可以添加多个监听器(事件处理程序),IE9之前版本支持,推荐使用addEventListener();
attachEvent()是IE9之前版本支持,仅做了解,实际生产环境中不要使用
¶删除事件(解绑事件)
1 | <div>1</div> |
listener不能用匿名函数来写
1 | <div>1</div> |
第二种使用attachEvent()时的解绑事件函数
¶DOM事件流
1 | //结果是:先弹出father,再弹出son |
¶事件对象
1 | div.onclick=function(event){} |
-
event就是一个事件对象,写到监听函数里面当做形参来看
-
事件对象只有有了事件(onclick onmouseover…)才会存在,他是系统自动创建的,不需要我们传递参数
-
事件对象是事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击里面就包含了鼠标的相关信息、鼠标坐标等,如果是键盘事件就包含键盘的信息,不如判断用户按下了那个键等
-
事件对象的名称是可以自己修改的,建议使用e来代替
-
兼容性问题:IE678用window.event
1
2
3div.onclick=function(e){
console.log(window.event);
}兼容性处理方案:e=e||window.event;但实际开发中不太需要
事件对象的常见属性和方法:
- target:
e.target返回的事触发事件的对象(元素),而this返回的事绑定事件的对象,例如当鼠标点击li中的内容1时:
1 | <ul> |
console.log(e.target)会输出
但e.target存在兼容性问题,在IE678中不能使用,此时需要调用e.srcElement;
兼容方案:var target=e.target||e.srcElement
-
currentTarget
是跟this非常相似的属性,但currentTarget存在兼容性问题,IE678不认识,所以在实际开发中提倡使用this
-
e.type返回事件的类型,不带On,如click、mouseover、mouseout
-
e.preventDefault() 阻止默认的行为(事件)
例如链接、表单,我们要求当满足某个条件时才可以跳转到该链接上去,没有满足时让链接不跳转,或者让提交按钮不提交
是一个方法,需要加小括号
1 | <a href="http://cs.kittates.top">link</a> |
低版本浏览器使用e.returnValue,注意是一个属性,不需要加小括号
1 | return false |
也能阻止默认行为,没有兼容性问题,但其之后的代码不再执行
¶阻止事件冒泡
面试&&开发
标准写法:利用e.stopPropagation()方法
例如让son弹出,而father不弹出,则需要在son中的函数中调用e.stopPropagation()方法来阻止向上一级的冒泡,存在兼容性问题,IE678不能使用
IE678:window.event.canelBubble=true
¶事件委托(代理、委派)
事件冒泡的一个应用
不用为每个子节点绑定事件(太繁琐),不必重复使用DOM
1 | <ul> |
¶常用的鼠标事件
常用的鼠标事件:
-
禁止鼠标右键菜单
contextmenu鼠标右键菜单事件
虽然不显示右键菜单,但是还是可以通过ctrl+v来复制和粘贴的
-
禁止鼠标选中(selectstart 开始选中)
selectstart鼠标选中事件
但是:
从文字的最左边还是有一条缝隙是可以复制的
crtl+A也可以
F12键调试复制
鼠标事件对象
e.screen在实际开发中用的比较少,了解
小项目:跟随鼠标移动的小天使
用到的是mousemove事件,获取鼠标移动时的数据
注意:设置坐标时记得加后面的单位
1 | img.style.top=y-img.height/2+'px'; |
相同原理的样例:淘宝商品封面放大效果
¶常用的键盘事件
Alt键、左右箭头键等功能键onkeypress不能识别
存在执行顺序:
如果keydown和keypress事件都存在时,先执行keydown,最后执行keyup事件
键盘事件对象:
通过keyCode可以获取键盘按键的ASCII码值,从而判断按下了哪个键
**注意:**keyup、keydown事件不区分字母大小写,a和A得到的都是65;keypress是区分大小写的,默认是大写
小项目1:模拟京东按键输入内容
小项目2:模拟京东快递单号查询
拓展开发:射击小游戏
¶BOM
¶BOM概述
例如在不同的浏览器调用alert函数,弹出的外观是不一样的
DOM包含在BOM中,所以
在学习DOM时,经常是document.querySelector(‘xxx’),而规范的写法是window.document.querySelector(‘xxx’),window可以省略的
在DOM中声明的全局变量或方法,在BOM中可以通过window.example的形式调用
¶window对象的常见事件
- 窗口加载事件
1 | <script> |
这样就可以写到文档的任何一个位置了,也可以外部引用
window.onload若有多个,只会执行最后一个;而window.addEventListener(‘load’,function(){})若有多个时,会全部执行
DOMContentLoaded:
DOMContentLoaded在把基本构架加载完成之后就会执行,而window.onload是将所有内容加载后才执行,相比之下,DOMContentLoaded比window.onload加载速度快
-
调整窗口大小事件
resize事件
window.innerWidth 获取当前屏幕的宽度
¶定时器
-
setTimeout()定时器
setTimeout()属于window对象,window可以省略,可以直接调用,像alert(); 延时时间是毫秒单位,省略默认为0
函数调用可以直接在setTimeout()里面写函数,也可以在外部写完后再在setTimeout里面调用,还有一种不提倡的写法:‘函数名()’
1
2
3
4
5
6
7
8
9
10
11//方法一
setTimeout(function(){
alert('xxx');
},2000)
//方法二
function callback(){
alert('xxx');
}
setTimeout(callback,2000);
//不提倡写法
setTimeout('callback()',2000);由于页面中可能会有多个不同的定时器,可以给定时器加标识符(名字),例如:
1
2var time1=setTimeout(callback1,2000);
var time2=setTimeout(callback2,2000);![image-20220725191625173](image-20220725191625173.png)
小项目:5s之后自动关闭广告
清除定时器:clearTimeout()
1 | <script> |
- setInterval()定时器
小项目:倒计时
清除定时器:clearInterval()
小项目:发送短信
¶this指向问题
面试重点
-
在全局作用域或者是普通函数中:this指向全局对象window
**注意:**计时器中的this指向window
-
在方法中调用:this指向的是包含该方法的对象(调用者),例如
1
2
3
4
5var o={
sayHi: function(){
console.log(this);//this指向o
}
} -
构造函数中调用:this指向构造函数的实例,例如:
1
2
3
4function(){
console.log(this);//指向fun
}
var fun=new fun();
¶JS执行队列
例如:
1 | console.log(1); |
上述结果为:先1 再2 后3,运行了异步处理机制
JS虽然是单线程的,但是允许处理多个任务
1 | console.log(1); |
上述结果为:先1 再2 后3,原因如下:
任务队列又称为消息队列
JS执行机制
执行栈中的任务完成之后,会把任务队列中的任务放到执行栈中,继续执行。所有任务执行完成之后,队列就会清空
**事件循环(event loop):**执行栈中的同步任务完成之后,会重复的到任务队列中查看是否有新的任务,如果有,就拿到执行栈中执行
¶location对象
-
location对象属性
重点记住href、search
小项目1:5秒钟之后自动跳转页面
小项目2:获取URL参数数据:
通过location.search获取参数,格式是类似于?name=kittates的形式,先通过substr获取name=kittates的字串,然后通过split('=')将其分割为数组,得到第二个参数即为所需,
1 | var params=location.search.substr(1); |
-
location对象的方法
location.href()和location.assign()都能够返回前一个页面,location.replace()不能后退,replace将url的地址替换了,以前地址的缓存被替换了
¶navigator对象
根据是手机端还是电脑端打开的页面从而以不同的形式展现
了解即可,一般情况下都是服务端做的
¶history对象
1 | <script> |
一般在浏览器中不会使用,但是会在一些OA办公系统中见到
¶PC端网页特效
¶元素偏移量offset
offsetTop和offsetLeft以带有定位的父亲为准,如果有父亲或者父亲没有定位,则以body为准
offset与style的区别
行内样式表:
1 | <div style=''> |
小项目1:获取鼠标在盒子内的坐标
小项目2:拖动模态框
小项目3:仿京东放大镜页面效果
¶元素可视区client
与offset的区别是:clientWidth、clientHeight不包含边框
¶淘宝flexible.js源码分析
-
立即执行函数:不需要调用,立马能够自己执行的函数
写法1:(function() {})()
1
2
3(function(){
console.log(2);
})()写法2:(function(){}())
1
2
3(function(){
console.log(2);
}())里面也可以传递参数
1
2
3(function(a,b){
console.log(a,b);
})()也可以为立即函数起个名字
1
2
3(function sum(a,b){
console.log(a+b);
})(a,b)立即函数独立的创建了一个作用域,里面所有的变量都是局部变量,不会有命名冲突的情况
![image-20220729112920811](image-20220729112920811.png)
¶元素滚动scroll
scrollWidth和scrollHeight不包含边框,但是包含padding,内容可能会超出盒子的范围,所以获取的是元素实际的大小
1 | //显示滚动条 |
scroll事件
小项目:仿淘宝固定右侧侧边栏
注意
获取页面被卷去的高度:window.pageYOffset,但存在兼容性问题
DTD:
兼容性封装函数如上
页面滚动距离用window.pageXOffset、window.pageYOffset获取
mouseenter和mouseover的区别:
mouseover子盒子会冒泡到当前盒子而mouseenter不会
mouseover会冒泡
¶动画函数封装
1 | <style> |
上述存在使用absolute relative动画速度不同的问题?
解决:
absolute:如果元素没有已定位的祖先元素,那么它的位置则是相对于最初的包含块(body)。
relative:元素“相对于”它的原始起点(上一个位置)进行移动
封装
上述方法每次调用就会开辟一段空间,性能不太好。
性能优化+消除变量歧义:
将timer作为调用对象的属性进行操作
给动画设置按钮,点击按钮执行,出现问题:
按钮点击次数越多,动画速度越快,解决方案:
先清除之前的定时器,再调用动画
缓动动画
代码实现:
1 | <script> |
实现后退(比如点击500到达500位置,点击800到达800位置,实现前进后退功能):
step<0要向下取整,要加判断
1 | step = step<0?Math.floor(step):Math.ceil(step) |
动画函数添加回调函数
将函数名作为参数传递过去
1 | <script> |
动画函数单独封装成一个js文件
小项目:引用animate动画函数
通过一下方式引用
1 | <script src="animate.js"></script> |
出现的问题:
1 | function animate(obj,target,callback){ |
中间的
1 | if(obj.offsetLeft==target)() |
最好使用==,因为存在如果target是负值-160的时候,而此时是>=,(target-obj.offsetLeft)/10=(-160-0)/10=-16,这是会发现-16是>=target,也就是-16>=-160的,所以执行一次就clear了,所以综上,还是使用==
1 | var step=(target-obj.offsetLeft)/10; |
第一行先保持原样,第二行在据实际判断执行的操作
小项目1:网页轮播图,在品优购上面操作
手动调用事件,例如:
arrow_r.click():模拟手动点击触发事件
节流阀
小项目2:返回顶部
window.scrollTo(x,y)
滚动到文档中的某个坐标。
1 | window.scrollTo({ |
小项目3:筋斗云