20230327----重返学习-轮播图-function的ES6变量提升问题

Posted 方朝端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20230327----重返学习-轮播图-function的ES6变量提升问题相关的知识,希望对你有一定的参考价值。

day-036-thirty-six-20230327-轮播图-function的ES6变量提升问题

轮播图

  1. 设置好布局

    <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;
        
      
    
    
  2. 设置各个数据

    • 图片宽度width为容器宽度
    • count为轮播单位总数,也顺带等于总图片个数
      • 有重复图片的总数,也是无重复图片的总数加1。因为第一幅与最后一幅是一样的
        • 最后一幅与第一幅一样:是为了当无重复图片到最后一幅,也就是有重复图片的倒数第一幅时,视觉上可以有动画地过渡到第一幅。
          • 也就是说,下一次的动画就是要第一幅到第二幅
    • 设置步长step开始为0
      • step为0到count-1时 0->1->2->count-1(有动画)
      • count-1->0 (无动画count-1-> 0),并且有动画
        • 浏览器如果只是设置属性,会统一执行完设置,统一更新渲染队列。
        • 浏览器如果是获取属性,会立刻更新渲染队列。
  3. 设置各个事件

    1. 定时滚动事件
      • 浏览器如果只是设置属性,会统一执行完设置,统一更新渲染队列。
    2. 容器移入移出事件
      • 移入盒子 停止定时器
      • 移出盒子 重新开启定时器
      • 可用事件
        • onmouseenter(移入) onmouseleave(移出) ---- 没有冒泡
        • onmouseover(移入) onmouseout(移出) — 有冒泡
    3. 点击事件委托到容器上
      1. 点击下一个
      2. 点击上一个
      3. 点击小圆点
    4. 小圆点激活
  4. 渲染页面

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变量提升问题的主要内容,如果未能解决你的问题,请参考以下文章

轮播图学习2:实现轮播图自动跳转

js轮播图(学习笔记)

JavaScript实现的轮播图

ionic3-ng4学习见闻--(轮播图完美方案)

JavaScript学习——实现首页轮播图效果

用jQuery实现优酷首页轮播图