11 offset系列 client系列 立即调用函数 flexible分析 更多事件 更多事件对象 scroll系列 offset、client、scroll系列的总结 实战演习
offset系列
属性
offsetParent
返回作为该元素带有定位的父级元素 如果父级都没有定位则返回body
补充
与parentNode属性的区别:parentNode属性返回最近的父亲,无论是否有定位
offsetTop
返回元素相对带有定位父元素上方的偏移
offsetLeft
返回元素相对带有定位父元素左边框的偏移
offsetWidth
返回自身包括padding、边框、内容区的宽度,返回数值不带单位
offsetHeight
返回自身包括padding、边框、内容区的高度,返回数值不带单位
例子
缓动动画
原理是运动越来越慢,所以每个时间的速度要越来越慢
<button>点击夏雨荷才走</button>
<span>夏雨荷</span>
<script>
// 缓动动画函数封装obj目标对象 target 目标位置
// 思路:
// 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
// 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
// 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
function animate(obj, target) {
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步长值写到定时器的里面
var step = (target - obj.offsetLeft) / 10;
//var step = target/ 10;
if (obj.offsetLeft == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 调用函数
animate(span, 500);
})
// 匀速动画 就是 盒子是当前的位置 + 固定的值/10
// 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
</script>
拖动的模态框
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
ul,
li,
ol,
dl,
dt,
dd,
div,
p,
span,
h1,
h2,
h3,
h4,
h5,
h6,
a {
padding: 0px;
margin: 0px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, .3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<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>
<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)
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>
</body>
</html>
补充:回调函数的使用
语法
function fun(callback){
if(callback){//如果存在回调函数
callback();//则调用
}
}
client系列
clientTop
返回元素上边框的大小
clientLeft
返回元素左边框的大小
clientWidth
返回自身包括padding、内容区的宽度,不含边框,返回数据不带单位
clientHeight
返回自身包括padding、内容区的高度,不含边框,返回数据不带单位
立即调用函数
不需要调用,立刻能够自己执行的函数,通常来说,函数都需要调用
function fn(a){
console.log(a);
}
fn(1);
但有一些写法可以使函数在定义后立刻调用
(function fn(a){
console.log(a);
})(1);
(function fn(a){
console.log(a);
}(1));
这样做独立创建了一个作用域,里面所有的变量都是局部变量
flexible分析
//立即调用函数
(function flexible(window, document) {
// 获取的html 的根元素
var docEl = document.documentElement
// dpr 物理像素比 一般来说 电脑是1 手机是2
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)
// pageshow 是我们重新加载页面触发的事件
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))
补充
pageshow事件
load事件触发条件是当刷新、a标签的超链接、前进后退按钮等刷新页面的情况,部分浏览器前进后退按钮会缓存页面从而不触发load,但是触发pageshow事件,配合事件对象中的persisted可以判断是否是缓存中的页面触发的pageshow事件
更多事件
触摸事件
触摸事件的默认事件是屏幕滚动,当组织默认事件可以阻止屏幕滚动
touchstart
手指触摸DOM元素事件
touchmove
手指在DOM元素身上移动事件
touchend
手指离开DOM元素事件
mouseenter
鼠标进入元素时触发
补充
在08 更多事件 自定义属性操作 节点操作 实战演练中的更多事件中曾经提到过onmouseover事件
onmouseover
鼠标经过事件
mouseenter和mouseover事件最大的区别就在于mouseover经过本身盒子会触发,经过子盒子也会触发,而mouseenter只在自身盒子触发
更多事件对象
touches
正在触摸屏幕的所有手指的列表
转载自https://developer.mozilla.org/zh-CN/
一个 TouchList,其会列出所有当前在与触摸表面接触的 Touch对象,不管触摸点是否已经改变或其目标元素是在处于 touchstart 阶段。
targetTouches
正在触摸当前DOM元素的手指列表 如果侦听的是一个DOM元素,他们两个是一样的
转载自https://developer.mozilla.org/zh-CN/
一个 TouchList,包含仍与触摸面接触的所有触摸点的 Touch 对象,touchstart事件触发在哪个element内,它就是当前目标元素。
changedTouches
手指状态发生了改变的列表 从无到有 或者 从有到无
转载自https://developer.mozilla.org/zh-CN/
列出对应这个触摸事件的 Touch对象的TouchList对象。
touches、targetTouches、changedTouches补充
因为我们一般都是触摸元素 所以最经常使用的是 targetTouches
当我们手指离开屏幕的时候,就没有了 touches 和 targetTouches 列表,但是会有 changedTouches
scroll系列
scrollTop
返回被卷去的 上侧距离,返回数值不带单位
scrollLeft
返回被卷去的 左侧距离,返回数值不带单位
scrollWidth
返回自身实际的宽度,不含边框,返回数值不带单位,与clientWidth的区别在于scrollWidth包含实际内容(包括溢出盒子的部分)
scrollHeight
返回自身实际的高度,不含边框,返回数值不带单位,与clientHeight的区别在于scrollHeight包含实际内容(包括溢出盒子的部分)
offset、client、scroll系列的总结
offset系列
经常用于获得元素位置
client系列
经常用于获取元素大小
scroll系列
经常用于获取滚动距离
实战演习
图片放大镜
要求
要求鼠标放到照片上,照片的右侧就会显示一个放大后的图片(内容为后续所说的正方形中的内容),且以鼠标为中心做出一个正方形于照片上,若无法放置则偏离中心以致可以放置
代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>图片放大镜</title>
<style type="text/css">
.bei_fang_da{
position: relative;
float: left;
width: 500px;
height: 321px;
}
.bei_fang_da img{
}
.bei_fang_da div{
display: none;
position: absolute;
top: 0px;
left: 0px;
width: 200px;
height: 200px;
background-color: rgba(164, 194, 207,.4);
}
.fang_da{
display: none;
float: left;
position: relative;
width: 300px;
height: 300px;
border: 1px solid aqua;
overflow: hidden;
}
.fang_da img{
position: absolute;
top: 0px;
left: 0px;
width: 750px;
height: 481.5px;
}
</style>
</head>
<body>
<div class="magnifying_glass">
<div class="bei_fang_da">
<img src="./images/图片.jpg" >
<div></div>
</div>
<div class="fang_da">
<img src="./images/图片.jpg">
</div>
</div>
<script type="text/javascript">
beiFangDa=document.getElementsByClassName('bei_fang_da')[0];
beiFangDaImg=document.querySelector('.bei_fang_da img');
beiFangDaDiv=document.querySelector('.bei_fang_da div');
fangDa=document.getElementsByClassName('fang_da')[0];
fangDaImg=document.querySelector('.fang_da img');
beiFangDa.addEventListener('mouseover',function(e){
beiFangDaDiv.style.display='block';
fangDa.style.display='block';
});
beiFangDa.addEventListener('mousemove',function(e){
var x=e.pageX-beiFangDa.offsetLeft-100;
var y=e.pageY-beiFangDa.offsetHeight+200;
if(x<=300&&x>=0){
beiFangDaDiv.style.left=x+'px';
fangDaImg.style.left=((x+100)*-3/2+150)+'px';
}else{
if(x>300){
beiFangDaDiv.style.left='300px';
fangDaImg.style.left='-450px';
}else{
beiFangDaDiv.style.left='0px';
fangDaImg.style.left='0px';
}
}
if(y>=0&&y<=122){
beiFangDaDiv.style.top=y+'px';
fangDaImg.style.top=((-y-100)*3/2+150)+'px';
}else{
if(y>122){
beiFangDaDiv.style.top='122px';
fangDaImg.style.top='-183px';
}else{
beiFangDaDiv.style.top='0px';
fangDaImg.style.top='0px';
}
}
});
beiFangDa.addEventListener('mouseout',function(e){
beiFangDaDiv.style.display='none';
fangDa.style.display='none';
});
</script>
</body>
</html>