JavaScript—— PC 端网页特效
Posted imByte
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript—— PC 端网页特效相关的知识,希望对你有一定的参考价值。
本篇为 javascript 系列笔记第八篇,将陆续更新后续内容。参考:黑马程序员JavaScript核心教程,前端基础教程
系列笔记:
JavaScript(一)—— 初识JavaScript / 注释 / 输入输出语句 / 变量 / 数据类型
JavaScript(二)—— 运算符 / 流程控制 / 数组
JavaScript(三)—— 函数 / 作用域 / 预解析 / 对象
JavaScript(四)—— 内置对象 / 简单数据类型与复杂类型
JavaScript(五)—— Web APIs 简介 / JavaScript 必须掌握的 DOM 操作
文章预览
「一」元素偏移量 offset
offset 系列相关属性可以 动态的 得到该元素的位置(偏移)、大小等:
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度、高度)
- 返回的数值不带单位
offset 系列常用属性如下:
offsetTop
、offsetLeft
属性
- 父亲有定位,则以 父亲 为准,返回 45
- 父亲无定位,则以 body 为准,返回 195
offsetWidth
、offsetHeight
属性
- 计算数值时包含
padding
、border
、width
- 可以动态获取数值,比如浏览器缩小时,数值相应变化
offsetParent
属性
- 返回带有定位的父亲,否则返回 body
- 与节点操作中
parentNode
相比,parentNode
返回最近一级的父亲,无论父亲是否有定位
- offset 与 style 区别
offset
- offset 可以得到任意样式表中的样式值
- offset 系列获得的数值是没有单位的
- offsetWidth 包含 padding、border、width
- offsetWidth 等属性是只读属性,只能获取不能赋值
- 只想获取元素大小位置,offset 更合适
style
- style 只能得到行内样式表中的样式值
- style.width 获得的是带有单位的字符串
- style.width 获得不包含 padding 和 border 的值
- style.width 是可读写属性,可以获取也可以赋值
- 要想给元素更改值,需要用 style
- 案例:获取鼠标在盒子内的坐标
var box = document.querySelector('.box');
box.addEventListener('mousemove', function (e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerhtml = 'x坐标是' + x + ' y坐标是' + y;
})
box.addEventListener('mouseout', function () {
this.innerHTML = '';
})
- 案例:模态框拖拽
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
// 显示
link.addEventListener('click', function () {
mask.style.display = 'block';
login.style.display = 'block';
})
// 隐藏
closeBtn.addEventListener('click', function () {
mask.style.display = 'none';
login.style.display = 'none';
})
// 拖拽
title.addEventListener('mousedown', function (e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
document.addEventListener('mousemove', move);
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
})
})
- 鼠标按下
mousedown
,获取鼠标在盒子中坐标 - 鼠标移动
mousemove
,求得模态框的left
、top
- 鼠标弹起
mouseup
,移除注册事件removeEventListener
- 案例:仿京动放大镜
部分 HTML 代码
<div class="preview_img">
<img src="img/mac_small.jpg" alt=""> <--小图-->
<div class="mask"></div> <--遮罩-->
<div class="preview_img_big"> <--大图-->
<img src="img/mac_big.jpg" alt="" class="big_img">
</div>
</div>
部分 CSS 代码
.preview_img {
position: relative;
height: 450px;
border: 1px solid #ccc;
}
.mask {
display: none;
position: absolute;
left: 0;
top: 0;
width: 300px;
height: 300px;
background: #FEDE4F;
opacity: .5; /* 不透明度 */
border: 1px solid #ccc;
cursor: move; /* 鼠标样式为移动 */
}
.preview_img_big {
display: none;
position: absolute;
left: 450px;
top: -1px;
width: 540px;
height: 540px;
border: 1px solid #ccc;
overflow: hidden;
}
.big_img {
position: absolute;
top: 0;
left: 0;
}
JS 代码
window.addEventListener('load', function () {
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.preview_img_big');
preview_img.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
})
preview_img.addEventListener('mousemove', move);
function move(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// 减去遮罩盒子高度一半
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// 最大移动距离(宽高相等)
var maskMax = preview_img.offsetWidth - mask.offsetWidth;
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskMax) {
maskX = maskMax;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskMax) {
maskY = maskMax;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 获得大图片
var big_img = document.querySelector('.big_img');
// 最大移动距离
var bigMax = big_img.offsetWidth - big.offsetWidth;
var bigX = maskX * bigMax / maskMax;
var bigY = maskY * bigMax / maskMax;
big_img.style.left = -bigX + 'px';
big_img.style.top = -bigY + 'px';
}
preview_img.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
})
})
注意:
- 若将 js 文件放在 html 上面,注意一定要先加载窗口
window.addEventListener('load', function(){})
,否则注册事件绑定为空,出现报错
- 理解遮罩层和放大图片移动的算法
「二」元素可视区 client
通过 client 相关属性可以动态的得到该元素的边框大小、元素大小
- client 系列和 offset 系列区别
「三」元素滚动 scroll
使用 scroll 相关属性可以动态得到该元素的大小、滚动距离等
onscroll
事件
如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条,当滚动条向下滚动时,会触发 onscroll
事件
- 案例:仿淘宝固定右侧侧边栏
部分 HTML 代码
JS 代码
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
var bannerTop = banner.offsetTop;
var sliderbarTop = sliderbar.offsetTop - bannerTop;
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
document.addEventListener('scroll', function (e) {
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
注意:页面被卷去的头部,有兼容问题,通常有下面几种写法:
- 声明了 DTD(
<!DOCTYPE html>
),使用document.documentElement.scrollTop
- 未声明 DTD,使用
document.body.scrollTop
- IE9 开始,新方法
window.pageYOffset
、window.pageXOffset
「四」动画函数
- 动画实现原理
通过定时器 setInterval()
不断移动盒子位置。实现步骤:
- 获得盒子当前位置
- 通过定时器不断重复移动单位距离(需要添加定位,使用
element.style.left
) - 添加结束定时条件
- 动画函数的封装
可能一个页面中会多次调用动画过程,因此可以将其封装成函数。
注意:函数需要传递 2 个参数,动画对象 和 移动的距离
function animate(obj, target) {
var timer = setInterval(function () {
if (obj.offsetLeft >= target) {
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 2 + 'px';
}, 10)
}
- 动画函数给不同元素记录不同定时器
若每次调用都声明 var timer
变量,会造成占用大量内存以及重复命名歧义等问题。因此,这里利用给对象添加属性的方式进行赋值操作 obj.timer
,实现了不同元素指定不同定时器
- 为避免持续点击导致开启多个定时器,应在函数调用开始时清除所有定时器
- 为避免停止后点击还会少量移动问题,在到达指定距离后,
return
结束函数调用
- 缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的是逐渐降速到停止,使得效果更加自然
算法: 步长 = (目标位置 - 当前位置)/ 10
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
- 避免小数问题导致最后无法运动到指定
target
, 这里利用了向上取整 - 此外,考虑到后退过程,向上取整也出现了问题。因此需要分类来讨论
- 动画函数添加回调函数
回调函数原理:函数可以作为一个参数,作为传递到另一个函数中
function animate(obj, target, callback) {} // callback 回调函数
animate(span, 500, function () {});
- 动画函数封装到单独 JS 文件中
以后会经常使用动画函数,因此可以将其单独封装到一个 JS 文件中,使用时直接引用 JS 文件即可
- 案例:滑动盒子
<div class="sliderbar">
<span>←</span>
<div class="con">问题反馈</div>
</div>
<script>
var sliderbar = document.querySelector('.sliderbar');
var con = document.querySelector('.con');
sliderbar.addEventListener('mouseenter', function () {
animate(con, -160, function () {
sliderbar.children[0].innerHTML = '→';
});
})
sliderbar.addEventListener('mouseleave', function () {
animate(con, 0, function () {
sliderbar.children[0].innerHTML = '←';
});
})
</script>
mouseenter
、mouseleave
和mouseover
、mouseout
用法一样,区别在于前者无法冒泡- 注意要引用 animate.js
「五」常见网页特效案例
- 案例:淘宝轮播图
JS 代码主要利用
- animate.js 代码
function animate(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
clearInterval(obj.timer);
callback && callback();
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
- index.js 代码
window.addEventListener('load', function () {
var arrow_l = document.querySelector('.arrow-l');
var arrow_r = document.querySelector('.arrow-r');
var focus = document.querySelector('.focus');
var focusWidth = focus.offsetWidth;
// 鼠标经过 focus 显示隐藏左右按钮
focus.addEventListener('mouseenter', function () {
arrow_l.style.display = 'block';
arrow_r.style.display = 'block';
// 鼠标经过停止自动轮播
clearInterval(timer);
timer = null; // 清除定时器变量
})
focus.addEventListener('mouseleave', function () {
arrow_l.style.display = 'none';
arrow_r.style.display = 'none';
timer = setInterval(function () {
//手动调用点击事件
arrow_r.click();
}, 2000);
})
// 动态生成小圆圈
var ul = focus.querySelector('ul');
var ol = focus.querySelector('.circle');
for (var i = 0; i < ul.children.length; i++) {
var li = document.createElement('li');
// 淘宝源码中 li 中又创建了 a,其实在这里不创建 a 也可以,本案例暂以上是关于JavaScript—— PC 端网页特效的主要内容,如果未能解决你的问题,请参考以下文章