20230327----重返学习-轮播图-function的ES6变量提升问题
Posted 方朝端
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20230327----重返学习-轮播图-function的ES6变量提升问题相关的知识,希望对你有一定的参考价值。
day-036-thirty-six-20230327-轮播图-function的ES6变量提升问题
轮播图
-
设置好布局
<div class="container" id="bannerBox"> <div class="wrapper"> <div class="slide"><img src="./images/banner01.png" alt="" /></div> <div class="slide"><img src="./images/banner02.jpg" alt="" /></div> <div class="slide"><img src="./images/banner03.png" alt="" /></div> <div class="slide"><img src="./images/banner01.png" alt="" /></div> </div> <div class="pagination"> <span class="active" index="0"></span> <span index="1"></span> <span index="2"></span> </div> <div class="navigation prev"></div> <div class="navigation next"></div> </div>
- 轮播图所有图片由图片盒子.wrapper包起来,用flex布局让图片.slide排成一行,图片宽高与轮播图盒子大小一致。
- 图片盒子.wrapper设置绝对定位,通过left属性值的改变前后移动它的位置,同时来让其显示特定一部分在轮播图盒子.container中。
.container --container-width: 1000px; --container-height: 400px; width: var(--container-width); height: var(--container-height); margin: 50px auto; position: relative; overflow: hidden; /* 显示出具体的过程,加边框会造成数据left的计算出错,故而加box-sizing。 & box-sizing: border-box; border: 1px solid red; .wrapper, .wrapper > .slide box-sizing: border-box; width:400%; .wrapper border: 1px solid skyblue; .wrapper > .slide border: 1px solid yellow; */ .wrapper display: flex; height: var(--container-height); position: absolute; left: 0; top: 0; transition: left 0.3s; .slide, .slide > img width: var(--container-width); height: var(--container-height); float: left; .pagination padding: 5px 5px; background-color: rgba(255, 255, 255, 0.5); border-radius: 15px; position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); span display: inline-block; padding: 5px; margin: 0px 8px; border-radius: 50%; background-color: #000000; &.active background-color: chocolate; .navigation height: 79px; width: 39px; background-color: rgba(245, 245, 245, 0.7); background: url(../images/btn.png) no-repeat; position: absolute; top: 50%; transform: translateY(-50%); &.prev left: 0; &.next background-position: -39px 0px; right: 0;
-
设置各个数据
- 图片宽度width为容器宽度
- count为轮播单位总数,也顺带等于总图片个数
- 有重复图片的总数,也是无重复图片的总数加1。因为第一幅与最后一幅是一样的
- 最后一幅与第一幅一样:是为了当无重复图片到最后一幅,也就是有重复图片的倒数第一幅时,视觉上可以有动画地过渡到第一幅。
- 也就是说,下一次的动画就是要第一幅到第二幅
- 最后一幅与第一幅一样:是为了当无重复图片到最后一幅,也就是有重复图片的倒数第一幅时,视觉上可以有动画地过渡到第一幅。
- 有重复图片的总数,也是无重复图片的总数加1。因为第一幅与最后一幅是一样的
- 设置步长step开始为0
- step为0到
count-1
时 0->1->2->count-1
(有动画) count-1
->0 (无动画count-1
-> 0),并且有动画- 浏览器如果只是设置属性,会统一执行完设置,统一更新渲染队列。
- 浏览器如果是获取属性,会立刻更新渲染队列。
- step为0到
-
设置各个事件
- 定时滚动事件
- 浏览器如果只是设置属性,会统一执行完设置,统一更新渲染队列。
- 容器移入移出事件
- 移入盒子 停止定时器
- 移出盒子 重新开启定时器
- 可用事件
- onmouseenter(移入) onmouseleave(移出) ---- 没有冒泡
- onmouseover(移入) onmouseout(移出) — 有冒泡
- 点击事件委托到容器上
- 点击下一个
- 点击上一个
- 点击小圆点
- 小圆点激活
- 定时滚动事件
-
渲染页面
const theLun = (function ()
let container = document.querySelector(".container"); //整个轮播图容器
let wrapper = container.querySelector(".wrapper"); //要移送的盒子
let width = container.offsetWidth; //整个容器的宽度,也是图片的宽度
let step = 0; //步长
let count = 0; //总图片个数,为ajax获取到的图片总数加1。
let timer = null; //定时器
let data = null;
//获取数据(ajax 4步)+循环渲染
const render = function render()
let xhr = new XMLHttpRequest();
xhr.open("GET", "data.json", false);
xhr.onreadystatechange = function ()
if (xhr.readyState === 4 && xhr.status === 200)
// console.log(xhr);
data = JSON.parse(xhr.response);
;
xhr.send();
console.log(data);
let wrapperString = ``;
let pagination = container.querySelector(".pagination");
let paginationString = ``;
data.forEach((item, index) =>
wrapperString += `<div class="slide">
<img src="$item.pic" alt="" />
</div>`;
// paginationString += `<span class="$ index === step ? "active" : "" " index="$index"></span>`;
paginationString += `<span index="$index"></span>`;
);
//除了拼接5张图片外,还要重复第一幅图片
wrapperString += `<div class="slide">
<img src="$data[0].pic" alt="" />
</div>`;
wrapper.innerhtml = wrapperString;
pagination.innerHTML = paginationString; //如果小圆点是作为全局变量的,那么要这里重新查找一下。
count = data.length + 1; //总图片个数,为ajax获取到的图片总数加1。
;
render();
const autoPlay = function autoPlay()
step++;
if (step > count - 1)
//1.如果是最后一幅重复的,无动画,回到第一幅。不回的话,下一个就是空白了。
step = 0; //将进入第一幅
wrapper.style.transitionDuration = "0s"; //无动画
wrapper.style.left = `-$step * widthpx`; //回到第一幅
// 浏览器如果只是设置属性,会统一执行完设置,统一更新渲染队列
// 浏览器如果是获取属性,会立刻更新渲染队列
wrapper.offsetWidth;
// 2. 由第一幅图片,使用动画进入第二幅
step = 1; //将进入第二幅
wrapper.style.transitionDuration = "0.3s"; //有动画
wrapper.style.left = `-$step * widthpx`; //-0*1000 0 //-1*1000 -1000
showCricle();//更新小圆点的各个状态。
;
timer = setInterval(autoPlay, 1000);//每隔1000ms要通过图片盒子的left移动盒子
//onmouseenter(移入) onmouseleave(移出) ---- 没有冒泡
// onmouseover(移入) onmouseout(移出) --- 有冒泡
//移入盒子 停止定时器
container.onmouseenter = function ()
clearInterval(timer);
timer = null;
;
//移出盒子 重新开启定时器
container.onmouseleave = function ()
timer = setInterval(autoPlay, 1000);
;
// 修改小圆点的激活状态
const showCricle = function showCricle()
//不能直接修改step,因为全局都在使用step。
// 声明一个变量temp,复制一版step,改temp
let temp = step;
if (temp === count - 1)
temp = 0;
let spanList = Array.from(container.querySelectorAll(".pagination>span"));
spanList.forEach((item, index) =>
//如果index等于step, 0--0 1--1 2--2
//给span添加className="active"
if (index === temp)
item.className = "active";
else
item.className = "";
);
;
// 绑定事件----事件委托 将事件绑定给祖先级元素,减少事件的绑定,提高性能
container.onclick = function (e)
// console.log(e.target);//目标元素
// console.log(e.target.tagName);//目标元素的大写标签名
// console.log(e.target.className);//目标元素的类名字符串
if (e.target.tagName === "SPAN") //小圆点
let index = Number(e.target.getAttribute("index"));//找到小圆点的索引
// console.log("点击小圆点", index);
// 如果index与step值一样,就不做操作
// 如果step为3,index为0,就不做操作
if (index === step || (step === count - 1 && index === 0))
return;
step = index;//修改步长 步长等于index
wrapper.style.left = `-$width * steppx`;//根据步长设置位置
showCricle();//展示小圆点
if (e.target.className.includes("prev")) //上一个
console.log("点击上一个");
step--;
if (step < 0)
//1. 由第一幅无动画地立刻回到最后一幅
step = count - 1;//将要前往最后一幅
wrapper.style.transitionDuration = `0s`;//无动画
wrapper.style.left = `-$width * steppx`;//前往最后一幅
wrapper.offsetWidth;//获取属性,刷新一次队列
// 2.由倒数第一副-->倒数第二幅(有动画)
step = count - 2;//将要前往倒数第二幅
wrapper.style.transitionDuration = `0.3s`;//有动画
wrapper.style.left = `-$width * steppx`;//-3*1000 //-2*1000
showCricle();
if (e.target.className.includes("next")) //下一个
console.log("点击下一个");
autoPlay();
;
)();
试题回顾
- function的ES6变量提升问题
- function声明的函数,声明提升到当前私有作用域,赋值提到了当前块作用域;以这行代码为分界线,上面为全局作用域,下方为块级作用域
console.log(foo)//undefined
console.log(foo)//ƒ foo() return 2
function foo() return 1
console.log(foo)//ƒ foo() return 2
foo = 1;
function foo() return 2
console.log(foo)//1
foo = 3;
console.log(foo)//3
console.log(foo);//1
//EC(G) foo--undefined--0x001--0x002---1
console.log(foo)
//EC(G) foo--0x001--0x002---1
console.log(foo)//ƒ foo() return 2
function foo() return 1//0x001
console.log(foo)//ƒ foo() return 2
foo = 1;//这里依旧是全局作用域
function foo() return 2//0x002 //这行代码的声明提升到当前私有作用域,赋值提到了当前块作用域;以这行代码为分界线,上面为全局作用域,下方为块级作用域
//EC(anonymous) foo--0x002---1---3
console.log(foo)//1
foo = 3;
console.log(foo)//3
console.log(foo);//1
相当于
//EC(G) foo--undefined--0x001--0x002---1
var foo
console.log(foo)
//EC(G) foo--0x001--0x002---1
foo=function foo() return 1//0x001
foo=function foo() return 2//0x002
console.log(foo)//ƒ foo() return 2
console.log(foo)//ƒ foo() return 2
foo = 1;//这里依旧是全局作用域
//-----------------
//EC(anonymous) foo--0x002---1---3
let foo=1//赋值为上次的值
console.log(foo)//1
foo = 3;
console.log(foo)//3
console.log(foo);//1
进阶参考
以上是关于20230327----重返学习-轮播图-function的ES6变量提升问题的主要内容,如果未能解决你的问题,请参考以下文章