六、PC端网页特效
1.offset元素偏移量
offset翻译过来就是偏移量,使用offset系列相关属性可以动态的得到该元素的位置(偏移量)、大小等
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度+高度)
- 注意:返回数值不带单位
- 会根据浏览器窗口的大小变化
【1】offset常用属性:
(1)element.offsetParent
得到元素的父级元素标签
同node.parentNode但其返回最近一级的父类,同时不管有无定位
- 如果没有父级/父级没有定位
- 返回body
- 如果有父级/父级定位成功
- 返回父级
(2)element.offsetTop
返回距带有定位的父元素的上方的偏移量
- 若没有父亲/父亲没有定位--->以距窗口的距离为准
- 若有父亲/父亲已定位----->以距父亲的距离为准
(3)element.offsetLeft
返回距带有定位的父元素的左边的偏移量
(4)element.offsetWidth
返回元素自身带padding+边框+内容区宽度,不带单位
(5)element.offHeight
返回元素自身带padding+边框+内容区高度、不带单位
【2】.offset与style的区别
offset可以得到元素带padding+边框+内容区的高度+宽度,还有到父类的宽高等,而style也可以用来得到宽高,两者的区别如下:
【行内样式:写在html标签里面的】
【外嵌样式:写在css中,然后通过class类引用的】
(1)offset
①即可得到行内样式,又可以得到外嵌样式
②获得的数值,无单位
③包含padding+边框border+width
④offset是只读的,不可修改赋值
只想获取元素大小位置,用offset
(2)style
①只能得到行内样式,无法获取class类中的
②获得的字符串,带单位
③只包含width
④style是可读写的,可获取也可赋值
想给元素更改值,用style
【案例】获取鼠标在盒子内的坐标
-
思路:
当点击鼠标时,得到鼠标距盒子左右的距离
- 首先通过e.pageX,e.pageY得到在页面的距离
- 再通过box.offsetLeft,box.offsetTop得到盒子距页面左、上的距离
- 两者相见,就是鼠标到盒子的距离
代码如下:
<style> div{ width: 300px; height: 300px; background-color: rgb(183, 121, 40); margin-top: 100px; margin-left: 500px; } </style> <body> <div></div> <script> //1.获取事件 var div = document.querySelector('div'); div.addEventListener('mousemove',function(e){ //鼠标距盒子x的距离:鼠标距页面x-盒子距页面x var x = e.pageX - div.offsetLeft; //鼠标距盒子y的距离:鼠标距页面y-盒子距页面y var y = e.pageY - div.offsetTop; div.innerHTML = 'x坐标是+'+ x + 'y坐标是' + y; }) </script>
【3】模态框拖拽效果
【思路】:
点击登陆-->显示模态框+背景灰色+关闭按钮(链接)
①html+css阶段:
编写模态框带关闭按钮,页面背景灰色,将其display先设置none;
②显示+关闭模态框
点击登陆按钮->设置监听事件click
出现模态框+灰色背景->两者display:block
点击关闭-->两者display:none
③鼠标按下模态框上方:模态框开始移动
- 鼠标按下mousedown,得到鼠标在模态框中的位置
- 鼠标移动mousemove,不断更新模态框的值
- 模态框的位置:鼠标坐标-鼠标在盒子内的坐标
- 即保证鼠标在模态框位置不变
- 又保证模态框处于移动状态(别忘了给更新坐标+px)
- ④鼠标松开:模态框停止移动
- 鼠标松开mouseup,将mousemove的监听事件移除
(注意移除时,先绑定鼠标松开,再移除鼠标移动事件)
(移除时,需要指定移除的函数名,所以事件不能为匿名函数)
【注意鼠标移动+鼠标松开绑定的事件对象都是document】
不断将鼠标移动的值,赋给盒子,盒子就会有跟随效果
- css代码:
<style> h6, a { padding: 0; margin: 0; } .login{ display: none; width: 512px; height: 280px; position: fixed; border: #ebebeb solid 1px; left: 50%; top: 50%; background: #fff; box-shadow: 0 0 20 #ddd; z-index: 9999; transform: translate(-50%,-50%); } .login-title { width: 100%; margin: 10px 0 0 0; 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 0 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: 0; left: 0; background: rgba(0,0,0,.3); } a { text-decoration: none; color: black; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0 0 20px 0; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #fff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; } </style>
- html代码:
<div class="login-header"><a id="link" href="javascript:;"><h6>点击,弹出登录框</h6></a></div> <div 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="username"> </div> <div class="login-input"> <label >登录密码</label> <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="password"> </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 link = document.querySelector('#link'); //②登陆模态框 var login = document.querySelector('.login'); //③关闭按钮 var closeBtn = document.querySelector('#closeBtn'); //④上方移动条 var title = document.querySelector('.login-title'); //⑤灰色背景 var bg = document.querySelector('.login-bg'); //2.点击可显示登陆模态框 link.addEventListener('click',function(){ login.style.display = 'block'; bg.style.display = 'block'; }) //3.点击关闭可取消登陆模态框 closeBtn.addEventListener('click',function(){ login.style.display = 'none'; bg.style.display = 'none'; }) //4.开始拖拽 //(1)鼠标按下盒子顶部后,获得鼠标在盒子内的坐标,设置盒子的坐标 title.addEventListener('mousedown',function(e){ var x = e.pageX-login.offsetLeft; var y = e.pageY-login.offsetTop; //(2)鼠标移动后,盒子坐标:鼠标在页面的坐标-鼠标在盒子内的坐标 document.addEventListener('mousemove',move) //移动事件,因为之后会移除,所以不能为匿名函数 function move(e){ login.style.left = e.pageX-x+'px';//注意加单位 login.style.top = e.pageY-y+'px';//才会移动 } // (3)鼠标弹起时,移除mousemove事件 //①先绑定鼠标弹起事件 document.addEventListener('mouseup',function(){ //移除mousemove事件 document.removeEventListener('mousemove',move); }) }) </script>
【4】仿京东🔍效果
- 效果图:
- html+css思路:编写黄色区域+放大区域
①将黄色放大区域,绝对定位到商品的图片中
②右边的放大区域,也绝对定位到商品图片中,但添加左边距,移到对应位置
③给类添加cursor:move可让鼠标变成十字
④先将其display:none 使用js将其显示
- js思路:(js选择外嵌,要注意+window.onload事件)
(1)鼠标经过/离开小图片,出现/隐藏黄色区域+放大图片盒子
- mousemove鼠标经过,利用display=block显示盒子
- mouseout鼠标离开,利用display=none隐藏盒子
- 注意两个事件对象都是商品小图片
(2)黄色遮挡层跟随鼠标🖱移动
①获得鼠标在盒子中的位置
-
鼠标在页面的位置(e.pageX,Y)-盒子在页面的位置(div.offsetLeft,Top)
-
注意利用offset获得距页面的距离,要注意有没有定位,否则是父类的距离。
-
x = 鼠标在页面x-盒子在页面x
-
y = 鼠标在页面y-盒子在页面y
-
②得到黄色遮挡层坐标=鼠标在盒子中的位置
- maskX=x-黄色遮挡层宽度(mask.offsetWidth)一半
- maskY=y-黄色遮挡层高度(mask.offsetHeight)一半
- 便于鼠标居中
③判断黄色遮挡层位置:
-
限制商品小图片内移动
- 【限制范围:大盒子-黄色盒子的宽度,用offset得到】
-
在给黄色区域赋xy时,判断黄色区域x,y是否处于限制范围
1️⃣黄色区域x坐标小于0,其x=min(限制范围) ;黄色区域x坐标大于0,其x=max(限制范围)
2️⃣黄色区域y坐标小于0,其y=min(限制范围);黄色区域y坐标大于0,其y=max(限制范围)
(3)移动黄色遮挡层,大图片跟随移动
①遮挡层移动距离:
当前的maskX和maskY
maskX=鼠标X-盒子X-遮挡层Width一半
maskY=鼠标Y-盒子Y-遮挡层Height一半
②遮挡层最大移动距离:
小图片盒子宽度-遮挡层宽度
③大图片移动距离:
求解值????
④大图片最大移动距离:
大图片盒子宽度-遮挡层宽度
⑤得到大盒子中图片的位置
-
计算出大图片的x,y值赋给left和top值
-
带px单位
css代码实现:
<style> * { padding: 0; margin: 0; } .box { position: relative; width: 400px; height: 400px; margin: 50px 0 0 100px; border: 1px solid #000000; cursor: move; } .box img { width: 100%; height: 100%; } .mask { display: none; position: absolute; width: 300px; height: 300px; top: 0px; left: 0px; border: 1px solid #ccc; background: yellow; opacity: .5; } .big { display: none; position: absolute; width: 600px; height: 600px; top: -1px; left: 411px; border: 1px solid #000000; overflow: hidden; /* 图片超出盒子边框就隐藏,以此达到放大效果 */ } .big img { /* 因为是通过left和top值去让图片发生位置变化*/ /*所以要给图片盒子设置绝对定位 */ position: absolute; width: 800px; height: 800px; left: 0px; top: 0px; } </style>
html代码:
<div class="box"> <img src="https://img12.360buyimg.com/n1/s450x450_jfs/t1/59022/28/10293/141808/5d78088fEf6e7862d/68836f52ffaaad96.jpg" alt=""> <div class="mask"></div> <div class="big"> <img src="https://img12.360buyimg.com/n1/s450x450_jfs/t1/59022/28/10293/141808/5d78088fEf6e7862d/68836f52ffaaad96.jpg" alt="" class="bigImg"> </div> </div>
js代码实现:
<script> //1.获取元素:小图片+大图片+黄色盒子 var smallImg = document.querySelector('.box'); var big = document.querySelector('.big'); var bigImg = document.querySelector('.bigImg'); var mask = document.querySelector('.mask'); //2.鼠标经过小图片,显示黄色盒子+大图片 smallImg.addEventListener('mouseover',function(){ big.style.display = 'block'; mask.style.display = 'block'; }) //3.鼠标离开小图片,显示黄色盒子+大图片 smallImg.addEventListener('mouseout',function(){ big.style.display = 'none'; mask.style.display = 'none'; }) //4.黄色区域随着鼠标移动 smallImg.addEventListener('mousemove',function(e){ //(1)得到鼠标在盒子内x,y坐标 var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; //(2)得到黄色区域位置=鼠标在小图片盒子内的坐标 //tips:利用mask.offsetWidth调整居中 // 要加px单位才生效 //①黄色遮挡层坐标 var maskX = x - mask.offsetWidth / 2; var maskY = y - mask.offsetHeight / 2; //②黄色遮挡层最大可移动坐标 var maskMaxX = smallImg.offsetWidth-mask.offsetWidth; var maskMaxY = smallImg.offsetHeight-mask.offsetHeight; //③大图最大可移动坐标 var bigMaxX = big.offsetWidth - bigImg.offsetWidth; var bigMaxY = big.offsetHeight - bigImg.offsetHeight; //④大盒子图片的left值和top值 //计算公式:【黄色遮挡层移动距离/黄色遮挡层最大移动距离 = 大图移动距离/大图最大移动距离】 var bigImgX = bigImg.style.left = bigMaxX * maskX/maskMaxX ; var bigImgY = bigImg.style.top = bigMaxY * maskY/maskMaxY ; //5.设置黄色区域xy不能超过小图片区域 if(maskX <= 0){//限制X轴 maskX = 0; }else if(maskX >= maskMaxX){ maskX = smallImg.offsetWidth -mask.offsetWidth; } if(maskY <= 0){//限制y轴 maskY = 0; }else if(maskY >= maskMaxY){ maskY = smallImg.offsetHeight - mask.offsetHeight; } //最后确定黄色区域的位置 mask.style.left = maskX +'px';//别忘了单位!! mask.style.top = maskY +'px'; //6.设置大图片随着黄色遮挡层移动 bigImg.style.left = bigImgX + 'px'; bigImg.style.top = bigImgY + 'px'; }) </script>
2.client 元素可视区
client是客户端,使用client相关属性可以获取动态元素可视区的相关信息。如:该元素边框大小、元素大小等
【1】client常见属性:
(1)element.clientTop
返回元素上边框的大小
- elemnt.offsetTop是距绝对定位的父元素上边距
(2)element.clientLeft
返回元素左边框的大小
- element.offsetLeft是距绝对定位的父元素左边距
(3)element.clientWidth
返回元素padding+内容区宽度(不含边框)
(4)element.clientHeight
返回元素padding+内容区高度(不含边框)
【2】立即执行函数
立即执行函数是不需调用就可以使用的函数
(1)语法
①两个()()一个写函数,另一个表调用
(function 函数名(实参){ })(形参)
②函数调用放一起,最后+()
(function 函数名(){}());
③示例-第一种写法
(function(a,b){//接受形参 console.log(a); })(1,2)//传形参
(2)作用
- 立即执行函数好处在于:
创建了一个独立作用域,同时里面的变量都是局部变量,不会有命名冲突的情况
(3)注意:
每个立即执行函数后,要使用分号结尾表示结束
两个立即执行函数间,要使用分号隔开,否则会看成一个
3.scroll 元素滚动
scroll系列的相关属性可以动态得到该元素的大小,滚动距离等。
【1】scroll常见属性:
(1)element.scrollTop
返回被卷曲的上侧距离
(2)element.scrollLeft
返回被卷去的左侧距离
(3)element.scrollWidth
返回自身实际的宽度+padding,不含边框
- 实际的宽度:表示内容的宽度
- 如文字超出盒子大小,而element.scrollWidth显示的是文字宽度
(4)element.scrollHeight
返回自身实际的高度+padding,不含边框
- 实际的高度:表示盒子中的内容高度
- element.scrollWidth是文字实际大小+padding
- element.clientWidth则是盒子+padding的大小
【2】滚动效果
给css样式加上,overflow:auto可以让超出盒子的文字,形成下拉滚动条
【3】页面被卷去的头部
若浏览器搞(或宽)不足以显示整个页面时,会自动出现滚动条。而滚动条向下滚动时,页面上方被隐藏掉的高度,称为页面被卷去的头部。
- 滚动条在滚动时会触发onscroll事件。
(1)onscroll滚动事件
onscroll事件是当滚动条发生变化会触发的事件
- 示例:当滚动时提示滚动条的长度
<style> div{ overflow:auto; } </style> <div>内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容内容</div> <script> var div = document.querySelector('div'); console.log(div.scrollHeight); console.log(div.scrollWidth); div.addEventListener('scroll',function(){ console.log(div.scrollTop); }) </script>
(2)页面被卷去头部
页面被卷去,并非元素被卷去的element.scrollTop
主要注意,页面被卷去的头部,有兼容性问题,常见写法有:
1.声明了DTD,使用document.documentElement.scrollTop
2.未声明DTD,使用document.body.scrollTop
3.【ie9支持】window.pageYOffset和window.pageXOffset
- 实际开发一般不管兼容
DTD是文档声明:
<!DOCTYPE html>
- 解決兼容性問題:
【4】仿淘宝固定侧边栏
- 效果图:
- 效果分析:
1.原先侧边栏是绝对定位
2.当页面滚动到一定位置,侧边栏改为固定定位
3.页面继续滚动,会让[返回顶部]显示出来
- 思路分析
①需要使用页面滚动事件scroll,因是时间滚动,事件源为document
②通过判断页面被卷去的上部值===>页面滚到哪个位置
③**页面**被卷去的头部:window.pageYOffset获得
页面被卷去的左侧:window.pageXOffset
④而元素被卷去的头部:element.scrollTop
元素被卷去的左侧:element.scrollLeft
⑤获取元素->给滚动条绑定事件
1️⃣if判断滚动到banner区域,滚动条变flexed;否则,absoluted->解决跳跃问题
2️⃣判断滚动到main区域,滚动条显示[返回顶部];否则隐藏
css代码:
<style> a { text-decoration: none; color: #000; } .w { width: 1200px; margin: 10px auto; } .header { height: 150px; background-color: purple; } .banner { height: 250px; background-color: skyblue; } .main { height: 1000px; background-color: yellowgreen; } .slider-bar { position: absolute; left: 50%; top: 300px; margin-left: 600px; width: 45px; height: 130px; background-color: pink; } span { display: none; position: absolute; bottom: 0px; } </style>
html代码:
<div class="slider-bar"> <span class="goBack"> <a href="#toubu">返回顶部</a> </span> </div> <div class="header w" id="toubu">头部区域</div> <div class="banner w">banner区域</div> <div class="main w">主体部分</div>
js代码:
- 使用的document.pageXoffset具有兼容性问题
<script> //1.获取元素 var sliderBar = document.querySelector('.slider-bar'); var banner = document.querySelector('.banner'); var main = document.querySelector('.main'); var goback = document.querySelector('.goBack'); //滚动条到banner的距离 var bannerTop = banner.offsetTop; //滚动到banner后,侧边栏变为固定值,修改的top值 var sliderTop = sliderBar.offsetTop - bannerTop; //滚动条到main的距离 var mainTop = main.offsetTop; //2.给页面绑定滚动事件 document.addEventListener('scroll',function(){ //通过window.pageYOffset判断被卷去的长度 //(1)如果滚动条到banner区域后 //用banner.offsetTop在此距页面上方的高度,达到滚动banner滑动条失去绝对定位 if(window.pageYOffset >= bannerTop ){ //①解除绝对定位 sliderBar.style.position = 'fixed'; //②改变top值为侧边栏距页面顶部-banner距页面顶部 //【解决跳跃的问题】 sliderBar.style.top = sliderTop + 'px'; }else{ //②恢复绝对定位+原先top值 sliderBar.style.position = 'absolute'; sliderBar.style.top = '300px'; } //(2)滚动到main区域,让[回到顶部]的字样显示出来 if(window.pageYOffset >= mainTop){ goback.style.display = 'block';//显示字 }else{ goback.style.display = 'none';//让字消失 } }) </script>
4.三大系列总结
- element.offsetWidth包含边框+padding+内容
- element.clientWidth不含边框+padding+内容不超出
- element.scrollWidth不含边框+padding+内容可超出
【常用】:
①offset系列常用于获得元素位置 offsetTop、offsetLeft
②client系列常用语获取元素大小 clientWidth、clientHeight
③scroll系列常用语获得滚动距离 scrollTop、scrollLeft
- 页面滚动距离 window.pageYOffset获得
5.鼠标经过事件
(1)mouseover+mouseout
【差别:移入本身/及其子元素都会触发】
- 当移到元素及其子元素就触发
1️⃣mouseover鼠标经过
2️⃣mouseleave鼠标离开
<div class=“father”> <div class="son"></div> </div> <script> var father = document.querySelector('.father'); var son = document.querySlector('.son'); fahther.addEventListener('mousennter',function(){ console.log(11);//点击子元素也会输出11 }) </script>
(2)mouseenter+mouseleave
【差别:移入元素本身才会触发】
- 当移到元素本身时触发
1️⃣mouseenter鼠标经过
2️⃣mouseout鼠标离开
- 主要原因是mouseenter不会产生冒泡
<div class=“father”> <div class="son"></div> </div> <script> var father = document.querySelector('.father'); var son = document.querySlector('.son'); fahther.addEventListener('mousennter',function(){ console.log(11);//只有点击自身元素才输出11 }) </script>