WebAPI学习
接下来一些案例 https://download.csdn.net/download/f_felix/11130717
查找对象的方式
//document.getElementById():通过id
//document.getElementsByTagName("标签名"):通过标签名 返回一个伪数组,无论有几个元素,返回都是伪数组
//document.getElementsByClassName("类名") 返回值:伪数组
//document.getElementsByName():通过name属性查找 只适用于表单元素
//通过css选择器来查找,, 如果是id需要加上#id 如果是类名,需要加上.类型
//document.querySelector() :返回一个对象,如果有多个,会返回第一个
//document.querySelectorAll():返回一个伪数组,
document.querySelector(".class div");
document.querySelector("#id>div");
innerText属性与innerHTML属性
- innerText属性:设置标签的文本内容,会对标签进行转义,标签不能生效。(尽量多用innerText)
- innerHTML属性:设置标签的内容,不会对标签进行转义,标签能生效
// 区别
// innerText只会获取标签文本内容,如果有标签会被忽略
// innerHTML会获取到文本内容+标签
// innerText在设置内容的时候,HTML标签不生效,会对所有的标签进行转义 <h1>
// innerHTML在设置内容的时候,HTML会生效
// 注意:尽量少用innerHTML,防止xss攻击,尤其是用来用户的输入内容上
box.innerText = '<h1>我是一个更大的标题</h1>';
box.innerHTML = '<h1>我是一个更大的标题</h1>';
对于a标签来说,默认的行为就是进行页面跳转,如果不想让a标签进行跳转,可以在注册事件中使用return false
var link = document.getElementById("link");
link.onclick = function() {
alert("呵呵");
//阻止页面跳转
return false;
}
//href:如果写了javascript:表示a标签不执行跳转,执行js代码
//javascript:void(0);:可以阻止页面跳转
//javascript:; a标签不跳转
修改标签的样式
同样的DOM对象可以通过className操作样式,也可以通过style属性操作样。 style设置的样式是行内样式,因此优先级要高于className设置的样式
//1. style属性是一个对象,里面存储了所有行内样式对应的键值对。
//2. 如果样式的名字带了-,比如background-color,到了style对象中,变成了驼峰命名法,backgroundColor(因为-在js中不是一个合法的标识符)
//3 style属性只能获取和设置行内样式,在类样式中定义的样式通过style获取不到。
使用cssText可以设置style的属性值
//优点:可以一次性设置多个值
//缺点:会覆盖其他值
var box = document.getElementById("box");
box.style.cssText = "font-size: 20px; width:100px; height:100px;background-color:pink;";
标签的自定义属性
在html页面中,定义一个自定义属性
<div id="box" aa="bb"></div>
在对应的DOM对象中是不存在的,在DOM对象中只会存在固定的那些属性。
var box = document.getElementById("box");
console.log(box.aa);//undefined
给对象设置一个自定义的属性
<body>
<div class="tab">
<ul>
<li class="active">国际大牌<span></span></li>
<li>国妆名牌<span></span></li>
<li>清洁用品<span></span></li>
<li>男士精品</li>
</ul>
<div class="content">
<img src="images/guojidapai.jpg" alt="">
<img src="images/guozhuangmingpin.jpg" alt="" class="hide">
<img src="images/qingjieyongpin.jpg" alt="" class="hide">
<img src="images/nanshijingpin.jpg" alt="" class="hide">
</div>
</div>
<script>
var lis = document.getElementsByTagName("li");
var imgs = document.getElementsByTagName("img");
for (var i = 0; i < lis.length; i++) {
// 这是给对象设置的自定义属性,所以在标签中是不会显示的
lis[i].index = i;
// 这是给标签设置属性的,所以在页面上的标签是会有显示的
// lis[i].setAttribute("aa", i);
lis[i].onmouseover = function () {
for (var j = 0; j < lis.length; j++) {
lis[j].className = ""
imgs[j].className = "hide";
}
this.className = "active";
imgs[this.index].className = "";
// imgs[this.getAttribute("aa")].className = "";
}
}
</script>
</body>
attribute方法
attribute系列方法用于设置标签的属性,不管是自定义的还是固有的属性。例子参考上面的
//获取标签的属性
box.getAttribute(name);
//设置标签的属性
box.setAttribute(name, value);
//移除标签的属性
box.removeAttribute(name);
排他思想
上述的例子中用到了这个排他思想
lis[i].onmouseover = function () {
/*
排他思想:
只想要选中的标签有特定的效果显示,别的标签保持一致。
首先让所有的标签都统一样式(包括自己),然后给自身单独设置特定的样式
*/
for (var j = 0; j < lis.length; j++) {
lis[j].className = ""
imgs[j].className = "hide";
}
this.className = "active";
imgs[this.index].className = "";
// imgs[this.getAttribute("index")].className = "";
}
this的指向
//关于this
//函数内部的this是window
//方法内部的this,指向当前的对象
//构造函数内部的this,新创建的对象
//事件里面的this,当前对象
节点操作
孩子节点
//childNodes:获取所有的孩子节点(包括了元素节点和其他很多类型的节点,基本不常用)
//children:获取所有的子元素(用途很广泛),兼容性:IE678会把注释节点算上。
//firstChild //第一个子节点
//firstElementChild //第一个子元素 有兼容性问题(IE678)
//lastChild //最后一个节点
//lastElementChild //最后一个子元素 有兼容性问题(IE678)
兄弟节点
//1. nextSibling:下一个兄弟节点
//2. nextElementSibling:下一个兄弟元素(IE678不兼容)
//3. previousSibling//上一个兄弟节点
//4. previousElementSibling //上一个兄弟元素 有兼容性问题 可以封装一个兼容性方法
父节点
//1. parentNode:父节点 没有兼容性问题
appendChild
语法:parent.appendChild(newChild)
parent:调用者,父节点来调用
newChild:需要添加的那个孩子。
作用:把newChild添加到parent的孩子的最后面。
注:如果
newChild
已经存在于DOM树中,则它会被从原始位置删除。 newchild原来的父节点长度会缩短
var demo = document.getElementById("demo");
var box = document.getElementById("box");
box.appendChild(demo);
insertBefore
语法:parent.insertBefore(newChild, refChild);
parent:必须要父节点来调用
newChild:需要添加的那个节点
refChild:添加到哪一个节点的前面。
var ul = document.getElementById("list");
var li = document.createElement("li");
li.innerHTML = "哈哈";
//就是添加到子节点的最前面。
ul.insertBefore(li, ul.children[0]);
createElement
语法:var element = document.createElement(“tagName”);
作用:在内存里面创建了一个节点
返回:一个元素
用途非常的广泛。
删除节点
语法:parent.removeChild(child);
功能:有父盒子调用,删除里面的一个子元素。
替换节点
语法:parentNode.replaceChild(newChild, oldChild);
newChild
用来替换oldChild
的新节点,如果newChild
已经存在于DOM树中,则它会被从原始位置删除。
pageX (Y)、clientX(Y)和screenX(Y)
// 网页上的坐标
// console.log(event.pageX, event.pageY);
// 屏幕的坐标。和页面的坐标是一致的
// console.log(event.clientX, event.clientY);
// 获取的坐标是包含浏览器的工具栏和地址栏那部分的
// console.log(event.screenX, event.screenY);
注册事件的两种方式
1、on+事件类型
注册事件:
box.onclick = function(){
//事件处理程序
}
移除事件:
box.onclick = null;
on+事件名称注册事件的缺点:
同一个元素同一类型的事件,只能注册一个,如果注册了多个,会出现覆盖问题。
2、addEventListener
// 给一个元素添加一个事件监听, 给元素注册一个事件
// 参数1: 事件的类型 类型中没有on
// 参数2: 事件处理程序
// 参数3: 是否捕获 true 捕获 false 冒泡(常常不写这个参数,默认冒泡)
// 事件源.addEventListener(事件类型, 事件处理程序, 是否捕获)
addEventListener(type, func, useCapture);
tips:如果想要让你注册的事件能够移除,不能使用匿名函数。
function fn1() {
alert("hehe");
}
//如果想让注册的事件能移除,不能用匿名函数。
box.addEventListener("click", fn1, false);
removeEventListen的语法
//第一个参数:参数类型
//第二个参数:要移除的那个函数
//第三个参数:false(可以不写)
removeEventListener(type, func, useCapture);
事件流
事件冒泡
当一个元素的事件被触发时,同样的事件将会在该元素的所有祖先元素中依次被触发。这一过程被称为事件冒泡。
事件捕获
事件的处理将从DOM层次的根开始,而不是从触发事件的目标元素开始,事件被从目标元素的所有祖先元素依次往下传递 (基本上,我们都是用事件冒泡)
// 任何一个事件都会经历3个阶段
// 1. 事件捕获
// 2. 目标阶段
// 3. 事件冒泡
<div class="father">
<div class="son">
<div class="sun">
</div>
</div>
</div>
<script>
var son = document.querySelector('.son');
var sun = document.querySelector('.sun');
var father = document.querySelector('.father');
document.addEventListener('click', function() {
console.log(this);
}, false);
document.body.addEventListener('click', function() {
console.log(this);
}, true);
father.addEventListener('click', function() {
console.log(this);
}, true);
son.addEventListener('click', function() {
console.log(this);
}, false);
sun.addEventListener('click', function() {
console.log(this);
}, true);
</script>
事件对象
// 事件对象: 任意一个事件都会有一个事件对象
// 事件对象的作用: 用来获取鼠标的位置, 键盘的按下的键
// 当我们需要获取鼠标的位置 或者按下的键 需要用到事件对象
// 怎么获取事件对象
// 在注册事件的时候,给function提供一个形参,下面的event就是接受事件对象的(这个名字可以随意取)
button.onclick=function(event){console.log();}
兼容性封装(可以不用考虑IE678,后面的框架都是不支持IE678的)
btn.onclick = function(event){
//只要用到了事件对象,就要记得处理浏览器兼容性
event = event || window.event;
}
// 想要获取鼠标的位置
// screenX screenY : 相对于屏幕最左上角的距离(用的不多)
// clientX clientY : 相对于可视区左上角的距离
// pageX pageY: 相当于整个页面左上角的距离 如果有滚动条, pageY是包含滚动条隐藏的那部分高度
阻止浏览器默认行为
// 通过e.preventDefault()可以阻止浏览器的默认行为,不推荐使用return false;
// a标签点击会跳转 img按住了可以拖拽 表单点击提交了也会跳转
// 不推荐使用, return false优点: ie678也可以用
// 缺点: 1. return false后的代码不会执行,只能写在最后面.
// 2. 将来在react的时候,return false不被支持
// 通过事件对象 e.preventDefault() 1. 后续代码可以执行 2. 标准的阻止浏览器默认行为
阻止事件冒泡
// 通过e.stopPropagation()方法可以阻止事件冒泡
阻止a标签跳转
<!-- 跳锚点, 表示跳到顶部锚点 -->
<!-- javascript:; 表示一个伪协议 href中只要写了javascript: 表示这个a标签不跳转,变成执行js代码了
void(0):等价于undefined -->
<!--
阻止a标签跳转
1. 注册点击事件, 阻止浏览器默认行为
2. # : 一般来说,还是连接
3. javascript:;: 把a当成按钮来用
-->
三大系列
offset系列
// offsetWidth 与 offsetHeight: 用于获取元素真实的高度和高度
// style对应的 标签中的style属性,对应的是行内样式
// 通常来说,我们不会通过style来获取样式,只能获取行内样式。
// 1. 获取到的是盒子的真实的大小, offsetWidth = width + padding + border
// 2. 获取到的直接数字类型,直接运算
// 3. offsetWidth是只读属性,不允许修改
// offsetParent: 距离自己最近的有定位的父元素, 如果都没有,找body元素
// parentNode: 父元素
// offsetLeft offsetTop: 获取元素真实的位置, 距离offsetParent的距离 offsetLeft = left + margin—left
scroll系列
不常用这个
// scrollWidth scrollHeight : 指的是内容的大小,如果内容超出了,大小会比盒子更大
// scrollLeft scrollTop:获取滚动条滚动的距离
client系列
//client系列 client:客户区,可视区 获取盒子的大小,不包括边框
//clientWidth clientHeight
//clientLeft clientTop
// clientLeft:获取的就是左边框的宽度
// clientTop: 获取的就是上边框的宽度
// client系列: 获取整个window的大小
// window.onload window.onscrll window.onresize: 当窗口大小发生改变的时候
window.onresize = function() {
// 获取到窗口的宽度和高度
// console.log(document.documentElement.clientWidth); 以前是这样获取的
// console.log(document.documentElement.clientHeight);
console.log(window.innerWidth);
console.log(window.innerHeight);
}
client与rem布局
// 一般需要在页面加载前设置html的fontSize的大小
//rem布局: 给不同的屏幕设置不同的html的fontSize
//下面代码写在head标签下的script中,因为页面一进来就要进行加载,不然的话会忽然跳一下
// 等价于我们之前用媒体查询写的那一段
function fn(){
console.log('哈哈')
var width = window.innerWidth;
width = Math.min(width, 750);
width = Math.max(width , 320);
document.documentElement.style.fontSize = width/15 + 'px';
}
fn();
window.onresize = fn;
新增一个事件
一般我们不给盒子设置滚动条,但是我们的页面(window)可以有滚动条
// 事件 onscroll 当div的滚动条滚动的时候
element.onscroll = function(){
console.log(element.scrollTop);
}
BOM
Window对象
// window对象 onload
// window对象常用的有三个事件 load scroll resize
window.onscroll = function() {
console.log('哈哈哈');
// 想要获取到scrollTop值
// 早期:要么获取html的,要么获取body的
// 现在直接通过 window.pageYOffset就可以获取
// 垂直滚动条的距离
console.log(window.pageYOffset);
// 水平滚动条的距离
console.log(window.pageXOffset);
}
// window.onload : 当整个网页加载完成,保证网页依赖的资源(图片)加载完成后才会触发onload事件
// 在window.onload中可以保证页面加载完成,所以肯定能获取到页面中的元素
// 如果将来想要获取页面中图片的宽度和高度, 应该把代码写在window.onload中
setTimeout
setTimeout延时器可以在延迟时间到期后执行一个指定的函数
setInterval
setInterval,方法重复调用一个函数或执行一个代码段,在每次调用之间具有固定的时间延迟。定时器除非清除,否则会一直执行下去。
// timeId是定时器的编号,是一个累加的数字,,,,浏览器只要开启了一个定时器
// 开启一个定时器,就是给浏览器一个任务,让浏览器每隔指定的时间去调用一次函数
轮播图
常用的轮播图插件swiper https://www.swiper.com.cn/
1、封装动画函数
/**
* 匀速运动
* @param element 哪个元素运动
* @param target 目标距离
* @param num 每一步移动的距离
*/
function animate(element, target, num) {
clearInterval(element.timeId);
element.timeId = setInterval(function () {
var current = element.offsetLeft;
var step = current > target ? -num : num;
if (Math.abs(current - target) > Math.abs(step)) {
current += step;
element.style.left = current + "px";
} else {
clearInterval(element.timeId);
element.style.left = target + "px";
}
}, 16);
}
/**
* 变速运动(缓动动画)
* @param {元素标签} element
* @param {需要改变的属性(对象类型)} obj
* @param {回调函数} fn
* obj {width:400, height:400, left:400, top:400, borderRadius:200}
* 如果传了回调函数,动画就可以呈现阶段变化
*/
function speedAnimation(element, obj, fn) {
clearInterval(element.timer);
element.timer = setInterval(function () {
var flag = true;
for (var k in obj) {
var attr = k;
var target = obj[k];
//对opacity做特殊处理即可
//1. parseInt改成parseFloat (获取到的透明度是个小数)
//2. 把leader和target都放大了1000倍。 算出来的step也是放大了1000倍
//3. 设置回去的时候,让leader/1000 把px给去掉了
if (attr == "opacity") {
var leader = getStyle(element, attr); // 这个方法见下面的获取计算后的样式那一节
leader = parseFloat(leader) || 0;
leader = leader * 1000;
target = target * 1000;
var step = (target - leader) / 10;
//step肯定是一个很小的数,Math.ceil就会向上取整,直接会变成1
// 当为负数的时候就要向下取整了
step = step > 0 ? Math.ceil(step) : Math.floor(step);
leader += step;
element.style[attr] = leader / 1000;
if (leader != target) {
flag = false;
}
} else if (attr == "zIndex") {
//层级不需要动画,直接设置即可。
element.style.zIndex = target;
} else {
var leader = getStyle(element, attr);
leader = parseInt(leader) || 0;
var step = (target - leader) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
leader += step;
console.log(step);
element.style[attr] = leader + "px";
if (leader != target) {
flag = false;
}
}
}
if (flag) {
clearInterval(element.timer);
//如果传了fn,就调用fn,如果没传,就不掉
// if(fn) {
// fn();
// }
//假值短路
fn && fn();
}
}, 15);
}
2、切割轮播图
扩展知识点
参数 | 描述 |
---|---|
function(currentValue, index, arr) | 必需。 数组中每个元素需要调用的函数。 |
thisValue | 可选。传递给函数的值一般用 “this” 值。 如果这个参数为空, “undefined” 会传递给 “this” 值 |
参数 | 描述 |
---|---|
currentValue | 必需。当前元素 |
index | 可选。当前元素的索引值。 |
arr | 可选。当前元素所属的数组对象。 |
// forEach() 方法
// forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
// 注意: forEach() 对于空数组是不会执行回调函数的。
array.forEach(function(currentValue, index, arr), thisValue)
//例子:
var uls = box.querySelectorAll("ul");
uls.forEach(function (ul, index, uls) {
ul.style.transform = "rotateX(" + -90 * count + "deg)";
ul.style.transition = "1s " + 0.2 * index + "s";
})
节流阀
当前一个动作执行的时候,下一个动作需要等前一个动作完成了才可以继续,可以节省资源,参考案例切割轮播图
移动端的WebAPI
区域滚动
实现页面上常见到的区域滚动效果
开发中常用的 插件iscroll
http://caibaojian.com/iscroll-5/
// 移动端有专属的四个事件
// touchstart: 开始触摸
// touchmove: 触摸移动
// touchend: 触摸结束
// touchcancel: 触摸取消 被系统取消,系统有一些优先级很高的应用,电话
// 同样通过事件对象获取 e.touches[0],可以计算出手指滑动的距离
// touches: 当前屏幕上所有的手指。
// targetTouches: 目标元素上的手指
// changedTouches: 改变的手指 ,在事件touchend 中只能通过这个获取触摸点,在end的手相当于手指已经离开屏幕
// 要获取手指的位置还需要通过三个touches中的PageX和pageY
// (clientX和clientY在没有滚动条的情况下和page的是一样的) 不考虑使用screenX(Y),前面有解释
var son = document.querySelector('.son');
// 记录开始移动的位置
var startX;
var total = 0;
son.addEventListener('touchstart', function(e) {
startX = e.touches[0].pageX;
});
// 让son跟着跑
son.addEventListener('touchmove', function(e) {
var moveX = e.touches[0].pageX - startX ;
// 让son跟着动,在之前移动的基础上继续移动
var x = total + moveX;
console.log(x);
// 等价于 if(x > 0) x = 0; if(x < -300) x =-300;
x = Math.min(0, x);
x = Math.max(x, -300);
son.style.transform = 'translateX(' + x + 'px)';
// console.log(moveX);
});
// 记录最终移动的距离
son.addEventListener('touchend', function(e) {
// 本地移动的最终距离
var totalX = e.changedTouches[0].pageX - startX;
total += totalX;
total = Math.min(0, total);
total = Math.max(total, -300);
console.log(total);
// console.log('total',total);
});
补充
// 经验之谈 手机端 safari浏览器时间不识别 - 2019-04-19 00:00:00
var seckillTime = new Date('2019/04/19 18:30:00');
// 因此时间格式可以写成 2019/04/19 00:00:00
// 位运算符 任何一个小数 | 0 把小数给去了 等价于 parseInt(1.234) 输出 1
var time = 1234 / 1000 | 0; // 输出 1
自定义播放器
全屏切换API:
// video.requestFullScreen()
// div.webkitRequestFullScreen();
// div.mozRequestFullScreen();
function full(element) {
// 能力检测
if ('requestFullScreen' in element) {
element.requestFullScreen()
} else if ('webkitRequestFullScreen' in element) {
element.webkitRequestFullScreen()
} else if ('mozRequestFullScreen' in element) {
element.mozRequestFullScreen()
} else {
alert('亲,你的浏览器不支持全屏的api,要不换个浏览器??')
}
}
属性
// currentTime:当前时间
// duration:总长时间
// timeupdate:播放进度更改时触发
// volume:控制音量
classList
类名操作
推荐:classList是一个集合,会存储某个元素上所有的类名,使用classList来替代className操作class类
//添加类
node.classList.add("classname");
//移除类
node.classList.remove("classname");
//切换类
node.classList.toggle("classname");
//判断类
node.classList.contains("classname");
console.log(node.classList) // 输出的是一个数组,是设置在node上的所有class
获取计算后的样式
通过element.style.xxx只能获取到行内样式
通过offset系列只能获取到特殊的一些样式
获取元素计算后的样式指的是元素经过层叠后真正生效的样式,不管样式写在哪,计算后的样式指的就是最终的样式。
// 现代浏览器:
return window.getComputedStyle(element, null)[attr];
// IE678:
return element.currentStyle[attr];
/**
* 解决兼容性问题
* @param {获取哪个标签的属性} element
* @param {获取标签的哪个属性} attr
*/
function getStyle(element, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(element, null)[attr];
} else {
return element.currentStyle[attr];
}
}