01、PC网页特效导读
02、offsetLeft和offsetTop获取元素偏移
eg:
<script>
// offset 系列
var father = document.querySelector('.father');
var son = document.querySelector('.son');
// 1.可以得到元素的偏移 位置 返回的不带单位的数值
console.log(father.offsetTop);
console.log(father.offsetLeft);
// 它以带有定位的父亲为准 如果么有父亲或者父亲没有定位 则以 body 为准
console.log(son.offsetLeft);
var w = document.querySelector('.w');
// 2.可以得到元素的大小 宽度和高度 是包含padding + border + width
console.log(w.offsetWidth);
console.log(w.offsetHeight);
// 3. 返回带有定位的父亲 否则返回的是body
console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
console.log(son.parentNode); // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位
</script>
03、offsetWidth和offsetHeight获取元素大小、offsetParent返回父亲
见上
04、offset和style的区别
05、案例:获取鼠标在盒子里面的坐标
// 我们在盒子内点击, 想要得到鼠标距离盒子左右的距离。
// 首先得到鼠标在页面中的坐标( e.pageX, e.pageY)
// 其次得到盒子在页面中的距离(box.offsetLeft, box.offsetTop)
// 用鼠标距离页面的坐标减去盒子在页面中的距离, 得到 鼠标在盒子内的坐标
<body>
<div class="box"></div>
<script>
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;
})
</script>
</body>
06-08、拖动模态框
html:
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
<div id="login" class="login">
<div id="title" class="login-title">登录会员
<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
</div>
<div class="login-input">
<label>登录密码:</label>
<input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
</div>
</div>
<div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
js:
<script>
// 1. 获取元素
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');
// 2. 点击弹出层这个链接 link 让mask 和login 显示出来
link.addEventListener('click', function () {
mask.style.display = 'block';
login.style.display = 'block';
})
// 3. 点击 closeBtn 就隐藏 mask 和 login
closeBtn.addEventListener('click', function () {
mask.style.display = 'none';
login.style.display = 'none';
})
// 4. 开始拖拽
// (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
title.addEventListener('mousedown', function (e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
// (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
document.addEventListener('mousemove', move) //这里使用函数名称的原因在于:之后需要用move再移除
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
// (3) 鼠标弹起,就让鼠标移动事件移除
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
})
})
</script>
09-13、仿京东的放大镜效果
1、制作放大镜的框框mask
<div class="preview_img">
<img src="upload/s3.png" alt="">
<div class="mask"></div>
<div class="big">
<img src="upload/big.jpg" alt="" class="bigImg">
</div>
</div>
2、设置样式:
.mask {
display: none;
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
background: #FEDE4F;
/* 半透明效果 */
opacity: .5;
border: 1px solid #ccc;
/* 鼠标经过后,鼠标样式改为十字 */
cursor: move;
}
3、再准备一个放大效果的盒子big
<div class="preview_img">
<img src="upload/s3.png" alt="">
<div class="mask"></div>
<div class="big">
<img src="upload/big.jpg" alt="" class="bigImg">
</div>
</div>
4、大盒子样式
.big {
display: none;
/* 子绝父相 */
position: absolute;
left: 410px;
top: 0;
width: 500px;
height: 500px;
background-color: pink;
/* 设在最外层 */
z-index: 999;
border: 1px solid #ccc;
/* 多余的隐藏起来 */
overflow: hidden;
}
.big img {
/* 子绝父相 */
position: absolute;
top: 0;
left: 0;
}
5、js分析:
①html中引入js文件:
<!-- 引入我们的js 文件 -->
<script src="js/detail.js"></script>
②给所有的js设置load:先加载,然后js
window.addEventListener('load', function()
③获取元素:
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
④当我们鼠标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big 大盒子
preview_img.addEventListener('mouseover', function() {
mask.style.display = 'block';
big.style.display = 'block';
})
preview_img.addEventListener('mouseout', function() {
mask.style.display = 'none';
big.style.display = 'none';
})
⑤鼠标移动的时候伴随放大镜的移动:
1)获取鼠标距离盒子的位置(用e.page和offset做)
2)获取放大镜距离盒子的位置(用1)中的结果减去放大镜的边框即可)
3)考虑放大镜位置的特殊情况(坐标超出边框时按照在边框上处理)
4)更新放大镜的位置(用放大镜的.style.left
和right
做)
// 2. 鼠标移动的时候,让黄色的盒子跟着鼠标来走
preview_img.addEventListener('mousemove', function(e) {
// (1). 先计算出鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// console.log(x, y);
// (2) 减去盒子高度 300的一半 是 150 就是我们mask 的最终 left 和top值了
// (3) 我们mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// (4) 如果x 坐标小于了0 就让他停在0 的位置
// 遮挡层的最大移动距离
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';
⑥放大图片跟随的移动效果
1)由等比例移动的关系:
则:
大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
2)由公式计算
遮挡层移动距离 = maskX/Y
大图片最大移动距离 = 图片的最大宽度-盒子的最大宽度 = bigIMg.offsetWidth - big.offsetWidth
遮挡层的最大移动距离 = maskMax
3)大图的移动方向和放大镜的移动方向相反:
bigIMg.style.left = -bigX + 'px';
bigIMg.style.top = -bigY + 'px';
代码:
// 3. 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
// 大图
var bigIMg = document.querySelector('.bigImg');
// 大图片最大移动距离
var bigMax = bigIMg.offsetWidth - big.offsetWidth;
// 大图片的移动距离 X Y
var bigX = maskX * bigMax / maskMax;
var bigY = maskY * bigMax / maskMax;
bigIMg.style.left = -bigX + 'px';
bigIMg.style.top = -bigY + 'px';
14、client系列
client 宽度 和我们offsetWidth 最大的区别就是 不包含边框border,但是都包含padding
其他基本都一样
15、立即执行函数
立即执行函数: 不需要调用,立马能够自己执行的函数
立即执行函数最大的作用就是 独立创建了一个作用域, 里面所有的变量都是局部变量 不会有命名冲突的情况
写法:
1.(function() {})();
eg:
(function(a, b) {
console.log(a + b);
var num = 10;
})(1, 2); // 第二个小括号可以看做是调用函数
(function(){}());
eg:
(function sum(a, b) {
console.log(a + b);
var num = 10; // 局部变量
}(2, 3));
16、淘宝flexibleJS源码分析之核心原理
(function flexible(window, document) {
// 获取的html 的根元素
var docEl = document.documentElement
// dpr 物理像素比
var dpr = window.devicePixelRatio || 1
// adjust body font size 设置我们body 的字体大小
function setBodyFontSize() {
// 如果页面中有body 这个元素 就设置body的字体大小
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
// 如果页面中没有body 这个元素,则等着 我们页面主要的DOM元素加载完毕再去设置body
// 的字体大小
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10 设置我们html 元素的文字大小
function setRemUnit() {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize 当我们页面尺寸大小发生变化的时候,要重新设置下rem 的大小
window.addEventListener('resize', setRemUnit) // resize指当浏览器页面大小发生了变化时
// pageshow 是我们重新加载页面触发的事件,比load更加灵敏,它会在火狐的后退操作后也发生重新加载
window.addEventListener('pageshow', function (e) {
// e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要从新计算一下rem 的大小
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
17、元素滚动scroll
系列
eg:每滚动一次就记录一下scrollTop
的值
div.addEventListener('scroll', function() {
console.log(div.scrollTop);
})
18、仿淘宝固定侧边栏
需要实现的功能:
html:
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
css略
JS:
首先侧边栏的位置是固定的absolute
当滚动到banner的部分时,更改为fixed
当滚动到main的部分时,出现返回顶部的锚点
①获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
②记录banner和main和侧边栏sliderbar的盒子上面被减去的头部:
var bannerTop = banner.offsetTop;
var mainTop = main.offsetTop;
// 当我们侧边栏固定定位之后应该变化的数值
var sliderbarTop = sliderbar.offsetTop - bannerTop;
③制作页面滚动事件
document.addEventListener('scroll', function () {
// 3 .当我们页面被卷去的头部大于等于了 172(到达了banner处) 此时 侧边栏就要改为固定定位
if (window.pageYOffset >= bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px'; // 固定的位置要处于172处而不是CSS中定义的页面中央,让动画更丝滑
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px'; // 重新把固定位置定位到页面中央,让动画更丝滑
}
// 4. 当我们页面滚动到main盒子,就显示 goback模块
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
21、三大系列总结
22、mouseenter
和mouseover
的区别
23、动画原理
获取用offset,赋值用style
var div = document.querySelector('div');
var timer = setInterval(function() {
if (div.offsetLeft >= 400) {
// 停止动画 本质是停止定时器
clearInterval(timer);
}
div.style.left = div.offsetLeft + 1 + 'px';
}, 30);
24、简单动画函数封装
因为动画需要用到style中的left,而这个属性只有定位才有,所以必须给元素加定位!!!
<script>
// 简单动画函数封装obj目标对象 target 目标位置
function animate(obj, target) {
var timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止动画 本质是停止定时器
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
// 调用函数
animate(div, 300);
animate(span, 200);
</script>
25、动画函数-给不同元素记录不同定时器
用对象.属性
的方法取代var声明变量,从而做到元素都有自己的定时器,比如:div.timer()/p.timer()/btn.timer()
<script>
// 给不同的元素指定了不同的定时器
function animate(obj, target) {
// 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
// 解决方案就是 让我们元素只有一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
// 调用函数
animate(div, 300);
btn.addEventListener('click', function() {
animate(span, 200);
})
</script>