二:第二阶段 JS(4)

一: BOM浏览器对象模型

1.1: 目标

能够说出什么是BOM

能够知道浏览器的顶级对象window

能够写出页面加载事件以及注意事项

能够写出两种定时器函数并说出区别

能够说出JS执行机制

能够使用location 对象完成页面之间的跳转

能够知晓navigator对象涉及的属性

能够使用history提供的方法实现页面刷新

1.2: 目录

BOM概述

window对象的常见事件

定时器

JS执行机制

location对象

navigator对象

history对象

1.3:BOM概述

1:什么是BOM?

比如:一个页面如果后退或者前进一个页面,怎么刷新一个页面,浏览器页面的窗口发生变化,或者浏览器页面的滚动条滚动。需要用到BOM

BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window。

BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。

BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape浏览器标准的一部分。

DOM

  • 文档对象模型
  • DOM 就是把「文档」当做一个「对象」来看待
  • DOM 的顶级对象是document
  • DOM 主要学习的是操作页面元素
  • DOM 是W3C 标准规范

BOM

  • 浏览器对象模型
  • 把「浏览器」当做一个「对象」来看待
  • BOM 的顶级对象是window
  • BOM 学习的是浏览器窗口交互的一些对象
  • BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差

2;BOM的构成

BOM 比DOM 更大,它包含DOM。

window对象是浏览器的顶级对象,它具有双重角色。

    1.它是JS 访问浏览器窗口的一个接口。

    2.它是一个全局对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法。在调用的时候可以省略window,前面学习的对话框都属于window 对象方法,如alert()、prompt()等。

注意:window下的一个特殊属性window.name

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
 
<body>
    <script>
        // window.document.querySelector()
        var num = 10;
        console.log(num);
        console.log(window.num);
 
        function fn() {
            console.log(11);
 
        }
        fn();
        window.fn();
        // alert(11);
        // window.alert(11)
        console.dir(window);
        // var name = 10;
        console.log(window.name);
    </script>
</body>
 
</html>

1.4: window对象的常见事件

1: 窗口加载事件

window.onload = function(){ }

或者

window.addEventListener("load",function( ){ } );

window.onload 是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等), 就调用的处理函数。

注意:

1. 有了window.onload 就可以把JS 代码写到页面元素的上方,因为onload 是等页面内容全部加载完毕,再去执行处理函数。

2. window.onload 传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload 为准。

3. 如果使用addEventListener则没有限制

document.addEventListener('DOMContentLoaded',function(){})

DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。Ie9以上才支持。

如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded 事件比较合适。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //1:onload是全部加载完毕后,window的函数里面的方法才执行
        //window函数
        window.onload = function () {
            //1.1:选择元素
            var btn = document.querySelector('button');
            //1.2: 注册事件
            btn.addEventListener('click', function () {
                // alert('点击');
            });
        }
        window.onload = function () {
            // alert(22);
        }

        window.addEventListener('load', function () {
            var btn = document.querySelector('button');
            btn.addEventListener('click', function () {
                // alert('hahah');
            })
        })

        //2: DOMContentLoaded
        document.addEventListener('DOMContentLoaded', function () {
            alert(33);
        })
        // load 等页面内容全部加载完毕,包含页面dom元素 图片 flash  css 等等
        // DOMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些
        // var btn = document.querySelector('button');
    </script>
    <button>按钮</button>
</body>

</html>

2: 调整窗口大小事件

window.onresize = function(){ }

window.addEventListener("resize",function( ) { });

window.onresize是调整窗口大小加载事件, 当触发时就调用的处理函数。

注意:

1. 只要窗口大小发生像素变化,就会触发这个事件。

2. 我们经常利用这个事件完成响应式布局。window.innerWidth 当前屏幕的宽度

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <script>
        window.addEventListener('load', function () {
            var div = document.querySelector('div');
            window.addEventListener('resize', function () {
                console.log(window.innerWidth);

                console.log('变化了');
                if (window.innerWidth <= 800) {
                    div.style.display = 'none';
                } else {
                    div.style.display = 'block';
                }

            })
        })
    </script>
    <div></div>
</body>

</html>

1.5: 定时器

1: 两种定时器

window 对象给我们提供了2 个非常好用的方法-定时器

  • setTimeout()
  • setInterval()

2: setTimeout() 定时器

window.setTimeout(调用函数,[延迟的毫秒数]);

       延时时间是延迟多少毫秒后就开始执行调用函数。

setTimeout()方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。

注意:

1. window 可以省略。

2. 这个调用函数可以直接写函数,或者写函数名或者采取字符串‘函数名()'三种形式。第三种       不推荐

3. 延迟的毫秒数省略默认是0,如果写,必须是毫秒。

4. 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 1. setTimeout 
        // 语法规范:  window.setTimeout(调用函数, 延时时间);
        // 1. 这个window在调用的时候可以省略
        // 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
        // 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
        // 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
        setTimeout(function () {
            console.log('时间到了');

        }, 2000)

        //方法二:直接调用
        function callback() {
            console.log('爆炸了');
        }

        var timer1 = setTimeout(callback, 3000);
        var timer2 = setTimeout(callback, 5000);

        setTimeout('callback()', 6000); //我们不提倡这个写法
    </script>
</body>

</html>

2:setTimeout() 定时器

window.setTimeout(调用函数,[延迟的毫秒数]);

  • setTimeout() 这个调用函数我们也称为回调函数 callback
  • 普通函数是按照代码顺序直接调用。
  • 而这个函数,需要等待时间,时间到了才去调用这个函数,因此称为回调函数。
  • 简单理解:回调,就是回头调用的意思。上一件事干完,再回头再调用这个函数。
  • 以前我们讲的element.onclick = function(){}或者element.addEventListener(“click”, fn);里面的函数也是回调函数。
2.1: 案例-5秒后自动关闭的广告

案例分析:

①核心思路:5秒之后,就把这个广告隐藏起来

②用定时器setTimeout

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <img src="images/ad.jpg" alt="">
    <script>
        var img = document.querySelector('img');
        setTimeout(function () {
            img.style.display = 'none';
        }, 5000)
    </script>
</body>

</html>

3: 停止setTimeout() 定时器

window.clearTimeout(timeoutID)

clearTimeout()方法取消了先前通过调用setTimeout()建立的定时器。

注意

1. window 可以省略。

2. 里面的参数就是定时器的标识符

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击停止定时器</button>
    <script>
        var btn = document.querySelector('button');
        //设置定时器时间
        var timer = setTimeout(function () {
            console.log('爆炸了');
        }, 5000);

        //清除定时时间设置的爆炸
        btn.addEventListener('click', function () {
            clearTimeout(timer);
        })
    </script>
</body>

</html>

4:  setInterval() 定时器

window.setInterval(回调函数,[间隔的毫秒数]);

setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。

注意:

1. window 可以省略。

2. 这个调用函数可以直接写函数,或者写函数名或者采取字符串'函数名()' 三种形式。

3. 间隔的毫秒数省略默认是0,如果写,必须是毫秒,表示每隔多少毫秒就自动调用这个函数。

4.因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

5. 第一次执行也是间隔毫秒数之后执行,之后每隔毫秒数就执行一次。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //1; setInterval
        //  语法规范  window.setInterval(调用函数,延时时间);
        setInterval(function () {
            console.log('继续输出');
        }, 1000);

        //2: setTimeout 延时时间到了 ,就去调用这个会调函数,只调用一次 就结束了这个定时器
        //3: setInterval 每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
    </script>
</body>

</html>

5: 案例-倒计时

案例分析

①这个倒计时是不断变化的,因此需要定时器来自动变化(setInterval)

②三个黑色盒子里面分别存放时分秒

③三个黑色盒子利用innerHTML 放入计算的小时分钟秒数

④第一次执行也是间隔毫秒数,因此刚刷新页面会有空白

⑤最好采取封装函数的方式,这样可以先调用一次这个函数,防止刚开始刷新页面有空白问题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            margin: 200px;
        }

        span {
            display: inline-block;
            width: 40px;
            height: 40px;
            background-color: #333;
            font-size: 20px;
            color: #fff;
            text-align: center;
            line-height: 40px;
        }
    </style>
</head>

<body>
    <div>
        <span class="hour">1</span>
        <span class="minute">2</span>
        <span class="second">3</span>
    </div>
    <script>
        // 1. 获取元素 
        var hour = document.querySelector('.hour'); // 小时的黑色盒子
        var minute = document.querySelector('.minute'); // 分钟的黑色盒子
        var second = document.querySelector('.second'); // 秒数的黑色盒子
        var inputTime = +new Date('2019-5-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
        countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白 
        // 2. 开启定时器
        setInterval(countDown, 1000);

        function countDown() {
            var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
            var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数 
            var h = parseInt(times / 60 / 60 % 24); //时
            h = h < 10 ? '0' + h : h;
            hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
            var m = parseInt(times / 60 % 60); // 分
            m = m < 10 ? '0' + m : m;
            minute.innerHTML = m;
            var s = parseInt(times % 60); // 当前的秒
            s = s < 10 ? '0' + s : s;
            second.innerHTML = s;
        }
    </script>
</body>

</html>

6:  停止setInterval()定时器

window.clearInterval(intervalID);

clearInterval()方法取消了先前通过调用setInterval()建立的定时器。

注意:

1. window 可以省略。

2. 里面的参数就是定时器的标识符。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button class="begin">开始</button>
    <button class="stop">结束</button>

    <script>
        var begin = document.querySelector('.begin');
        var end = document.querySelector('.stop');
        var timer = null;
        begin.addEventListener('click', function () {
            timer = setInterval(function () {
                console.log('开始');
            }, 1000);
        })

        end.addEventListener('click', function () {
            clearInterval(timer);
        })


    </script>
</body>

</html>

7:发送短信

点击按钮后,该按钮60秒之内不能再次点击,防止重复发送短信

案例分析:

①按钮点击之后,会禁用disabled为true

②同时按钮里面的内容会变化,注意button 里面的内容通过innerHTML修改

③里面秒数是有变化的,因此需要用到定时器

④定义一个变量,在定时器里面,不断递减

⑤如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
  手机号:  <input type="text"> <button>发送</button>

    <script>
        // 按钮点击之后,会禁用 disabled 为true 
        // 同时按钮里面的内容会变化, 注意 button 里面的内容通过 innerHTML修改
        // 里面秒数是有变化的,因此需要用到定时器
        // 定义一个变量,在定时器里面,不断递减
        // 如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态

        //1: 选择元素
        var btn = document.querySelector('button');
        var input = document.querySelector('input');

        //定义总秒数(剩下的米=秒数)
        var time = 10;

        //2 :注册事件
        //2.1: 点击按钮
        btn.addEventListener('click', function () {
            //2.1.1: 按钮致灰
            btn.disabled = true;



            //2.1.2: 开始计时(用定时器)
            var timer = setInterval(function () {
                //2.1.3:但是时间为0时就按钮就恢复,所以需要进行判断时间
                if (time === 0) {
                    //删除定时器,不需要定时了
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.innerHTML = '发送';

                } else {

                    //2.2.1: 按钮显示倒计时时间
                    btn.innerHTML = ('还剩下' + time + '秒');
                    time--;
                }
            }, 1000)



        })
    </script>
</body>

</html>

8: this

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象

现阶段,我们先了解一下几个this指向

1. 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)

2.方法调用中谁调用this指向谁

3.构造函数中this指向构造函数的实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击按钮</button>

    <script>
        // this 指向问题 一般情况下this的最终指向的是那个调用它的对象

        // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)

        //1.1: 全局作用域
        console.log(this);

        //1.2: 函数
        function fn() {
            console.log(this);
        }
        fn();

        //1.3: 定时器
        setTimeout(function () {
            console.log(this);
        }, 1000)

        // 2. 方法调用中谁调用this指向谁
        var btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            console.log(this);  // this指向的是btn这个按钮对象

        })
        btn.addEventListener('click', function () {
            console.log(this); // this指向的是btn这个按钮对象

        })

        // 3. 构造函数中this指向构造函数的实例
        function Fun() {
            console.log(this);  // this 指向的是fun 实例对象
        }
        var fun = new Fun();  
    </script>
</body>

</html>

1.6: JS执行机制

1: JS是单线程

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作DOM 而诞生的。比如我们对某个DOM 元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是:如果JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

1.1: 一个问题

以下代码执行的结果是什么?

console.log(1);

setTimeout(function () {

console.log(3);

}, 1000);

console.log(2);

2: 同步和异步

为了解决这个问题,利用多核CPU 的计算能力,HTML5 提出Web Worker 标准,允许JavaScript 脚本创建多个线程。于是,JS 中出现了同步和异步。

同步:

前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。

异步:

你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。比如做饭的异步做法,我们在烧水的同时,利用这10分钟,去切菜,炒菜。

他们的本质区别:这条流水线上各个流程的执行顺序不同。

2.1:一个问题

那么以下代码执行的结果又是什么?

console.log(1);

setTimeout(function () {

   console.log(3);

   }, 0);

  console.log(2);

3: 异步和同步

同步任务

同步任务都在主线程上执行,形成一个执行栈。

异步任务

JS 的异步是通过回调函数实现的。

一般而言,异步任务有以下三种类型:

1、普通事件,如click、resize 等

2、资源加载,如load、error 等

3、定时器,包括setInterval、setTimeout 等

异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。

4: JS执行机制

1. 先执行执行栈中的同步任务

2. 异步任务(回调函数)放入任务队列中。

3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

console.log(1);

document.onclick = function() {

    console.log('click');}
   
}

console.log(2);

setTimeout(function() {

    console.log(3)

  },3000}

分析上面代码流程:(遇到多个异步任务是怎么进行处理的)

 1: 先把所有的任务分成同步任务和异步任务;

 2:所有的同步任务放在主线程执行栈里面;而异步任务有好几个,都要放在异步任务队列里      吗?或者说主线程执行线,和异步现场执行线谁放在前面,谁放在后面? 这个时候就用异.  步进程来处理;

 处理过程:

3:先执行同步任务 console.log(1), 就先把1打印出来;

4: 再执行第二句话 document.onclick ,并且有一个异步回调函数fn,属于异步任务;这个时候        会把这个提交给异步进程来处理,它来决定你这个要不要写入异步任务队列里,所以这个      需要等待用户是否点击了。用户点击了才会把这个回调任务写入异步任务队列里,不点击      就不写入异步队列中。假如现在不点击,不写入异步队列里,这个时候就略过。

5: 再执行console.log (2) ,打印出来即可;

6: 看 setTimeout(fn,3000); 这个也是异步任务,也会提交给异步进程处理,异步进程也是等.        着3秒到了才能把这个异步任务写入异步队列中去。这个时候3秒到了,并写入了异步队.        列中console.log(3),但现在不会里面执行异步队列的任务,先把主线程的执行完成才执.        行异步队列中的;

7: 往下看是否还有代码是主线程处理的,没有就表示同步任务执行完成。再回到异步的任. 务.    队列中看是否有 异步任务,有定时器的console.log(3), 就会把这个拿到执行栈中执行,并打印3。异步队列中的任务执行完成后,队列里就没有任务了。 

8: 回到document.onclick = fn;如果点击了,就提交给异步进程处理,就把这个回调函数fn写.       入异步任务队列中console.log('click'); 这个时候任务队列里又有任务了。

9:虽然同步任务已经结束了,但还是会看到任务队列里 有没有新的异步任务,现在是又有新       的异步任务进来,并且把这个任务拿到执行栈中执行,并打印出来click;

10:  如果又点击了,就会执行8,9过程。

11: 上面过程是3秒之后点击的,所以先输出的是3 ,再输出的是click

12: 如果是在3秒钟之前点击的鼠标,那就是先输出click,再输出3;

注意: 就算同步任务完成后,还是会返回看任务队列里还有没有异步任务,有就执行;这个就是事件循环 event loop.

按照下图小总结:

在JS中会把任务分成同步任务和异步任务,把同步任务放入执行栈中,异步任务是提交给异步进程来处理,等着异步事件触发,才把回调函数异步任务放入任务队列里。当同步·任务全部执行完毕后,才到任务队列里看有没有异步任务,如果有就取出来到执行栈中去执行,然后再回头看是否有异步任务,如果有再取出来到执行栈中执行,这种循环的过程叫事件循环。

1.7: location对象

1: 什么是location对象?

window 对象给我们提供了一个location 属性用于获取或设置窗体的URL,并且可以用于解析URL 。因为这个属性返回的是一个对象,所以我们将这个属性也称为location 对象

2: URL

统一资源定位符(Uniform Resource Locator, URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

URL 的一般语法格式为:

protocol://host[:port]/path/[?query]#fragment

http://www.itcast.cn/index.html?name=andy&age=18#link

3: location对象的属性

重点记住:href 和search

4: 案例-5秒钟之后自动跳转页面

案例分析

①利用定时器做倒计时效果

②时间到了,就跳转页面。使用location.href

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>按钮</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        // btn.addEventListener('click', function () {
        // console.log(location.href);  //获取url地址
        // location.href = 'http://www.itcast.cn';  //设置url地址
        // })

        var div = document.querySelector('div');
        var timer = 3;



        setInterval(function () {
            if (timer == 0) {
                //跳转到首页
                location.href = 'http://www.itcast.cn';
            } else {
                div.innerHTML = '您将在秒钟' + timer + '之后跳转到首页';
                timer--;
            }

        }, 1000);

        //页面刷新的时候会有空白,再会出现内容,可以把下面内容放到函数里面,然后再调用函数

    </script>
</body>

</html>

5: 案例-获取URL 参数数据

案例分析:

①第一个登录页面,里面有提交表单,action 提交到index.html页面

②第二个页面,可以使用第一个页面的参数,这样实现了一个数据不同页面之间的传递效果

③第二个页面之所以可以使用第一个页面的数据,是利用了URL 里面的location.search参数

④在第二个页面中,需要把这个参数提取。

⑤第一步去掉? 利用substr

⑥第二步利用=号分割键和值split(‘=‘)

⑦第一个数组就是键 第二个数组就是值

表单要有表单域才能提交有效;

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div></div>
    <script>

        //1: 获取地址中用户输入的用户名
        console.log(location.search); //?uname=andy
        //2: 获取内容
        var div = document.querySelector('div');
        div.innerHTML = location.search; //页面获取用户输入的用户名
        //3: 先去掉? substr('起始的位置','截取几个字符')
        var params = location.search.substr(1);
        console.log(params); //uname=andy

        //4: 利用=把字符串分割为数组 split('=')
        var arr = params.split('=');
        console.log(arr);   //['uname','andy']

        //5: 利用下标获取元素(把数据写入div中)
        div.innerHTML = arr[1] + '欢迎你';
    </script>
</body>

</html>

6: location对象的方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>点击</button>

    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            //1; 记录浏览历史,所以可以实现后退功能(后退箭头)
            // location.assign('http://www.itcast.cn');

            //2; 不记录浏览历史,所以不可以实现后退功能
            // location.replace('http://www.itcast.cn');

            //3:页面刷新 true是强制性
            location.reload(true);

        })
    </script>
</body>

</html>

 1.9: navigator对象

navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent 头部的值。

下面前端代码可以判断用户那个终端打开页面,实现跳转:

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|

  Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS

|Symbian|Windows Phone)/i))){

    window.location.href = "";     //手机

} else {

   window.location.href = "";  //电脑

}

1.10: history对象

window 对象给我们提供了一个history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。

history 对象一般在实际开发中比较少用,但是会在一些OA 办公系统中见到。 

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <a href="list.html">点击我去往列表页</a>
    <button>前进</button>

    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            // history.forward();
            history.go(1);
        })
    </script>
</body>

</html>

list.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <a href="index.html">点击我去往首页</a>
    <button>后退</button>

    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function () {
            // history.back();
            history.go(-1);
        })
    </script>
</body>

</html>

二: PC端网页特效(网页交互) 

2.1:目标

  • 能够说出常见offset系列属性的作用
  • 能够说出常见client系列属性的作用
  • 能够说出常见scroll系列属性的作用
  • 能够封装简单动画函数
  • 能够写出网页轮播图案例

2.2: 目录

  • 元素偏移量offset系列
  • 元素可视区client系列
  • 元素滚动scroll系列
  • 动画函数封装
  • 常见网页特效案例

2.3:元素偏移量offset系列

1: offset概述

offset 翻译过来就是偏移量,我们使用offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小(宽度高度)
  • 注意:返回的数值都不带单位

offset 系列常用属性:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .father {
            position: relative;
            height: 200px;
            width: 200px;
            margin: 100px 100px;
            background-color: pink;
        }

        .son {
            height: 100px;
            width: 100px;
            margin-left: 50px;
            background-color: purple;
        }

        .w {
            height: 100px;
            width: 100px;
            margin: 100px 200px;
            padding-left: 50px;
            border: 10px solid green;
            background-color: skyblue;
        }
    </style>
</head>

<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <div class="w"></div>
    <script>
        //offset系列
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        // 1.可以得到元素的偏移 位置 返回的不带单位的数值  
        console.log(father.offsetTop);
        console.log(father.offsetLeft);
        // 它以带有定位的父亲为准  如果么有父亲或者父亲没有定位 则以 body 为准
        console.log(son.offsetLeft);
        var w = document.querySelector('.w');
        // 2.可以得到元素的大小 宽度和高度 是包含padding + border + width 
        console.log(w.offsetWidth);
        console.log(w.offsetHeight);  //120=100+10(上)+10(下)
        // 3. 返回带有定位的父亲 否则返回的是body
        console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
        console.log(son.parentNode);  // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位

    </script>
</body>

</html>

2: offset与style的区别

offset

offset 可以得到任意样式表中的样式值

offset 系列获得的数值是没有单位的

offsetWidth 包含padding+border+width

offsetWidth 等属性是只读属性,只能获取不能赋值

所以,我们想要获取元素大小位置,用offset更合适

style

style 只能得到行内样式表中的样式值

style.width 获得的是带有单位的字符串

style.width 获得不包含padding和border 的值

style.width 是可读写属性,可以获取也可以赋值

所以,我们想要给元素更改值,则需要用style改变

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: pink;
            padding: 10px;
        }
    </style>
</head>

<body>
    <div class="box" style="width: 300px;"></div>

    <script>
        var box = document.querySelector('.box');
        console.log(box.offsetWidth); //220
        console.log(box.style.width);  //不展示,只有行内样式表中显示
        box.offsetWidth = '400px';  //offset不能赋值
        box.style.width = '500px';
        console.log(box.style.width); //500px
    </script>
</body>

</html>

3: offset概述

offset 翻译过来就是偏移量,我们使用offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • 获得元素距离带有定位父元素的位置
  • 获得元素自身的大小(宽度高度)

4: 案例-获取鼠标在盒子内的坐标

案例分析:

①我们在盒子内点击,想要得到鼠标距离盒子左右的距离。

②首先得到鼠标在页面中的坐标(e.pageX, e.pageY)

③其次得到盒子在页面中的距离( box.offsetLeft, box.offsetTop)

④用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标

⑤如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件mousemove

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: pink;
            margin-left: 200px;
        }
    </style>
</head>

<body>
    <div class="box"></div>

    <script>
        var box = document.querySelector('.box');
        box.addEventListener('click', function (e) {
            //点击下鼠标与页面的距离
            console.log(e.pageX);
            console.log(e.pageY);

            //盒子与页面的距离
            console.log(box.offsetWidth);

            //鼠标与盒子之间的距离=鼠标与页面的距离-盒子与页面的距离
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            this.innerHTML = 'x坐标是' + x + 'y坐标是' + y;


        })
    </script>
</body>

</html>

5: 案例-模态框拖拽

弹出框,我们也称为模态框。

1.点击弹出层,会弹出模态框,并且显示灰色半透明的遮挡层。

2.点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层。

3.鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动。

4.鼠标松开,可以停止拖动模态框移动。

案例分析:

①点击弹出层,模态框和遮挡层就会显示出来display:block;

②点击关闭按钮,模态框和遮挡层就会隐藏起来display:none;

③在页面中拖拽的原理:鼠标按下并且移动,之后松开鼠标

④触发事件是鼠标按下mousedown,鼠标移动mousemove鼠标松开mouseup

⑤拖拽过程:鼠标移动过程中,获得最新的值赋值给模态框的left和top值,这样模态框可以跟着鼠标走了

⑥鼠标按下触发的事件源是最上面一行,就是id为title

⑦鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置。

⑧鼠标按下,我们要得到鼠标在盒子的坐标。

⑨鼠标移动,就让模态框的坐标设置为:鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。

⑩鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</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 link = document.querySelector('#link');
        var login = document.querySelector('.login');
        var closeBtn = document.querySelector('#closeBtn');
        var mask = document.querySelector('.login-bg');

        //2:点击弹出层这个链接link 让mask和login显示出来
        link.addEventListener('click', function () {
            login.style.display = 'block';
            mask.style.display = 'block';
        })

        //3: 点击关闭 closeBtn 就隐藏 mask和 login
        closeBtn.addEventListener('click', function () {
            mask.style.display = 'none';
            login.style.display = 'none';
        })

        //4:开始拖拽
        // (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
        var title = document.querySelector('#title');
        title.addEventListener('mousedown', function (e) {

            //获取鼠标与盒子之间的距离
            // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;

            //移动事件是在点击事件里面,在页面的任何地方都可以移动,所以事件源是页面
            //获取盒子与页面的距离(因为鼠标与盒子的距离是固定的)
            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>

6:案例:仿京东放大镜

6.1: 案例分析

①整个案例可以分为三个功能模块

②鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏2个盒子功能

③黄色的遮挡层跟随鼠标功能。

④移动黄色遮挡层,大图片跟随移动功能。

6.2.1: 功能一分析

①鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏2个盒子功能

②就是显示与隐藏

6.2.2: 功能二分析

①黄色的遮挡层跟随鼠标功能。

②把鼠标坐标给遮挡层不合适。因为遮挡层坐标以父盒子为准。

③首先是获得鼠标在盒子的坐标。④之后把数值给遮挡层做为left 和top值。

⑤此时用到鼠标移动事件,但是还是在小图片盒子内移动。

⑥发现,遮挡层位置不对,需要再减去盒子自身高度和宽度的一半。

⑦遮挡层不能超出小图片盒子范围。

⑧如果小于零,就把坐标设置为0

⑨如果大于遮挡层最大的移动距离,就把坐标设置为最大的移动距离⑩遮挡层的最大移动距离:小图片盒子宽度减去遮挡层盒子宽度

6.2.3: 功能三分析

①移动黄色遮挡层,大图片跟随移动功能。

②求大图片的移动距离公式

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>手机详情页!</title>
    <meta name="description"
        content="品优购JD.COM-专业的综合网上购物商城,销售家电、数码通讯、电脑、家居百货、服装服饰、母婴、图书、食品等数万个品牌优质商品.便捷、诚信的服务,为您提供愉悦的网上购物体验!" />
    <meta name="Keywords" content="网上购物,网上商城,手机,笔记本,电脑,MP3,CD,VCD,DV,相机,数码,配件,手表,存储卡,品优购" />
    <!-- 引入facicon.ico网页图标 -->
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
    <!-- 引入css 初始化的css 文件 -->
    <link rel="stylesheet" href="css/base.css">
    <!-- 引入公共样式的css 文件 -->
    <link rel="stylesheet" href="css/common.css">
    <!-- 引入详情页面的css文件 -->
    <link rel="stylesheet" href="css/detail.css">
    <!-- 引入我们的js 文件 -->
    <script src="js/detail.js"></script>
</head>

<body>
    <!-- 顶部快捷导航start -->
    <div class="shortcut">
        <div class="w">
            <div class="fl">
                <ul>
                    <li>品优购欢迎您! </li>
                    <li>
                        <a href="#">请登录</a>
                        <a href="#" class="style-red">免费注册</a>
                    </li>
                </ul>
            </div>
            <div class="fr">
                <ul>
                    <li><a href="#">我的订单</a></li>
                    <li class="spacer"></li>
                    <li>
                        <a href="#">我的品优购</a>
                        <i class="icomoon"></i>
                    </li>
                    <li class="spacer"></li>
                    <li><a href="#">品优购会员</a></li>
                    <li class="spacer"></li>
                    <li><a href="#">企业采购</a></li>
                    <li class="spacer"></li>
                    <li><a href="#">关注品优购</a> <i class="icomoon"></i></li>
                    <li class="spacer"></li>
                    <li><a href="#">客户服务</a> <i class="icomoon"></i></li>
                    <li class="spacer"></li>
                    <li><a href="#">网站导航</a> <i class="icomoon"></i></li>
                </ul>
            </div>
        </div>
    </div>
    <!-- 顶部快捷导航end  -->
    <!-- header制作 -->
    <div class="header w">
        <!-- logo -->
        <div class="logo">
            <h1>
                <a href="index.html" title="品优购">品优购</a>
            </h1>
        </div>
        <!-- search -->
        <div class="search">
            <input type="text" class="text" value="请搜索内容...">
            <button class="btn">搜索</button>
        </div>
        <!-- hotwrods -->
        <div class="hotwrods">
            <a href="#" class="style-red">优惠购首发</a>
            <a href="#">亿元优惠</a>
            <a href="#">9.9元团购</a>
            <a href="#">美满99减30</a>
            <a href="#">办公用品</a>
            <a href="#">电脑</a>
            <a href="#">通信</a>
        </div>
        <div class="shopcar">
            <i class="car"> </i>我的购物车 <i class="arrow">  </i>
            <i class="count">80</i>
        </div>
    </div>
    <!-- header 结束 -->
    <!-- nav start -->
    <div class="nav">
        <div class="w">
            <div class="dropdown fl">
                <div class="dt"> 全部商品分类 </div>
                <div class="dd" style="display: none;">
                    <ul>
                        <li class="menu_item"><a href="#">家用电器</a> <i>  </i> </li>
                        <li class="menu_item">
                            <a href="list.html">手机</a> 、
                            <a href="#">数码</a> 、
                            <a href="#">通信</a>
                            <i>  </i>
                        </li>
                        <li class="menu_item"><a href="#">电脑、办公</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">家居、家具、家装、厨具</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">男装、女装、童装、内衣</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">个户化妆、清洁用品、宠物</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">鞋靴、箱包、珠宝、奢侈品</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">运动户外、钟表</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">汽车、汽车用品</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">母婴、玩具乐器</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">食品、酒类、生鲜、特产</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">医药保健</a> <i>  </i> </li>
                        <li class="menu_item"><a href="#">图书、音像、电子书</a> <i> </i> </li>
                        <li class="menu_item"><a href="#">彩票、旅行、充值、票务</a> <i> </i> </li>
                        <li class="menu_item"><a href="#">理财、众筹、白条、保险</a> <i>  </i> </li>
                    </ul>
                </div>
            </div>
            <!-- 右侧导航 -->
            <div class="navitems fl">
                <ul>
                    <li><a href="#">服装城</a></li>
                    <li><a href="#">美妆馆</a></li>
                    <li><a href="#">传智超市</a></li>
                    <li><a href="#">全球购</a></li>
                    <li><a href="#">闪购</a></li>
                    <li><a href="#">团购</a></li>
                    <li><a href="#">拍卖</a></li>
                    <li><a href="#">有趣</a></li>
                </ul>
            </div>
        </div>
    </div>
    <!-- nav end -->

    <!-- 详情页内容部分  -->
    <div class="de_container w">
        <!-- 面包屑导航 -->
        <div class="crumb_wrap">
            <a href="#">手机、数码、通讯</a> 〉 <a href="#">手机 </a> 〉 <a href="#">Apple苹果 </a> 〉 <a href="#">iphone 6S Plus系类</a>
        </div>
        <!-- 产品介绍模块 -->
        <div class="product_intro clearfix">
            <!-- 预览区域 -->
            <div class="preview_wrap fl">

                <!-- js课程+ : -->
                <!-- 左边大盒子 -->
                <div class="preview_img">
                    <img src="upload/s3.png" alt="">
                    <!-- 左边盒子里面的小盒子 -->
                    <div class="mask"></div>

                    <!-- 右边大盒子 -->
                    <div class="big">
                        <!-- 右边大盒子里面的图 -->
                        <img src="upload/big.jpg" alt="" class="bigImg">
                    </div>


                </div>

                <div class="preview_list">
                    <a href="#" class="arrow_prev"></a>
                    <a href="#" class="arrow_next"></a>
                    <ul class="list_item">
                        <li>
                            <img src="upload/pre.jpg" alt="">
                        </li>
                        <li class="current">
                            <img src="upload/pre.jpg" alt="">
                        </li>
                        <li>
                            <img src="upload/pre.jpg" alt="">
                        </li>
                        <li>
                            <img src="upload/pre.jpg" alt="">
                        </li>
                        <li>
                            <img src="upload/pre.jpg" alt="">
                        </li>
                    </ul>
                </div>
            </div>
            <!-- 产品详细信息 -->
            <div class="itemInfo_wrap fr">
                <div class="sku_name">
                    Apple iPhone 6s(A1700)64G玫瑰金色 移动通信电信4G手机
                </div>
                <div class="news">
                    推荐选择下方[移动优惠购],手机套餐齐搞定,不用换号,每月还有花费返
                </div>
                <div class="summary">
                    <dl class="summary_price">
                        <dt>价格</dt>
                        <dd>
                            <i class="price">¥5299.00 </i>

                            <a href="#">降价通知</a>

                            <div class="remark">累计评价612188</div>

                        </dd>
                    </dl>
                    <dl class="summary_promotion">
                        <dt>促销</dt>
                        <dd>
                            <em>加购价</em> 满999.00另加20.00元,或满1999.00另加30.00元,或满2999.00另加40.00元,即可在购物车换 购热销商品 详情 》

                        </dd>
                    </dl>
                    <dl class="summary_support">
                        <dt>支持</dt>
                        <dd>以旧换新,闲置手机回收 4G套餐超值抢 礼品购</dd>
                    </dl>
                    <dl class="choose_color">
                        <dt>选择颜色</dt>
                        <dd>
                            <a href="javascript:;" class="current">玫瑰金</a>
                            <a href="javascript:;">金色</a>
                            <a href="javascript:;">白色</a>
                            <a href="javascript:;">土豪色</a>
                        </dd>
                    </dl>
                    <dl class="choose_version">
                        <dt>选择版本</dt>
                        <dd>
                            <a href="javascript:;" class="current">公开版</a>
                            <a href="javascript:;">移动4G</a>
                        </dd>
                    </dl>
                    <dl class="choose_type">
                        <dt>购买方式</dt>
                        <dd>
                            <a href="javascript:;" class="current">官方标配</a>
                            <a href="javascript:;">移动优惠购</a>
                            <a href="javascript:;">电信优惠购</a>
                        </dd>
                    </dl>
                    <div class="choose_btns">
                        <div class="choose_amount">
                            <input type="text" value="1">
                            <a href="javascript:;" class="add">+</a>
                            <a href="javascript:;" class="reduce">-</a>
                        </div>
                        <a href="#" class="addcar">加入购物车</a>
                    </div>
                </div>
            </div>
        </div>


        <!-- 产品细节模块 product_detail    -->
        <div class="product_detail clearfix">
            <!-- aside -->
            <div class="aside fl">
                <div class="tab_list">
                    <ul>
                        <li class="first_tab ">相关分类</li>
                        <li class="second_tab current">推荐品牌</li>
                    </ul>
                </div>
                <div class="tab_con">

                    <ul>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>
                        <li>
                            <img src="upload/aside_img.jpg" alt="">
                            <h5>华为 HUAWEI P20 Pro 全面屏徕卡</h5>
                            <div class="aside_price">¥19</div>
                            <a href="#" class="as_addcar">加入购物车</a>
                        </li>


                    </ul>
                </div>
            </div>
            <!-- detail -->
            <div class="detail fr">
                <div class="detail_tab_list">
                    <ul>
                        <li class="current">商品介绍</li>
                        <li>规格与包装</li>
                        <li>售后保障</li>
                        <li>商品评价(50000)</li>
                        <li>手机社区</li>
                    </ul>
                </div>
                <div class="detail_tab_con">
                    <div class="item">
                        <ul class="item_info">
                            <li>分辨率:1920*1080(FHD)</li>
                            <li>后置摄像头:1200万像素</li>
                            <li>前置摄像头:500万像素</li>
                            <li>核 数:其他</li>
                            <li>频 率:以官网信息为准</li>
                            <li>品牌: Apple ♥关注</li>
                            <li>商品名称:APPLEiPhone 6s Plus</li>
                            <li>商品编号:1861098</li>
                            <li>商品毛重:0.51kg</li>
                            <li>商品产地:中国大陆</li>
                            <li>热点:指纹识别,Apple Pay,金属机身,拍照神器</li>
                            <li>系统:苹果(IOS)</li>
                            <li>像素:1000-1600万</li>
                            <li>机身内存:64GB</li>
                        </ul>
                        <p>
                            <a href="#" class="more">查看更多参数</a>
                        </p>
                        <img src="upload/detail_img1.jpg" alt="">
                        <img src="upload/detail_img2.jpg" alt="">
                        <img src="upload/detail_img3.jpg" alt="">
                    </div>
                    <!-- 
                    <div class="item">规格与包装</div>
                    <div class="item">售后保障</div> 
                    -->
                </div>
            </div>
        </div>

    </div>
    <!-- 详情页内容部分  -->

    <!-- footer start -->
    <div class="footer">
        <div class="w">
            <!-- mod_service -->
            <div class="mod_service">
                <ul>
                    <li>
                        <i class="mod-service-icon mod_service_zheng"></i>
                        <div class="mod_service_tit">
                            <h5>正品保障</h5>
                            <p>正品保障,提供发票</p>
                        </div>
                    </li>
                    <li>
                        <i class="mod-service-icon mod_service_kuai"></i>
                        <div class="mod_service_tit">
                            <h5>正品保障</h5>
                            <p>正品保障,提供发票</p>
                        </div>
                    </li>
                    <li>
                        <i class="mod-service-icon mod_service_bao"></i>
                        <div class="mod_service_tit">
                            <h5>正品保障</h5>
                            <p>正品保障,提供发票</p>
                        </div>
                    </li>
                    <li>
                        <i class="mod-service-icon mod_service_bao"></i>
                        <div class="mod_service_tit">
                            <h5>正品保障</h5>
                            <p>正品保障,提供发票</p>
                        </div>
                    </li>
                    <li>
                        <i class="mod-service-icon mod_service_bao"></i>
                        <div class="mod_service_tit">
                            <h5>正品保障</h5>
                            <p>正品保障,提供发票</p>
                        </div>
                    </li>
                </ul>
            </div>
            <!-- mod_help -->
            <div class="mod_help">
                <dl class="mod_help_item">
                    <dt>购物指南</dt>
                    <dd> <a href="#">购物流程 </a></dd>
                    <dd> <a href="#">会员介绍 </a></dd>
                    <dd> <a href="#">生活旅行/团购 </a></dd>
                    <dd> <a href="#">常见问题 </a></dd>
                    <dd> <a href="#">大家电 </a></dd>
                    <dd> <a href="#">联系客服 </a></dd>
                </dl>
                <dl class="mod_help_item">
                    <dt>购物指南</dt>
                    <dd> <a href="#">购物流程 </a></dd>
                    <dd> <a href="#">会员介绍 </a></dd>
                    <dd> <a href="#">生活旅行/团购 </a></dd>
                    <dd> <a href="#">常见问题 </a></dd>
                    <dd> <a href="#">大家电 </a></dd>
                    <dd> <a href="#">联系客服 </a></dd>
                </dl>
                <dl class="mod_help_item">
                    <dt>购物指南</dt>
                    <dd> <a href="#">购物流程 </a></dd>
                    <dd> <a href="#">会员介绍 </a></dd>
                    <dd> <a href="#">生活旅行/团购 </a></dd>
                    <dd> <a href="#">常见问题 </a></dd>
                    <dd> <a href="#">大家电 </a></dd>
                    <dd> <a href="#">联系客服 </a></dd>
                </dl>
                <dl class="mod_help_item">
                    <dt>购物指南</dt>
                    <dd> <a href="#">购物流程 </a></dd>
                    <dd> <a href="#">会员介绍 </a></dd>
                    <dd> <a href="#">生活旅行/团购 </a></dd>
                    <dd> <a href="#">常见问题 </a></dd>
                    <dd> <a href="#">大家电 </a></dd>
                    <dd> <a href="#">联系客服 </a></dd>
                </dl>
                <dl class="mod_help_item">
                    <dt>购物指南</dt>
                    <dd> <a href="#">购物流程 </a></dd>
                    <dd> <a href="#">会员介绍 </a></dd>
                    <dd> <a href="#">生活旅行/团购 </a></dd>
                    <dd> <a href="#">常见问题 </a></dd>
                    <dd> <a href="#">大家电 </a></dd>
                    <dd> <a href="#">联系客服 </a></dd>
                </dl>
                <dl class="mod_help_item mod_help_app">
                    <dt>帮助中心</dt>
                    <dd>
                        <img src="upload/erweima.png" alt="">
                        <p>品优购客户端</p>
                    </dd>
                </dl>
            </div>

            <!-- mod_copyright  -->
            <div class="mod_copyright">
                <p class="mod_copyright_links">
                    关于我们 | 联系我们 | 联系客服 | 商家入驻 | 营销中心 | 手机品优购 | 友情链接 | 销售联盟 | 品优购社区 | 品优购公益 | English Site | Contact U
                </p>
                <p class="mod_copyright_info">
                    地址:北京市昌平区建材城西路金燕龙办公楼一层 邮编:100096 电话:400-618-4000 传真:010-82935100 邮箱: zhanghj+itcast.cn <br>
                    京ICP备08001421号京公网安备110108007702
                </p>
            </div>
        </div>
    </div>
    <!-- footer end -->
</body>

</html>

detail.css

/*详情页的样式文件*/

.de_container {
    margin-top: 20px;
}

.crumb_wrap {
    height: 25px;
}

.crumb_wrap a {
    margin-right: 10px;
}

.preview_wrap {
    width: 400px;
    height: 590px;
}

.preview_img {
    position: relative;
    height: 398px;
    border: 1px solid #ccc;
}

/*  js课程+ */
.mask {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    width: 300px;
    height: 300px;
    background: #FEDE4F;
    opacity: .5;
    border: 1px solid #ccc;
    cursor: move;
}

/*  js课程+ */
.big {
    display: none;
    position: absolute;
    left: 410px;
    top: 0;
    width: 500px;
    height: 500px;
    background-color: pink;
    z-index: 999;
    border: 1px solid #ccc;
    overflow: hidden;
}

/* 赋值left top一定要定位postion才能移动 */
.big img {
    position: absolute;
    top: 0;
    left: 0;
}

.preview_list {
    position: relative;
    height: 60px;
    margin-top: 60px;
}

.list_item {
    width: 320px;
    height: 60px;
    margin: 0 auto;
}

.list_item li {
    float: left;
    width: 56px;
    height: 56px;
    border: 2px solid transparent;
    margin: 0 2px;
}

.list_item li.current {
    border-color: #c81623;
}

.arrow_prev,
.arrow_next {
    position: absolute;
    top: 15px;
    width: 22px;
    height: 32px;
    background-color: purple;
}

.arrow_prev {
    left: 0;
    background: url(../img/arrow-prev.png) no-repeat;
}

.arrow_next {
    right: 0;
    background: url(../img/arrow-next.png) no-repeat;
}

.itemInfo_wrap {
    width: 718px;
}

.sku_name {
    height: 30px;
    font-size: 16px;
    font-weight: 700;
}

.news {
    height: 32px;
    color: #e12228;
}

.summary dl {
    overflow: hidden;
}

.summary dt,
.summary dd {
    float: left;
}

.summary dt {
    width: 60px;
    padding-left: 10px;
    line-height: 36px;
}

.summary_price,
.summary_promotion {
    position: relative;
    padding: 10px 0;
    background-color: #fee9eb;
}

.price {
    font-size: 24px;
    color: #e12228;
}

.summary_price a {
    color: #c81623;
}

.remark {
    position: absolute;
    right: 10px;
    top: 20px;
}

.summary_promotion {
    padding-top: 0;
}

.summary_promotion dd {
    width: 450px;
    line-height: 36px;
}

.summary_promotion em {
    display: inline-block;
    width: 40px;
    height: 22px;
    background-color: #c81623;
    text-align: center;
    line-height: 22px;
    color: #fff;
}

.summary_support dd {
    line-height: 36px;
}

.choose_color a {
    display: inline-block;
    width: 80px;
    height: 41px;
    background-color: #f7f7f7;
    border: 1px solid #ededed;
    text-align: center;
    line-height: 41px;
}

.summary a.current {
    border-color: #c81623;
}

.choose_version {
    margin: 10px 0;
}

.choose_version a,
.choose_type a {
    display: inline-block;
    height: 32px;
    padding: 0 12px;
    background-color: #f7f7f7;
    border: 1px solid #ededed;
    text-align: center;
    line-height: 32px;
}

.choose_btns {
    margin-top: 20px;
}

.choose_amount {
    position: relative;
    float: left;
    width: 50px;
    height: 46px;
    background-color: pink;
}

.choose_amount input {
    width: 33px;
    height: 44px;
    border: 1px solid #ccc;
    text-align: center;
}

.add,
.reduce {
    position: absolute;
    right: 0;
    width: 15px;
    height: 22px;
    border: 1px solid #ccc;
    background-color: #f1f1f1;
    text-align: center;
    line-height: 22px;
}

.add {
    top: 0;
}

.reduce {
    bottom: 0;
    /*禁止鼠标样式*/
    cursor: not-allowed;
    /* pointer  小手  move  移动  */
}

.addcar {
    float: left;
    width: 142px;
    height: 46px;
    background-color: #c81623;
    text-align: center;
    line-height: 46px;
    font-size: 18px;
    color: #fff;
    margin-left: 10px;
    font-weight: 700;
}

.product_detail {
    margin-bottom: 50px;
}

.aside {
    width: 208px;
    border: 1px solid #ccc;
}

.tab_list {
    overflow: hidden;
    height: 34px;
}


/*把背景颜色 底边框都给 li*/

.tab_list li {
    float: left;
    background-color: #f1f1f1;
    border-bottom: 1px solid #ccc;
    height: 33px;
    text-align: center;
    line-height: 33px;
}


/*鼠标单击 li 变化样式   背景变白色 去掉下边框 文字变颜色*/

.tab_list .current {
    background-color: #fff;
    border-bottom: 0;
    color: red;
}

.first_tab {
    width: 104px;
}

.second_tab {
    width: 103px;
    border-left: 1px solid #ccc;
}

.tab_con {
    padding: 0 10px;
}

.tab_con li {
    border-bottom: 1px solid #ccc;
}

.tab_con li h5 {
    /*超出的文字省略号显示*/
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 400;
}

.aside_price {
    font-weight: 700;
    margin: 10px 0;
}

.as_addcar {
    display: block;
    width: 88px;
    height: 26px;
    border: 1px solid #ccc;
    background-color: #f7f7f7;
    margin: 10px auto;
    text-align: center;
    line-height: 26px;
}

.detail {
    width: 978px;
}

.detail_tab_list {
    height: 39px;
    border: 1px solid #ccc;
    background-color: #f1f1f1;
}

.detail_tab_list li {
    float: left;
    height: 39px;
    line-height: 39px;
    padding: 0 20px;
    text-align: center;
    cursor: pointer;
}

.detail_tab_list .current {
    background-color: #c81623;
    color: #fff;
}

.item_info {
    padding: 20px 0 0 20px;
}

.item_info li {
    line-height: 22px;
}

.more {
    float: right;
    font-weight: 700;
    font-family: 'icomoon';
}

detail.js

// 页面加载是从上往下:css---> html ----> js
// 先页面加载完后,才执行js
document.addEventListener('load', function () {
    var preview_img = document.querySelector('.preview_img');
    var mask = document.querySelector('.mask');
    //右边的图
    var big = document.querySelector('.big');

    //1:当鼠标经过的时候  preview_img 就显示和隐藏 mask 遮挡层 和 big 大盒子
    preview_img.addEventListener('mouseover', function () {
        mask.style.display = 'block';
        big.style.display = 'block';
    })

    preview_img.addEventListener('mouseout', function () {
        mask.style.display = 'none';
        big.style.display = 'none';
    })

    //2:鼠标移动的时候,让黄色的盒子跟着鼠标来走
    //注意:得到盒子与页面的距离时要注意:这个盒子是否有父盒子,并且父盒子有定位的话,那么offsetleft算出来的就是盒子与父盒子之间的距离
    preview_img.addEventListener('mousemove', function (e) {
        //2.1:先计算出鼠标在盒子内的坐标
        var x = e.pageX - this.offsetWidth;
        var y = e.pagey - this.offsetHight;

        //2.把鼠标的坐标赋值给阴影盒子mask
        // mask.style.left = x + 'px';
        // mask.style.top = y + 'px';

        //2.3:因为鼠标要在mask中央,所以盒子是300,鼠标要在一半 150 才到正中央;
        var maskX = x - (mask, offsetWidth / 2);
        var maskY = y - (mask.offsetHight / 2);
        // //把鼠标的坐标赋值给阴影盒子mask
        // mask.style.left = maskX + 'px';
        // mask.style.top = maskY + 'px';


        //3: mask盒子只能在 preview_img内移动,不能超出这个盒子
        //3.1: mask以preview_img的左右边框位准;如果x 坐标小于0 就让他停在0 的位置

        //遮挡层的最大移动距离:正方形的宽高是一样的
        maskMax = preview_img.offsetWidth - mask.offsetWidth;
        //左
        if (maskX <= 0) {
            maskX = 0;

            //右:preview盒子-mask盒子= mask移动的最大值
        } else if (maskX >= maskMax) {
            maskX = maskMax;
        }

        //上
        if (maskY <= 0) {
            maskY = 0;
        } else if (maskY >= maskMax) {
            maskY = maskMax;
        }


        //2:把鼠标的坐标赋值给阴影盒子mask
        mask.style.left = maskX + 'px';
        mask.style.top = maskY + 'px';

        //3: 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
        //大图
        var bigImg = document.querySelector('.bigImg');
        //大图移动的最大距离(大盒子和大图之间最大的距离) = 大图到页面的距离 - 大盒子到页面的距离
        var bigMax = bigImg.offsetWidth = big.offsetWidth;
        //大图片的移动距离 x Y;
        
        var bigX = maskX * bigMax / maskMax;
        var bigX = maskY * bigMax / maskMax;

        //赋值left top一定要定位postion才能移动
        // 因为小图片移动和大图片移动相反,所以用-
        bigImg.style.left = -bigX + 'px';
        bigImg.style.top = -bigY + 'px';





    })
})

2.4: 元素可视区 client系列

client翻译过来就是客户端,我们使用client 系列的相关属性来获取元素可视区的相关信息。通过client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。

client翻译过来就是客户端,我们使用client 系列的相关属性来获取元素可视区的相关信息。通过client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border: 10px solid green;
            /* padding: 10px; */
        }
    </style>
</head>

<body>
    <div></div>
    <script>
        // client 宽度 和我们offsetWidth 最大的区别就是 不包含边框
        var div = document.querySelector('div');
        console.log(div.clientWidth);
    </script>
</body>

</html>

2: 案例-淘宝flexible.js 源码分析 

立即执行函数 (function() {})() 或者  (function(){}())

主要作用:创建一个独立的作用域。避免了命名冲突问题

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //1:需要调用函数
        function fn() {
            console.log(1);
        }
        fn();

        //2: 立即执行函数,不需要调用,立马能够自己执行函数
        //3:写法· 也可以传递参数进来
        //3.1: (function(){})() 或者  2: (function ( ) { } ( ));

        (function (a, b) {
            console.log(a + b);
            var num = 10;   //两个num都互不影响,因为在不同的作用域中
        })(1, 2); //第二个小括号可以看做是调用函数

        (function (a, b) {
            console.log(a + b);
            var num = 10; //局部变量
        }(2, 3));

        // 3. 立即执行函数最大的作用就是 独立创建了一个作用域, 里面所有的变量都是局部变量 不会有命名冲突的情况
    </script>
</body>

</html>

 3: js分析

(function flexible(window, document) {
    // 获取的html 的根元素
    var docEl = document.documentElement
    // dpr 物理像素比(看当前的浏览器是否能拿到物理像素比,如果能拿到就显示当前的,不能拿到就显示1 )
    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() {
        // 把屏幕分成10等份
        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))

2.5: 元素滚动scroll系列

1:元素scroll 系列属性

scroll翻译过来就是滚动的,我们使用scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。

scroll 翻译过来就是滚动的,我们使用scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。

 

2: 页面被卷去的头部

如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发onscroll 事件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            /* 隐藏溢出的部分:就会出现滚动条 */
            overflow: auto;
        }
    </style>
</head>

<body>
    <div>
        我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容
        我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容
    </div>

    <script>
        //scroll系列
        var div = document.querySelector('div');
        //随着内容变化大小
        console.log(div.scrollHeight); //293
        //不会随着内容变化大小
        console.log(div.clientHeight); //200

        div.addEventListener('scroll', function () {
            //scrolltop是滚动上去,不显示的高度
            console.log(div.scrollTop);
        })
    </script>
</body>

</html>

3:案例-仿淘宝固定侧边栏

需求:

1.原先侧边栏是绝对定位

2. 当页面滚动到一定位置,侧边栏改为固定定位

3. 页面继续滚动,会让返回顶部显示出来

案例分析:

①需要用到页面滚动事件scroll因为是页面滚动,所以事件源是document

②滚动到某个位置,就是判断页面被卷去的上部值。

③页面被卷去的头部:可以通过window.pageYOffset获得如果是被卷去的左侧window.pageXOffset

④注意,元素被卷去的头部是element.scrollTop ,如果是页面被卷去的头部则是window.pageYOffset

⑤其实这个值可以通过盒子的offsetTop可以得到,如果大于等于这个值,就可以让盒子固定定位了

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }
         
        .w {
            width: 1200px;
            margin: 10px auto;
        }
         
        .header {
            height: 150px;
            background-color: purple;
        }
         
        .banner {
            height: 250px;
            background-color: skyblue;
        }
         
        .main {
            height: 1000px;
            background-color: yellowgreen;
        }
         
        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>
</head>
 
<body>
    <div class="slider-bar">
        <span class="goBack">返回顶部</span>
    </div>
    <div class="header w">头部区域</div>
    <div class="banner w">banner区域</div>
    <div class="main w">主体部分</div>
    <script>
        //1. 获取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
        var bannerTop = banner.offsetTop

        // 当我们侧边栏固定定位之后应该变化的数值
        //页面滑动,滑轮条固定位置 = 滑轮条到页面的距离 - banner盒子到页面的距离
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 获取main 主体元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 页面滚动事件 scroll
        document.addEventListener('scroll', function() {
            // console.log(11);
            // window.pageYOffset 页面被卷去的头部
            // console.log(window.pageYOffset);
            // 3 .当我们页面被卷去的头部大于等于了 172 此时 此时 侧边栏就要改为固定定位,并固定到某个位置
           
          // if(window.pageYOffset >= 172){
            if (window.pageYOffset >= bannerTop) {
                sliderbar.style.position = 'fixed';

                //滑轮条到页面的固定位置
                sliderbar.style.top = sliderbarTop + 'px';
            } else {
                sliderbar.style.position = 'absolute';

                //回复原来的位置距离
                sliderbar.style.top = '300px';
            }
            // 4. 当我们页面滚动到main盒子,就显示 goback模块
            if (window.pageYOffset >= mainTop) {
                goBack.style.display = 'block';
            } else {
                goBack.style.display = 'none';
            }
 
        })
    </script>
</body>
 
</html>

4:页面被卷去的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:

1. 声明了DTD,使用document.documentElement.scrollTop

2. 未声明DTD,使用document.body.scrollTop

3. 新方法window.pageYOffset和window.pageXOffset,IE9开始支持

function getScroll() {

    return {

      left: window.pageXOffset ||document.documentElement.scrollLeft ||document.body.scrollLeft||0,

     top: window.pageYOffset ||document.documentElement.scrollTop ||document.body.scrollTop ||0 };  

}

使用的时候   getScroll().left

  5: 三大系列总结

他们主要用法:

1.offset系列经常用于获得元素位置  offsetLeftof fsetTop

2.client经常用于获取元素大小  clientWidth clientHeight

3.scroll经常用于获取滚动距离 scrollTop scrollLeft

4.注意页面滚动的距离通过 window.pageXOffset获得

6: mouseenter 和mouseover的区别

mouseenter 鼠标事件

当鼠标移动到元素上时就会触发mouseenter 事件类似mouseover,它们两者之间的差别是mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发

之所以这样,就是因为mouseenter不会冒泡

跟mouseenter搭配鼠标离开mouseleave 同样不会冒泡

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .father {
            width: 300px;
            height: 300px;
            background-color: pink;
            margin: 100px auto;
        }
         
        .son {
            width: 200px;
            height: 200px;
            background-color: purple;
        }
    </style>
</head>
 
<body>
    <div class="father">
        <div class="son"></div>
    </div>
    <script>
        var father = document.querySelector('.father');
        var son = document.querySelector('.son');
        father.addEventListener('mouseenter', function() {
            console.log(11);
 
        })
    </script>
</body>
 
</html>

2.6: 动画函数封装

1:  动画实现原理

核心注意:要移动位置必须使用定位才能移动;动画里面必须添加定位

核心原理:通过定时器setInterval() 不断移动盒子位置。

实现步骤:

1. 获得盒子当前位置

2. 让盒子在当前位置加上1个移动距离

3. 利用定时器不断重复这个操作

4. 加一个结束定时器的条件

5.注意此元素需要添加定位,才能使用element.style.left

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            position: absolute;
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div></div>
    <script>
        // 动画原理
        // 1. 获得盒子当前位置  
        // 2. 让盒子在当前位置加上1个移动距离
        // 3. 利用定时器不断重复这个操作
        // 4. 加一个结束定时器的条件
        // 5. 注意此元素需要添加定位, 才能使用element.style.left


        //1.1:获取元素
        var div = document.querySelector('div');

        //1.2:盒子原来的距离+1(offset只能读取值,不能赋值)
        // div.style.left = div.offsetLeft + 100 + 'px';

        //1.3:定时器移动
        var timer = setInterval(function () {
            //3:设定移动的最大距离是400px,达到400则停止移动,清除定时器
            if (div.offsetLeft >= 400) {
                clearInterval(timer);
            }
            div.style.left = div.offsetLeft + 10 + 'px';
        }, 30);

    </script>
</body>

</html>

2: 动画片函数简单封装

注意函数需要传递2个参数,动画对象和移动到的距离

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            position: absolute;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            display: block;
            width: 200px;
            height: 200px;
            background-color: skyblue;
        }
    </style>
</head>

<body>
    <div></div>
    <span>夏雨荷</span>

    <script>

        //1: 封装动画函数
        // 简单动画函数封装obj目标对象 target 目标位置
        function animate(obj, target) {
            var timer = setInterval(function () {
                if (obj.offsetLeft >= target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';
            }, 30);

        }

        var div = document.querySelector('div');
        var span = document.querySelector('span');
        //2:调用动画函数
        animate(div, 500);
        animate(span, 300);

    </script>
</body>

</html>

3-动画函数简单封装优化(动画函数给不同元素记录不同定时器)

原因:

1:之前用var来声明,每次调用都开辟一次新的空间,会照成浪费。

2:并且名字都一样,会出现奇异;所以用对象属性的办法来处理优化,不需要每次都用var声明,并且属性每个调用者自己的函数来。

3:有按钮的情况下,一旦按钮越来越快,那么动画也会跑的越来越快,解决办法就是只让一个定时器执行,就行了。那么就删除其他的定时器。

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }
         
        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>
 
<body>
    <button>点击夏雨荷才走</button>
    <div></div>
    <span>夏雨荷</span>
    <script>
        // var obj = {};
        // obj.name = 'andy';
        // 简单动画函数封装obj目标对象 target 目标位置
        // 给不同的元素指定了不同的定时器
        function animate(obj, target) {
            // 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
            // 解决方案就是 让我们元素只有一个定时器执行
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';
 
            }, 30);
        }
 
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        var btn = document.querySelector('button');
        // 调用函数
        animate(div, 300);
        btn.addEventListener('click', function() {
            animate(span, 200);
        })
    </script>
</body>
 
</html>

4:  缓动效果原理

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

思路:

1.让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。

2.核心算法:(目标值-现在的位置)/10做为每次移动的距离步长

3.停止的条件是:让当前盒子位置等于目标位置就停止定时器

4.注意步长值需要取整

5: 动画函数多个目标值之间移动

可以让动画函数从800移动到500。

当我们点击按钮时候,判断步长是正值还是负值

1.如果是正值,则步长往大了取整

2.如果是负值,则步长向小了取整

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>

<body>
    <button class="btn500">点击夏雨荷到500</button>
    <button class="btn800">点击夏雨荷到800</button>

    <!-- <div></div> -->
    <span>夏雨荷</span>
    <script>
        //缓动动画函数封装obj 目标对象 target目标位置
        //思路:
        //1: 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
        //2: 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        //3: 停止的条件是: 让当前的盒子位置等于目标位置就停止定时器

        function animate(obj, target) {
            //先清除一切的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {

                //因为每次移动的步长都是变化的,所以步长值写在定时器里面
                //步长公式:(目标值 - 现在的位置) / 10
                //当盒子在左边,往右走是得到小数的步数,那么就向上去值,小数改为整数
                var step = Math.ceil(target - obj.offsetLeft) / 10;

                //当盒子走到左边时,要回退,如果有小时,就要往小值取;与上面step整合
                var step = (target - obj.offsetLeft) / 10;
                //三目运算符:如果是step是正的,则值往大的取;否则往小的取
                step = step > 0 ? Math.ceil(step) : Math.floor(step);

                if (obj.offsetLeft == target) {
                    //停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                }
                //把每次加1 这个步长值改为一个 慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 15);

        }

        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');

        //调用函数
        btn500.addEventListener('click', function () {
            animate(span, 500);
        });

        btn800.addEventListener('click', function () {
            animate(span, 800);
        });

        //匀速动画  就是  盒子是当前的位置  + 固定的值 10
        //缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10
    </script>
</body>

</html>

6: 缓动动画添加回调函数

回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。回调函数写的位置:定时器结束的位置。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }

        span {
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>

<body>
    <button class="btn500">点击夏雨荷到500</button>
    <button class="btn800">点击夏雨荷到800</button>

    <!-- <div></div> -->
    <span>夏雨荷</span>
    <script>
        //缓动动画函数封装obj 目标对象 target目标位置
        //思路:
        //1: 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
        //2: 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
        //3: 停止的条件是: 让当前的盒子位置等于目标位置就停止定时器

        function animate(obj, target, callback) {
            //先清除一切的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {

                //因为每次移动的步长都是变化的,所以步长值写在定时器里面
                //步长公式:(目标值 - 现在的位置) / 10
                //当盒子在左边,往右走是得到小数的步数,那么就向上去值,小数改为整数
                var step = Math.ceil(target - obj.offsetLeft) / 10;

                //当盒子走到左边时,要回退,如果有小时,就要往小值取;与上面step整合
                var step = (target - obj.offsetLeft) / 10;
                //三目运算符:如果是step是正的,则值往大的取;否则往小的取
                step = step > 0 ? Math.ceil(step) : Math.floor(step);

                if (obj.offsetLeft == target) {
                    //停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                    //回调:如果有回调,则执行回调函数;执行背景颜色是粉色
                    if (callback) {
                        callback();
                    }
                }
                //把每次加1 这个步长值改为一个 慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 15);

        }

        var span = document.querySelector('span');
        var btn500 = document.querySelector('.btn500');
        var btn800 = document.querySelector('.btn800');

        //调用函数
        btn500.addEventListener('click', function () {
            animate(span, 500);
        });

        btn800.addEventListener('click', function () {
            animate(span, 800, function () {
                // alert('haha');
                span.style.background = 'pink';
            });
        });

        //匀速动画  就是  盒子是当前的位置  + 固定的值 10
        //缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10
    </script>
</body>

</html>

7: 动画函数封装到单独JS文件里面

因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。

1.单独新建一个JS文件。

function animate(obj, target, callback) {
    //先清除一切的定时器,只保留当前的一个定时器执行
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {

        //因为每次移动的步长都是变化的,所以步长值写在定时器里面
        //步长公式:(目标值 - 现在的位置) / 10
        //当盒子在左边,往右走是得到小数的步数,那么就向上去值,小数改为整数
        var step = Math.ceil(target - obj.offsetLeft) / 10;

        //当盒子走到左边时,要回退,如果有小时,就要往小值取;与上面step整合
        var step = (target - obj.offsetLeft) / 10;
        //三目运算符:如果是step是正的,则值往大的取;否则往小的取
        step = step > 0 ? Math.ceil(step) : Math.floor(step);

        if (obj.offsetLeft == target) {
            //停止动画 本质是停止定时器
            clearInterval(obj.timer);
            //回调:如果有回调,则执行回调函数;执行背景颜色是粉色
            if (callback) {
                callback();
            }
        }
        //把每次加1 这个步长值改为一个 慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';
    }, 15);

}

2.HTML文件引入JS文件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .sliderbar {
            position: fixed;
            right: 0;
            bottom: 100px;
            width: 40px;
            height: 40px;
            text-align: center;
            line-height: 40px;
            cursor: pointer;
            color: #fff;
        }

        .con {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 40px;
            background-color: purple;
            z-index: -1;
        }
    </style>
    <!-- 引入js -->
    <script src="animate.js"></script>
</head>

<body>
    <div class="sliderbar">
        <span>←</span>
        <div class="con">问题反馈</div>
    </div>

    <script>
        //1: 选择元素
        var sliderbar = document.querySelector('.sliderbar');
        var span = document.querySelector('span');
        var con = document.querySelector('.con');

        //2:当我们鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧
        // 当我们鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧
        sliderbar.addEventListener('mouseenter', function () {
            //调用js中的动画函数
            //con的长度 - sliderbar的长度 = 160 ;因为是往反方向,所以-
            animate(con, -160);
            //使用回调函数,当执行完动画后,就把 <- 改为 -->
            animate(con, -160, function () {
                sliderbar.children[0].innerHTML = '->';
            })
        })

        sliderbar.addEventListener('mouseleave', function () {
            //调用js中的动画函数
            animate(con, 0, function () {
                sliderbar.children[0].innerHTML = '<-';

            });
        })

    </script>
</body>

</html>

2.7: 常见网页特效案例

1:网页轮播图 结合之前的品优购 直接添加js

轮播图也称为焦点图,是网页中比较常见的网页特效。

1.1: 功能需求

1.鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

2.点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。

3.图片播放的同时,下面小圆圈模块跟随一起变化。

4.点击小圆圈,可以播放相应图片。

5.鼠标不经过轮播图,轮播图也会自动播放图片。

6.鼠标经过,轮播图模块,自动播放停止。

1.2: 案例分析

 

代码只显示js部分:完整版可以看百度网盘,或者视频提供的资料

window.addEventListener('load', function() {
    // 1. 获取元素
    var arrow_l = document.querySelector('.arrow-l');
    var arrow_r = document.querySelector('.arrow-r');
    var focus = document.querySelector('.focus');
    var focusWidth = focus.offsetWidth;
    // 2. 鼠标经过focus 就显示隐藏左右按钮
    focus.addEventListener('mouseenter', function() {
        arrow_l.style.display = 'block';
        arrow_r.style.display = 'block';
        clearInterval(timer);
        timer = null; // 清除定时器变量
    });
    focus.addEventListener('mouseleave', function() {
        arrow_l.style.display = 'none';
        arrow_r.style.display = 'none';
        timer = setInterval(function() {
            //手动调用点击事件
            arrow_r.click();
        }, 2000);
    });
    // 3. 动态生成小圆圈  有几张图片,我就生成几个小圆圈
    var ul = focus.querySelector('ul');
    var ol = focus.querySelector('.circle');
    // console.log(ul.children.length);
    for (var i = 0; i < ul.children.length; i++) {
        // 创建一个小li 
        var li = document.createElement('li');
        // 记录当前小圆圈的索引号 通过自定义属性来做 
        li.setAttribute('index', i);
        // 把小li插入到ol 里面
        ol.appendChild(li);
        // 4. 小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件
        li.addEventListener('click', function() {
            // 干掉所有人 把所有的小li 清除 current 类名
            for (var i = 0; i < ol.children.length; i++) {
                ol.children[i].className = '';
            }
            // 留下我自己  当前的小li 设置current 类名
            this.className = 'current';
            // 5. 点击小圆圈,移动图片 当然移动的是 ul 
            // ul 的移动距离 小圆圈的索引号 乘以 图片的宽度 注意是负值
            // 当我们点击了某个小li 就拿到当前小li 的索引号
            var index = this.getAttribute('index');
            // 当我们点击了某个小li 就要把这个li 的索引号给 num  
            num = index;
            // 当我们点击了某个小li 就要把这个li 的索引号给 circle  
            circle = index;
            // num = circle = index;
            console.log(focusWidth);
            console.log(index);

            animate(ul, -index * focusWidth);
        })
    }
    // 把ol里面的第一个小li设置类名为 current
    ol.children[0].className = 'current';
    // 6. 克隆第一张图片(li)放到ul 最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7. 点击右侧按钮, 图片滚动一张
    var num = 0;
    // circle 控制小圆圈的播放
    var circle = 0;
    // flag 节流阀
    var flag = true;
    arrow_r.addEventListener('click', function() {
        if (flag) {
            flag = false; // 关闭节流阀
            // 如果走到了最后复制的一张图片,此时 我们的ul 要快速复原 left 改为 0
            if (num == ul.children.length - 1) {
                ul.style.left = 0;
                num = 0;
            }
            num++;
            animate(ul, -num * focusWidth, function() {
                flag = true; // 打开节流阀
            });
            // 8. 点击右侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle++;
            // 如果circle == 4 说明走到最后我们克隆的这张图片了 我们就复原
            if (circle == ol.children.length) {
                circle = 0;
            }
            // 调用函数
            circleChange();
        }
    });

    // 9. 左侧按钮做法
    arrow_l.addEventListener('click', function() {
        if (flag) {
            flag = false;
            if (num == 0) {
                num = ul.children.length - 1;
                ul.style.left = -num * focusWidth + 'px';

            }
            num--;
            animate(ul, -num * focusWidth, function() {
                flag = true;
            });
            // 点击左侧按钮,小圆圈跟随一起变化 可以再声明一个变量控制小圆圈的播放
            circle--;
            // 如果circle < 0  说明第一张图片,则小圆圈要改为第4个小圆圈(3)
            // if (circle < 0) {
            //     circle = ol.children.length - 1;
            // }
            circle = circle < 0 ? ol.children.length - 1 : circle;
            // 调用函数
            circleChange();
        }
    });

    function circleChange() {
        // 先清除其余小圆圈的current类名
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        // 留下当前的小圆圈的current类名
        ol.children[circle].className = 'current';
    }
    // 10. 自动播放轮播图
    var timer = setInterval(function() {
        //手动调用点击事件
        arrow_r.click();
    }, 2000);

})

2: 节流阀

防止轮播图按钮连续点击造成播放过快。

节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。

开始设置一个变量var flag = true;

If(flag) {flag = false; do something} 关闭水龙头

利用回调函数动画执行完毕,flag = true打开水龙头

function animate(obj, target, callback) {
    // console.log(callback);  callback = function() {}  调用的时候 callback()

    // 先清除以前的定时器,只保留当前的一个定时器执行
    clearInterval(obj.timer);
    obj.timer = setInterval(function() {
        // 步长值写到定时器的里面
        // 把我们步长值改为整数 不要出现小数的问题
        // var step = Math.ceil((target - obj.offsetLeft) / 10);
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step);
        if (obj.offsetLeft == target) {
            // 停止动画 本质是停止定时器
            clearInterval(obj.timer);
            // 回调函数写到定时器结束里面
            // if (callback) {
            //     // 调用函数
            //     callback();
            // }
            callback && callback(); //优化上个步骤,用到了短路运算符
        }
        // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
        obj.style.left = obj.offsetLeft + step + 'px';

    }, 15);
}

3: 返回顶部

滚动窗口至文档中的特定位置。

window.scroll(x, y)

注意,里面的x和y 不跟单位,直接写数字

案例分析:

①带有动画的返回顶部

②此时可以继续使用我们封装的动画函数

③只需要把所有的left 相关的值改为跟页面垂直滚动距离相关就可以了

④页面滚动了多少,可以通过window.pageYOffset得到

⑤最后是页面滚动,使用window.scroll(x,y)

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }
         
        .w {
            width: 1200px;
            margin: 10px auto;
        }
         
        .header {
            height: 150px;
            background-color: purple;
        }
         
        .banner {
            height: 250px;
            background-color: skyblue;
        }
         
        .main {
            height: 1000px;
            background-color: yellowgreen;
        }
         
        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>
</head>
 
<body>
    <div class="slider-bar">
        <span class="goBack">返回顶部</span>
    </div>
    <div class="header w">头部区域</div>
    <div class="banner w">banner区域</div>
    <div class="main w">主体部分</div>
    <script>
        //1. 获取元素
        var sliderbar = document.querySelector('.slider-bar');
        var banner = document.querySelector('.banner');
        // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
        var bannerTop = banner.offsetTop
            // 当我们侧边栏固定定位之后应该变化的数值
        var sliderbarTop = sliderbar.offsetTop - bannerTop;
        // 获取main 主体元素
        var main = document.querySelector('.main');
        var goBack = document.querySelector('.goBack');
        var mainTop = main.offsetTop;
        // 2. 页面滚动事件 scroll
        document.addEventListener('scroll', function() {
                // console.log(11);
                // window.pageYOffset 页面被卷去的头部
                // console.log(window.pageYOffset);
                // 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
                if (window.pageYOffset >= bannerTop) {
                    sliderbar.style.position = 'fixed';
                    sliderbar.style.top = sliderbarTop + 'px';
                } else {
                    sliderbar.style.position = 'absolute';
                    sliderbar.style.top = '300px';
                }
                // 4. 当我们页面滚动到main盒子,就显示 goback模块
                if (window.pageYOffset >= mainTop) {
                    goBack.style.display = 'block';
                } else {
                    goBack.style.display = 'none';
                }
 
            })
            // 3. 当我们点击了返回顶部模块,就让窗口滚动的页面的最上方
        goBack.addEventListener('click', function() {
            // 里面的x和y 不跟单位的 直接写数字即可
            // window.scroll(0, 0);
            //调用动画函数: 因为是窗口滚动 所以对象是window
            animate(window, 0);
        });

        // 封装的动画函数
        function animate(obj, target, callback) {
            // console.log(callback);  callback = function() {}  调用的时候 callback()
 
            // 先清除以前的定时器,只保留当前的一个定时器执行
            clearInterval(obj.timer);
            obj.timer = setInterval(function() {
                // 步长值写到定时器的里面
                // 把我们步长值改为整数 不要出现小数的问题
                // var step = Math.ceil((target - obj.offsetLeft) / 10);
                var step = (target - window.pageYOffset) / 10;
                step = step > 0 ? Math.ceil(step) : Math.floor(step);
                if (window.pageYOffset == target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(obj.timer);
                    // 回调函数写到定时器结束里面
                    // if (callback) {
                    //     // 调用函数
                    //     callback();
                    // }
                    callback && callback();
                }
                // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
                // obj.style.left = window.pageYOffset + step + 'px';
                window.scroll(0, window.pageYOffset + step);
            }, 15);
        }
    </script>
</body>
 
</html>

4:按钮-筋斗云

鼠标经过某个小li,筋斗云跟这到当前小li

位置鼠标离开这个小li,筋斗云复原为原来的位置

鼠标点击了某个小li,筋斗云就会留在点击这个小li 的位置

案例分析:

①利用动画函数做动画效果

②原先筋斗云的起始位置是0

③鼠标经过某个小li,把当前小li 的offsetLeft 位置做为目标值即可

④鼠标离开某个小li,就把目标值设为0

⑤如果点击了某个小li,就把li当前的位置存储起来,做为筋斗云的起始位置

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0
        }

        ul {
            list-style: none;
        }

        body {
            background-color: black;
        }

        .c-nav {
            width: 900px;
            height: 42px;
            background: #fff url(images/rss.png) no-repeat right center;
            margin: 100px auto;
            border-radius: 5px;
            position: relative;
        }

        .c-nav ul {
            position: absolute;
        }

        .c-nav li {
            float: left;
            width: 83px;
            text-align: center;
            line-height: 42px;
        }

        .c-nav li a {
            color: #333;
            text-decoration: none;
            display: inline-block;
            height: 42px;
        }

        .c-nav li a:hover {
            color: white;
        }

        .c-nav li.current a {
            color: #0dff1d;
        }

        .cloud {
            position: absolute;
            left: 0;
            top: 0;
            width: 83px;
            height: 42px;
            background: url(images/cloud.gif) no-repeat;
        }
    </style>
    <script src="animate.js"></script>

    <script>
        window.addEventListener('load', function () {
            //1: 获取元素
            var nav = document.querySelector('.c-nav');
            var cloud = document.querySelector('.cloud');
            var lis = document.querySelectoAll('li');

            //声明一个:这个current 做为筋斗云的起始位置
            var current = 0;
            //2: 给所有的li绑定事件
            for (var i = 0; i <= lis.length; i++) {
                // (1) 鼠标经过把当前小li 的位置做为目标值
                lis[i].addEventListener('mouseenter', function () {
                    animate(cloud, this.offsetLeft);
                });

                // (2) 鼠标离开就回到起始的位置 
                lis[i].addEventListener('mouseleave', function () {
                    //current:没有点击,则是0;点击了就是当前小li的位置为起始位置
                    animate(cloud, current);
                })

                //(3):点击事件:当点击某个小li的时候,就把该小li的位置做为起始位置
                lis[i].addEventListener('click', function () {
                    //这个点击是有用,但是鼠标离开就立马返回到默认的当前的图(文字)上去
                    // animate(cloud, this.offsetLeft);

                    //就把该小li的位置做为起始位置
                    current = this.offsetLeft;

                })

            }


        })
    </script>
</head>

<body>
    <div id="c_nav" class="c-nav">
        <!--  -->
        <span class="cloud"></span>
        <ul>
            <li class="current"><a href="#">首页新闻</a></li>
            <li><a href="#">师资力量</a></li>
            <li><a href="#">活动策划</a></li>
            <li><a href="#">企业文化</a></li>
            <li><a href="#">招聘信息</a></li>
            <li><a href="#">公司简介</a></li>
            <li><a href="#">我是佩奇</a></li>
            <li><a href="#">啥是佩奇</a></li>
        </ul>
    </div>
</body>

</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值