1. PC 端网页特效
1. 元素偏移量offset系列
可以动态得到该元素的位置(偏移)、大小等:
- 可以获取元素距离带有定位父元素的位置
- 获取元素自身的大小(宽度 和 高度)
- offset系列常用于获取元素位置 (但需要注意是否有带定位的父盒子)
- 注意:返回的数值不带单位
offset系列属性 | 返回 |
---|---|
element.offsetParent | 该元素带定位的父元素,如果父级都没有定位则返回body,与element.parentNode()亲爸爸还是有区别的 |
element.offsetTop | 该元素相对带有定位父元素上方的偏移量 |
element.offsetLeft | 该元素相对带有定位父元素左边框的偏移量 |
element.offsetWidth | 自身包括padding + border + content的宽度,返回数值不带单位 |
element.offsetHeight | 自身包括padding + border + content的高度,返回数值不带单位 |
offset 与 style 的区别
offset | style |
---|---|
得到 任意样式表中的 样式值 | 得到行内样式表中的样式值 |
返回数值不带单位 | 带单位的字符串 |
offsetWidth 包含 padding+border+width(盒子大小) | style.width 不包含padding+border(内容大小) |
offsetWidth等属性是 只读属性 | style.width 可读写属性 |
结论:想获取元素大小位置,用offset更合适(读) | 想更改元素值,需要用style改变(写) |
【案例:拖动的模态框(登录框)遮挡层 —— 可以鼠标拖动 】
//仿京东放大镜效果
var preview_img = document.querySelector('.preview_img') //小图片盒子
var mask = preview_img.children[1] //遮罩层
var big = preview_img.children[2] //大图片盒子
var bigImage = big.firstElementChild; //大图片
//(1). 鼠标经过小图片盒子 mask和大图片盒子显示,离开隐藏
preview_img.addEventListener('mouseenter', function () {
mask.style.display = 'block'
big.style.display = 'block'
})
preview_img.addEventListener('mouseleave', function () {
mask.style.display = 'none'
big.style.display = 'none'
})
//(2)黄色的遮挡层跟随鼠标移动
//应该是把鼠标在小图片盒子的坐标 给mask
preview_img.addEventListener('mousemove', function (e) {
//(1) 先计算出鼠标在盒子内的坐标 ps: 先看小图片盒子是否有定位
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
//(2) 为了使鼠标在mask中间,-mask 宽高的一半
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
//(3) mask不能超出小图片盒子 +判断条件解决
var maskMaxX = this.offsetWidth - mask.offsetWidth; //移动最大距离=大坐标-小坐标
var maskMaxY = this.offsetHeight - mask.offsetHeight;//100
//移动的最小距离和最大距离
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMaxX) {
maskX = maskMaxX;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMaxY) {
maskY = maskMaxY;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// (4) 大图片盒子移动距离与mask 成比例 maskX / mask 最大移动距离 = big / big最大移动距离
var bigMaxX = bigImage.offsetWidth - big.offsetWidth; //300
var bigMaxY = bigImage.offsetHeight - big.offsetHeight;
var bigX = maskX / maskMaxX * bigMaxX; //根据比例公式计算
var bigY = maskY / maskMaxY * bigMaxY;
bigImage.style.left = -bigX + 'px'; //负值+单位!!
bigImage.style.top = -bigY + 'px';
})
2. 元素可视区client系列
client 翻译过来就是客户端,使用client相关属性可获取元素可视区的相关信息,动态获得该元素的边框大小、元素大小等;
client常用于检测屏幕宽度:
窗口大小变化触 resize事件,可检测屏幕宽度
window.addEventListener('resize', function(){
let w = document.documentElement.clientWidth;
console.log(w);
})
client系列属性 | 返回值 |
---|---|
element.clientTop | 元素上边框大小 |
element.clientLeft | 元素左边框大小 |
element.clientWidth | 自身包括padding+content宽度,不含border,不含单位 |
element.clientHeight | 自身包括padding+content高度,不含border,不含单位 |
立即执行函数
普通函数 声明调用再执行;立即执行函数不需要调用,立刻自己执行,也可以传递参数,多个立即执行函数需要加分号;隔开
写法:第二个括号可以看做调用函数
立即函数最大的作用就是 独立创建了一个作用域
flexible.js 分析
整个js文件内部就是一个立即执行函数,不需要调用就能立即执行;
同时,由于所有独立局部变量都在该作用域中,并不会与其它引入的js文件发生命名冲突
1. (function (){})()
2. (fucntion(){}())
pageshow事件
当一条会话历史记录被执行的时候将会触发页面显示(pageshow
)事件。(这包括了后退/前进按钮操作,同时也会在onload 事件触发后初始化页面时触发),根据该事件对象persisted属性可以判断是否 是 缓存中的页面触发pageshow事件,注意,这个事件是给window添加。
3. 元素滚动scroll系列
scroll
系列的相关属性可以动态获得该元素的大小、滚动距离等,当滚动条发生变化会触发滚动事件onscroll
scroll常用于获取滚动距离,监听整个页面的滚动,是给window
或document
添加scroll
事件,监听某个元素内部滚动直接给某元素加即可,不包含滚动条
scroll系列属性 | 返回值 |
---|---|
element.scrollTop | 返回被卷去的上侧距离,不带单位,可读写 |
element.scrollLeft | 返回被卷去的左侧距离,不带单位,可读写 |
element.scrollWidth | 返回内容实际宽度,不带单位(因为实际宽度可能超出限定区域,才能加滚动条,获得scroll事件) |
element.scrollHeight | 返回内容实际高度,不带单位 |
window.pageYOffset | 整个页面被卷去的头部)【常用返回头部案例】 |
window.pageXoffset | 整个页面被卷去的左部 |
document.documentElement.scrollTop | 页面滚动的头部,可读写(老写法) |
document.documentElement.scrollLeft | 页面滚动的左侧,可读写(老写法) |
案例: 仿淘宝固定侧边栏
滚动到banner上边沿 侧边栏固定
滚订到main主体区域 侧边栏添加 返回头部 功能
页面被卷去的头部:window.pageYOffset
页面被卷去的左部:window.pageXOffset
var backUp = document.querySelector('.back_top');
var sideBar = document.querySelector('.side_bar');
var banner = document.querySelector('.banner');
var mainBox = document.querySelector('main');
var bannerTop = banner.offsetTop; //被卷到banner位置大小
var mainTop = main.offsetTop; //被卷到main位置大小
document.addEventListener('scroll', function (e) { //监听整个页面滚动给 window 或 document 加
if (window.pageYOffset >= mainTop){
backUp.style.display = 'block';
} else if (window.pageYOffset >= bannerTop && window.pageYOffset <= mainTop) {
sideBar.style.position = 'fixed';
sideBar.style.top = '0';
} else {
backUp.style.display = 'none';
sideBar.style.position = 'absolute';
sideBar.style.top = h + 'px';
}})
4. 动画函数封装
核心原理:通过定时器setInterval()
不断移动盒子距离
- 获得盒子当前的移动距离
- 让盒子在当前位置+1个移动距离
- 利用定时器不断重复该操作
- 加1个结束定时器的条件
- 注意:此元素需要定位,才能使用
element.stytle.left
,而且移动也不会影响其它盒子的摆放
简单动画函数封装:需要2个参数:动画对象 + 结束条件
function animate(obj, target, callback) { //目标对象 目标位置 回调函数(原函数执行完了才会执行)
var step = (target - obj.offsetLeft) / 10; //减速运动 但永远到不了终点 定时器永远关不掉
clearInterval(obj.timer) //如果点击触发动画 则点击速度越快 动画频率越快 因为开启了太多定时器 需要清除以前的定时器
//var timer = setInterval(function () { //不同对象调用需要开辟不同的内存空间 性能优化
obj.timer = setInterval(function () { //解决方法:封装为对象方法,给把不同元素记录不同定时器
if (obj.offsetLeft == target) {
clearInterval(obj.timer)
callback && callback(); //短路运算 都为真 则有callback传进来才会执行
} else {
obj.style.left = obj.offsetLeft + 1 + 'px';}}, 30)} //匀速动画
if (step <= 1) {
obj.style.left = target + 'px'; // 使得缓动动画 条件满足
} else {
obj.style.left = obj.offsetLeft + step + 'px';}}, 30)} //缓动动画
}
var div = document.querySelector('div')
animate(div, 500)
- 缓动动画:让元素的速度有所变化,最常见的就是让速度慢慢停下来(匀速动画)
原理:让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
核心算法:(目标值 - 现在位置)/ 10 作为每次移动的距离步长
(但这样其实永远也到不到终点,定时器也无法关闭,需要加判断条件)
-
动画函数添加回调函数
原理:函数A 可以作为 函数B的一个参数,当函数B执行完了,再执行函数A,这个过程就叫做回调 -
图片无缝滚动原理:在最后插入第一张图(节点的深拷贝),这样两端切换就不会有过渡问题
-
从最后一张到第一张,可以正常轮播下一张(下一张就是第一张),再迅速跳回第一张
-
从第一张到最后一张,可以迅速跳到最后一张(就是第一张),再正常轮播上一张
-
-
节流阀:防止轮播图连续点击造成播放过快
- 原理:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发
- 设置flag变量(相当于水龙头),先关闭水龙头,利用回调函数当动画执行完毕,再打开true
轮播图 / 焦点图
需求分析:
1. 鼠标经过轮播图 左右按钮显示轮播前后 离开隐藏
2. 鼠标点击 左右按钮 轮播图对应播放
3. 对应图片的 小圆点 index高亮 //小圆点的个数应该动态生成
4. 鼠标放在 小圆点上 对应显示轮播图
5. 自动播放轮播图(类似于右键功能)
6. 鼠标经过轮播图,停止自动播放
图片无缝滚动原理,在最后插入第一张图(节点的深拷贝),这样两端切换就不会有过渡问题
从最后一张到第一张,可以正常轮播下一张(下一张就是第一张),再迅速跳回第一张
从第一张到最后一张,可以迅速跳到最后一张,再正常轮播上一张
window.addEventListener('load', function () {
var focusBox = document.querySelector('.focus') //有定位的父盒子
var arrowR = focusBox.children[0]
var arrowL = focusBox.children[1]
var imgs = focusBox.children[2]
var dots = focusBox.children[3]
var w = focusBox.offsetWidth; //轮播框宽度,也就是移动距离的基数
console.log(w);
console.log(focusBox.children);
// (1) 鼠标经过对应显示左右箭头
focusBox.onmouseenter = function () {
arrowL.style.display = 'block'
arrowR.style.display = 'block'
clearInterval(timer)
timer = null;
}
focusBox.onmouseleave = function () {
arrowL.style.display = 'none'
arrowR.style.display = 'none'
timer = setInterval(function () {
arrowR.click();
}, 2000)
}
var len = imgs.children.length; //轮播图的数量
//小圆点个数对应初始轮播图数量len动态生成
for (var i = 0; i < len; i++) {
let dot = document.createElement('li')
dot.setAttribute('data-index', i)
// dot.innerHTML = "<a href='JavaScript:;'></a>"
dots.appendChild(dot)
}
dots.firstElementChild.classList.add('current') //默认第一个小圆点当前点
// (3) 对应滚动到 小圆点位置的图片
for (var i = 0; i < len; i++) {
dots.children[i].addEventListener('mouseover', function () {
for (var i = 0; i < len - 1; i++) {
dots.children[i].classList.remove('current')
}
this.classList.add('current')
index = this.getAttribute('data-index') //index是全局变量,因为要和左右按钮联动
animateSlow(imgs, -index * w)
})
}
//(2) 左右箭头切换图像 声明自增变量
//要克隆第一张图片到最后 实现无缝滚动的原理
var li = imgs.firstElementChild.cloneNode(true)
imgs.appendChild(li)
len = imgs.children.length
var index = 0; //默认index从0开始
var dotNum = dots.children.length;
arrowL.addEventListener('click', function () {
// 如果走到了第一张,index=0,就快速回到最后一张
if (index == 0) {
index = len - 1;
imgs.style.left = -index * w + 'px';
}
index--;
for (var i = 0; i < dotNum; i++) {
dots.children[i].classList.remove('current')
}
dots.children[index % dotNum].classList.add('current')
animateSlow(imgs, -index * w)
})
arrowR.addEventListener('click', function () {
//如果走到了最后一张图 index=5,就快速回到起点,
if (index == len - 1) {
index = 0;
imgs.style.left = -index * w
}
index++;
for (var i = 0; i < dotNum; i++) {
dots.children[i].classList.remove('current')
}
dots.children[index % dotNum].classList.add('current')
animateSlow(imgs, -index * w)
})
//轮播图自动播放
var timer = setInterval(function () {
//手动调用点击事件
arrowR.click();
}, 2000)
// 不能事件委托到ul身上 因为容易误触,ul没有index属性返回null,图片滑动回第一张
// dots.addEventListener('mouseover', function (e) {
// for (var i = 0; i < len - 1; i++) {
// dots.children[i].classList.remove('current')
// }
// console.log(e.target);
// e.target.classList.add('current')
// let index = e.target.getAttribute('data-index')
// console.log(index);
// animateSlow(imgs, -index * w)
// })
})
案例:带有动画的返回顶部 window.scroll(x,y)
function animateSlow(obj, target, callback) { //目标对象 目标位置
clearInterval(obj.timer)
obj.timer = setInterval(function () {
var step = (target - window.pageYOffset) / 10;
if (window.pageYOffset == target) {
clearInterval(obj.timer)
callback && callback();
} else {
if (Math.abs(step) <= 1) {
window.scroll(0, target)
} else {
window.scroll(0, window.pageYOffset + step)}}}, 20)
}
animateSlow(window, 0)
2. 移动端特效
移动端浏览器兼容性较好,不需要考虑以前JS的兼容性问题,可以放心使用原生JS书写效果,但移动端也有 自己独特的地方。比如触屏事件touch,Android和IOS都有。
1. 触屏事件
-
触屏事件
touch对象代表一个触摸点,触摸点可能是一根手指或触摸笔。触屏事件可响应其对屏幕或触控板操作。常见触屏事件如下:
touch触摸事件 说明(都有自己各自的事件对象) touchstart 手指触摸到一个DOM元素时触发 touchmove 手指在一个DOM元素上滑动时触发,默认移动屏幕操作,e.preventDefault()阻止 touchend 手指从一个DOM元素上移开时触发 -
触摸事件对象(TouchEvent)
touchEvent是一类描述手指在触摸平面的状态变化事件,这类事件用于描述一个或多个触点,使开发者可以检测触点的移动、增加和减少等,可以得到触点的坐标
触摸列表 说明 touches 正在触摸屏幕的所有手指的一个列表 targetTouches 正在触摸当前DOM元素上的所有手指的列表 changedTouches 手指状态发生了改变的列表,从无到有,从有到无的变化 -
案例:移动端拖动元素
- 方案1:DOM元素相对于触点坐标不变
- 方案2:DOM元素初始位置 + 触点的移动距离
2. 移动端常见特效
移动端轮播图——独特之处:
1. 无缝滚动 需要将第一张添加到最后一张后,需要将最后一张添加到第一张前,因为pc端为鼠标点击,可以实现快速跳转,但是移动端为触摸点拖动,来不及快速跳转
图片编号: 3 1 2 3 1
索引编号: -1 0 1 2 3
2. .focus ul {width: 500%; } //需要装多少张图片,就将宽度设置为x倍
移动端有个很大的问题,宽度是根据父元素确定的,当上面ul的宽度为 500% 时,
ul li img 继承的宽度也是 500% ,不是我们想要的效果
所以需要给 li 限制宽度,li继承ul, 所以li 的 width 为 1/5* 100%
3. 因为移动端没有兼容的问题,可以放心使用css3,所以不需要麻烦js动画函数
可以直接用过渡效果 transition: all .3s
但播放到最后一张要实现快速跳转 需要监听过渡完成事件 transitionend
4. 当前小圆点有单独的样式属性 定义在current类,可以通过切换类实现点击小圆点current
element.classList.toggle('className');
//原始写法
for (var i = 0; i < dots.length; i++) {
dots[i].classList.remove('current')}
//最新写法
ol.querySelector('.current').classList.remove('current')
ol[index].classList.add('current')
5. 手指滑动轮播图:本质就是ul跟随手指移动,简单来说就是移动端拖动元素
设置一个 标准 滑动距离超过则上/下一张, 不超过则恢复
由于小圆点对应高亮显示代码由transitionend事件触发
index只能取 0,1,2,而实际上index可以取 -1,0,1,2,3
所以在触点离开事件里,还需要当 index=3 取 0 index=-1 则取 2
瀑布流 实现原理
多行等宽元素排列,后面的元素依次添加到其后。
即:等宽不等高,图片按比例缩放至设定宽度,依次往后追加
注意:
1. 第二行 并不是按照左对齐一次排放的,而是会插入第一行所有列高度最小的元素下方
2. 父元素清除浮动,高度取列表数组的最大值
3. 移动端常用开发插件
移动端要求是快速开发,所以经常需要借助一些插件。
js插件就是js文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用,如轮播图和瀑布流插件
特点:一般是为了解决某个问题存在的,功能单一,文件小
click 延时解决方案
移动端click事件会有 300ms 的延时,原因是移动端双击会缩放(double tap to zoom)页面
解决方案:
1. 禁用缩放:<meta name="viewport" content="user-scable=no">
2. 利用touch事件自己封装这个事件解决300ms延时
1. 记录首次触摸屏幕时间
2. 记录离开屏幕时间 减去 获得 2次触摸间隔
3. 间隔时间小于150ms,并且没有滑动屏幕,则定义为点击
3. fastclick插件:网址:https://github.com/ftlabs/fastclick
2. 利用touch事件自己封装这个事件解决300ms延时 1. 记录首次触摸屏幕时间 2. 记录离开屏幕时间 减去 获得 2次触摸间隔 3. 间隔时间小于150ms,并且没有滑动屏幕,则定义为点击 3. 移动端要求是快速开发,所以经常需要借助一些插件 js插件就是js文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用,如轮播图和瀑布流插件 特点:一般是为了解决某个问题存在的,功能单一,文件小 网址:https://github.com/ftlabs/fastclick
1. Swiper插件的使用
1. 引入插入相关文件
2. 按照规定的语法使用
3. 使用方法:https://www.swiper.com.cn/usage/index.html
4. 注意不要更改里面的结构和类名,不然css和js都要对应更改,较为麻烦
2. TouchSlide/superslide插件
TouchSlide 是纯javascript打造的触屏滑动特效插件,面向手机、平板电脑等移动终端,
能实现触屏焦点图、触屏Tab切换、触屏多图切换等常用效果。
插件开源、体积小、简单实用、功能强大,是你架构移动终端网站的重要选择!
3. zy.media.js
H5 提供 video 标签,但浏览器的支持情况不同
不同视频格式文件,可以通过source解决
但是外观样式、还有 暂停、播放、全屏等功能只能自己写代码解决
可以通过插件方式制作
插件使用总结
- 确认插件实现的功能
- 去官网查看使用说明
- 下载插件
- 打开demo实例文件,查看需要引入的相关文件,并引入
- 分别复制demo实例文件中的html、css和js代码
4. 移动端常用开发框架
什么是框架:顾名思义就是一套架构,基于自身的特点向用户提供一套完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。
前端常用框架:bootstrap
、Vue
、Angular
、React
等,既能开发PC端,也能开发移动端
前端常用移动端插件:swiper
、superslide
、iscroll
等
总结:框架大而全,一整套解决方案;插件小而专一,某个功能的解决方案
jQuery
jQuery是JavaScript库,是封装好的特定的函数或方法的集合,比如获取元素、animate、hide、show等
作用:优化DOM操作,事件处理,动画设计和Ajax交互
原生JavaScript(楼梯)—— Jquery(电梯)
特点:轻量级、跨浏览器兼容、支持插件扩展,免费开源,链式编程、隐式迭代
使用css选择器选取元素,作为为客户端脚本库,可以和Ajax一起使用。简写为$符号
,
注意:Jquery对象只能使用Jquery方法,DOM对象只能使用JS原生方法,不能混用,因为互不认识,jQuery用$()
将DOM对象以伪数组的形式
封装为jQuery对象。但二者之间需要转换,因为jQuery毕竟只封装了常用的、使用频率高的DOM方法,所以还有用原生DOM API的需求。
基础语法:$(selector).action() //$其实就是jQuery的别称,同时也是jQuery的顶级对象,相当于原生JS中的window。
入口函数
1. $(function(){ //相当于window.addEventListener('load', function())
--- jQuery functions go here ----
})
2. $(document).ready(function(){ //相当于window.addEventListener('DOMContentLoaded', function())
--- jQuery functions go here ----
});
DOM对象转换为jQuery对象:$(DOM对象)
jQuery对象转换为DOM对象:$('jQuery对象')[index] $('jQuery对象').get(index)
JQuery常用API
1. 选取元素:$("css选择器")
2.样式操作 $("css选择器").css("属性", "属性值") $("div").css("color", "pink") //所有div都会变色(隐式迭代)
隐式迭代:Jquery对象以伪数组的形式存储DOM元素,其遍历内部DOM的过程叫做隐式迭代
简单理解:jQuery会给匹配到的所有元素进行遍历循环,执行对应的方法,不用我们手动循环伪数组
3. 筛选选择器:类似于css的 结构为类选择器 E:nth-child(n)
4. 筛选方法:parent(亲爸爸) children(亲儿子) parents(列祖列宗) find(后代) siblings(兄弟们) eq(第几个)
5. 排他思想
先设置自己的样式A,再设置其它兄弟的样式B
$('button').mouseover(function () {
$(this).css('backgroundColor', '#f5f5f5');
$(this).siblings().css('backgroundColor', '#fff')
});
6. 链式编程(yyds)
$('button').mouseover(function () {
$(this).css('color', '#f5f5f5').siblings().css('color', '#fff')
});
6. 得到当前元素的索引号 $(this).index() 这个太棒了!!!可以做选项卡tab栏标签和内容对应切换案例
7. JQuery效果:
显示/隐藏/切换 show([speed],[callback]) hide() toggle()
淡入/淡出 fadein([speed],[callback]) fadeout() fadeToggle()
上拉/下拉 slideUp([speed],[callback]) slideDwon() slideToggle()
动画 animate({params},speed,callback)
动画和效果的区别,动画的父亲要加定位,因为有位置的偏移,效果只是一种transition过渡罢了
stop() 方法用于停止动画或效果事件的排队,清空队列,防止短时间多次触发导致效果反复执行情况产生
8. 属性操作
1. prop设置/获取属性
$('input').prop('checked', 'true') //设置自带属性
$('input').prop('checked') //获取自带属性
2. attr设置/获取属性
$('input').attr('data-index', '1') //设置自定义属性,也可以设置自带属性
$('input').attr('data-index') //获取自定义属性。其实也可以获取自带属性 全能王
2. data数据缓存 方法里的数据是放在元素的内存里面的,也可以获取自定义属性
$('span').data("uname", "andy")
9. 内容文本值
html() 获取元素内容 相当于 innerHTML
html('内容') 设置内容
text() 相当于innerText 只想得到文本
text('内容')
$('input').val() 获取表单元素的值
10. 元素操作
主要是遍历、创建、添加、删除元素操作(增删查改)
1. 遍历
$(selector).each(function(index, domEle){}) 具体理解看我另一篇文章
$.each(arr, function(index, value){}) 主要用于遍历数据、处理数据、对象,全能王
2. 添加元素
append() prepend() - 子元素添加 before() after() - 兄弟元素添加