放大镜
style:
*{
margin: 0;
padding: 0;
list-style: none;
}
#sbox{
width: 200px;
height: 200px;
background-size:200px 200px;
position: absolute;
top: 100px;
left: 100px;
cursor: move;
}
p{
width: 100px;
height: 100px;
background-color: cornflowerblue;
opacity: 0.3;
display: none;
position: absolute;
}
#bbox{
width: 400px;
height: 400px;
background-size: 800px 800px;
position: absolute;
left: 310px;
top: 100px;
display: none;
}
ul{
width: 200px;
height: 40px;
display: flex;
position: absolute;
top: 302px;
left: 100px;
}
li{
width: 20%;
}
img{
width: 100%;
height: 100%;
}
html:
<div id="sbox">
<p></p>
</div>
<div id="bbox"></div>
<ul>
<li><img src="img/0.jpg" alt=""></li>
<li><img src="img/1.jpg" alt=""></li>
<li><img src="img/2.jpg" alt=""></li>
<li><img src="img/3.jpg" alt=""></li>
<li><img src="img/4.jpg" alt=""></li>
</ul>
script:
let hSb = document.querySelector("#sbox");-----------固定的照片框
let hBb = document.querySelector("#bbox");-----------放大镜展示效果的盒子
let hP = document.querySelector("p");-----------遮罩
let hLi = document.getElementsByTagName("li");-------------底部其他照片
class Mag{
constructor(hSb,hBb,hP,hLi){-------------------传参
this.hSb = hSb;
this.hBb = hBb;
this.hP = hP;
this.hLi = hLi;
this.dog = 0;--------------此处定义dog属性,目的是为了后续通过li下标的赋值改变大小盒子的背景图
this.hSb.style.backgroundImage = `url(img/${this.dog}.jpg)`;----------小盒子背景图赋初值,用dog属性拼接,方便后续改值换图片
this.hBb.style.backgroundImage = `url(img/${this.dog}.jpg)`;----------大盒子背景图赋初值
this.eventBind();-------------整合事件调用
}
mouseover(){--------------鼠标划入事件
let that = this;--------------下面需要写划入事件绑定,因此这里存一个this在变量that
this.hSb.onmouseover = function(){-------------为小盒子绑定划入事件,达到划入显示遮罩与大盒子的效果
that.hP.style.display = "block";
that.hBb.style.display = "block";
}
}
mouseout(){--------------鼠标划出事件
let that = this;--------------下面需要写划出事件绑定,因此这里存一个this在变量that
this.hSb.onmouseout = function(){------------为小盒子绑定划出事件,达到划入隐藏遮罩与大盒子的效果
that.hP.style.display = "none";
that.hBb.style.display = "none";
}
}
changes(){-----------------此处根据划入li的下标值改变大小盒子的背景图
let that = this;
for(let i = 0;i<this.hLi.length;i++){
this.hLi[i].onmouseover = function(){-------------为li循环添加鼠标划入事件
that.dog = i;-----------将划入的li的下标赋值给dog属性,以改变背景图
that.hSb.style.backgroundImage = `url(img/${that.dog}.jpg)`;
that.hBb.style.backgroundImage = `url(img/${that.dog}.jpg)`;
}
}
}
mousemove(){-----------------鼠标滑动事件
let that = this;----------------------绑定事件前面固定存一个this
this.hSb.onmousemove = function(cat){-----------------这里需要用到鼠标事件的坐标点,故创建鼠标事件对象cat,方便获取坐标点赋值给遮罩
因为在html中,遮罩与他的父元素小盒子都添加了绝对定位属性absolute,而绝对定位是相对于离元素最近的有定位属性的父元素,所以此处遮罩的定位是相对于小盒子的左顶点,当需要把鼠标事件坐标(鼠标离页面左顶点的距离)赋值给遮罩时,需要减去小盒子离页面左顶点的横竖距离,也就是offsetLeft和offsetTop,减去之后遮罩离小盒子左顶点的距离就和鼠标距离小盒子左顶点相同了,也即二者可以处在同一个位置,同步移动,此时鼠标还位于遮罩的左上角,我们需要再减去遮罩宽高各一半,使得鼠标位置位于遮罩正中间,达到理想效果。所以综上,我们需要的遮罩离盒子左边和上面的距离left和top,需要用鼠标页面坐标各自减去小盒子的offsetLeft和offsetTop,再减去遮罩自身宽高各一半,公式如下:
let left = cat.pageX-this.offsetLeft-that.hP.offsetWidth/2;
let top = cat.pageY-this.offsetTop-that.hP.offsetHeight/2
为防止遮罩越界影响放大镜效果,我们需要增加一些限制条件,当遮罩相对于小盒子正方向的位置小于0,就为他强行赋值为0,不允许遮罩移动超出小盒子左边缘和上边缘
if(left<0){
left = 0;
}
if(top<0){
top = 0;
}
这里用来限制遮罩移动超出小盒子的右边缘和下边缘,也就是遮罩相对于小盒子的上边缘的距离不能超过小盒子的高减去遮罩高,遮罩相对于小盒子右边缘的距离不能超过小盒子的宽减去遮罩宽
let maxLeft = this.offsetWidth - that.hP.offsetWidth;
let maxTop = this.offsetHeight - that.hP.offsetHeight;
当遮罩移出距离超过最大值时,就给他强行赋值最大值,将他限制在这个范围内
if(left>maxLeft){
left = maxLeft;
}
if(top>maxTop){
top = maxTop;
}
赋值给遮罩的坐标距离写在距离限制和计算的最后面,经过一系列限制条件和计算条件,最终赋值给遮罩;
that.hP.style.left = left +"px";
that.hP.style.top = top +"px";
此处用遮罩宽和大盒子(放大镜)的款计算出二者宽高比
let xi = that.hBb.offsetWidth/that.hP.offsetWidth;
用计算出的宽高比乘以遮罩相对于小盒子的坐标,也就是大盒子的背景图相对于大盒子的坐标,但是大盒子移动的对象是背景图,所以方向与遮罩相反,坐标值加上负号
that.hBb.style.backgroundPositionX = -left*xi+"px";
that.hBb.style.backgroundPositionY = -top*xi+"px";
}
}
事件绑定整合,方便统一调用
eventBind(){
this.mouseover();
this.mouseout();
this.changes();
this.mousemove();
}
}
let a = new Mag(hSb,hBb,hP,hLi);
瀑布流
1.要点:
瀑布流的前提,必须定宽或者定高
以定宽为例
提前在样式中设置,div的宽和绝对定位
2.代码
style:
*{
margin: 0;
padding: 0;
}
div{
width: 200px;
position: absolute;
border-radius: 10px;
}
html:
script:
class WaterFall{
createDiv(){-------------循环生成新的div并确定高度,背景图,序号
for(let i=0; i<14; i++){
let oDiv = document.createElement("div");-----------创建div
document.body.appendChild(oDiv);-----------------追加给body
let rnd = Math.round(Math.random()*200)+100;----------------随机生成高度
oDiv.style.height = rnd + "px";
oDiv.style.backgroundImage = `url(img/${i}.jpg)`;---------------循环生成背景图
oDiv.style.backgroundSize = `200px ${rnd}px`;------------利用前面生成的高度和给定的宽度确定背景图的尺寸
oDiv.innerHTML = i;-------------加上序列数字
}
this.setPosition();----------------调用排序函数
}
setPosition(){-----------------排列div的位置
let n = Math.floor(innerWidth/210);---------------计算页面能排几个元素(列数)
let oDivs = document.getElementsByTagName("div");---------------------把页面的所有div获取了
let arr = [];------------------核心:存储每一列高度的数组
for(let i=0; i<oDivs.length; i++){
if(arr.length < n){----------------第一行的排列
oDivs[i].style.top = 0;
oDivs[i].style.left = i*210 + "px";
arr.push(oDivs[i].offsetHeight);-------------将第一行每个div的高度存放在arr中,为了在除了第一行排列时,找出最矮的那一列
}else{
let index = this.findMin(arr);-------------找出数组当前最低高度元素的下标
oDivs[i].style.left = index*210 + "px";------------根据最低高度的元素下标,确定横向定位
oDivs[i].style.top = arr[index] + 10 + "px";----------------根据最低高度的元素高度,确定纵向定位
arr[index] += oDivs[i].offsetHeight + 10;---------------更新数组元素高度
}
}
}
findMin(arr){-----------------确定数组最低高度的元素
let min = 0;
arr.forEach((x,index,a) => {
if(a[min] > x){
min = index;
}
});
// for(let i=0; i<arr.length; i++){
// if(arr[min] > arr[i]){
// min = i;
// }
// }
return min;
}
scroll(){
let that = this;
window.onscroll = function(){-----------------------设定滚动条事件,当滚动条高度大于400时,随事件产生新的div并排序
let _top = document.body.scrollTop || document.documentElement.scrollTop;---------兼容性获取滚动条高度
if(_top > 400){当滚动条高度大于400时,随事件产生新的div并排序
that.createDiv();
}
}
}
}
let wf = new WaterFall();
wf.createDiv();
wf.createDiv();
wf.createDiv();
wf.scroll();
懒加载
1.懒加载的要点
一.什么是懒加载?
懒加载就是优先加载可视区域的内容,其他部分等进入了可视区域在加载
二.为什么要懒加载?
懒加载是一种网页性能优化的方式,它能极大的提升用户体验。
总结:
1.全部加载的话会影响用户体验
2.浪费用户的流量,有些用户并不想全部看完,全部加载会耗费大量流量。
三.懒加载的实现原理?
从<img>标签下手,判断可视区域,当图片进入可视区域,给img加上src属性
2.相关API:
1)document.documentElement.clientHeight-----------------------获取屏幕可视区域的高度
(这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,否则,它是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距。)
2)element.offsetTop---------------------------------获取元素相对于文档顶部的高度
(HTMLELement.offsetTop为只读属性,它返回当前元素相对于其offsetParent元素的顶部的距离。)
3)document.documentElement.scrollTop---------获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
(Element.scrollTop属性可以获取或设置一个元素的内容垂直滚动的像素数,一个元素的scrollTop值是这个元素的顶部到视口可见内容(的顶部)的距离的度量。当一个元素的内容没有产生垂直方向的滚动条,那么它的scrollTop值为0)
3.示意图
3.实现代码:
判断公式:如果offsetTop-scrollTop<clientHeight,则图片进入了可视区内,则被请求。
style:
*{
margin: 0;
padding: 0;
}
div{
width: 504px;
position: absolute;
overflow: hidden;
}
body div:nth-child(1){
height: 403px;
}
body div:nth-child(2){
height: 423px;
}
body div:nth-child(3){
height: 443px;
}
body div:nth-child(4){
height: 413px;
}
body div:nth-child(5){
height:473px;
}
body div:nth-child(6){
height: 403px;
}
body div:nth-child(7){
height: 423px;
}
body div:nth-child(8){
height: 493px;
}
body div:nth-child(9){
height: 463px;
}
body div:nth-child(10){
height: 403px;
}
body div:nth-child(11){
height: 433px;
}
body div:nth-child(12){
height: 453px;
}
body div:nth-child(13){
height: 433px;
}
body div:nth-child(14){
height: 483px;
}
body div:nth-child(15){
height: 463px;
}
body div:nth-child(16){
height: 423px;
}
body div:nth-child(17){
height: 493px;
}
body div:nth-child(18){
height: 413px;
}
body div:nth-child(19){
height: 483px;
}
body div:nth-child(20){
height: 423px;
}
img{
width: 100%;
}
html:
<div><img cat="img/0.jpg" alt=""></div>
<div><img cat="img/1.jpg" alt=""></div>
<div><img cat="img/2.jpg" alt=""></div>
<div><img cat="img/3.jpg" alt=""></div>
<div><img cat="img/4.jpg" alt=""></div>
<div><img cat="img/5.jpg" alt=""></div>
<div><img cat="img/6.jpg" alt=""></div>
<div><img cat="img/0.jpg" alt=""></div>
<div><img cat="img/1.jpg" alt=""></div>
<div><img cat="img/2.jpg" alt=""></div>
<div><img cat="img/3.jpg" alt=""></div>
<div><img cat="img/4.jpg" alt=""></div>
<div><img cat="img/5.jpg" alt=""></div>
<div><img cat="img/6.jpg" alt=""></div>
<div><img cat="img/0.jpg" alt=""></div>
<div><img cat="img/1.jpg" alt=""></div>
<div><img cat="img/2.jpg" alt=""></div>
<div><img cat="img/3.jpg" alt=""></div>
<div><img cat="img/4.jpg" alt=""></div>
<div><img cat="img/5.jpg" alt=""></div>
script:
function waterFall(){---------------生成瀑布流函数
let hBs = document.getElementsByTagName("div");------------获取页面元素
let gap = 10;----------------------确定列间距
let cat = 0;
let pageWidth = innerWidth;-------------可视窗口宽度
let column = Math.round(pageWidth/(hBs[0].offsetWidth+gap));------------确定列数
let dog = [];--------------存储第一行元素高度的数组
let minHeight = 0;------------数组内最低高度
for(let i = 0;i<hBs.length;i++){
if(i<column){-------------第一行元素排列方式
hBs[i].style.top = 0;-----------------第一行元素高度为0
hBs[i].style.left = i*(hBs[0].offsetWidth+gap)+"px";--------------元素左间距
dog.push(hBs[i].offsetHeight);--------将第一行元素的高按顺序插入数组
}else{--------------除了第一行之外的元素排列方式
cat = 0;
minHeight = dog[0];
for(let j = 0;j<dog.length;j++){--------------循环结构找到数组元素高度最低的元素,获取其下标
if(minHeight>dog[j]){
minHeight=dog[j];
cat = j;
}
}
hBs[i].style.top = minHeight+gap+"px";-------------新元素的top值为数组最低元素高度加上列/行间距gap;
hBs[i].style.left = hBs[cat].offsetLeft+"px";------新元素的左间距为对应最低元素的左间距;
dog[cat] = dog[cat]+hBs[i].offsetHeight+gap;----------新元素排列好后更新数组元素高度
}
}
}
waterFall();--------------调用瀑布流函数
function tops(e){
let t = e.offsetTop;----------------循环获取元素真实高度,为懒加载确定元素与可视窗口距离做准备
while(e = e.offsetParent){
t += e.offsetTop;
return t;
}
}
function Pic(){-----------懒加载函数
let hImgs = document.getElementsByTagName("img");------------获取页面图片img标签
let pageTop = innerHeight;--------------获取可视窗口高度
let sTop = document.documentElement.scrollTop||document.body.scrollTop;---------兼容性获取滚动条高度
for(let i =0;i<hImgs.length;i++){
if(pageTop+sTop>tops(hImgs[i])){----------------当滚动条高度加上可视窗口高度小于图片距离页面顶部高度的时候,为图片加上scr属性
setTimeout(function(){
hImgs[i].src = hImgs[i].getAttribute("cat");
},1000)
}
}
}
window.onscroll = function(){
Pic();---------将懒加载函数与滚动条事件绑定
}