JavaScript学习之路(WebAPIs阶段---BOM)

BOM

什么是 BOM ?

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

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

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

在这里插入图片描述

BOM 的构成:

BOM 比 DOM 更大,它包含DOM

在这里插入图片描述

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

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

  2. 它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。

在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert()、prompt() 等。

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

页面加载事件

window.onload = function(){}
或者

window.addEventListener(“load”,function(){}); 【推荐使用】

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

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

注意:

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

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

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

定时器之setTimeout

    // 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()', 3000); // 我们不提倡这个写法

5秒之后 自动关闭广告 案例

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

清除定时器 setTimeout

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

倒计时效果(setInterval)

<body>
    <div>
        <span class="hour">00</span>
        <span class="minute">00</span>
        <span class="second">00</span>
    </div>
    <script>
        // 1. 获取元素
        var hour = document.querySelector('.hour');
        var minute = document.querySelector('.minute');
        var second = document.querySelector('.second');
        var inputTime = +new Date('2021-11-11 20: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>

清除定时器 setInterval

<body>
    <button class="begin">开启定时器</button>
    <button class="stop">停止定时器</button>
    <script>
        var begin = document.querySelector('.begin');
        var stop = document.querySelector('.stop');
        var timer = null; // 全局变量  null是一个空对象
        begin.addEventListener('click', function() {
            timer = setInterval(function() {
                console.log('ni hao ma');

            }, 1000);
        })
        stop.addEventListener('click', function() {
            clearInterval(timer);
        })
    </script>
</body>

发送短信案例

<body>
    <div>
        手机号码:<input type="number" class=""><button>发送</button>
    </div>
    <script>
        var btn = document.querySelector('button');
        var time = 3; // 定义剩下的秒数

        btn.addEventListener('click',function() {
            btn.disabled = true;
            var timer = setInterval(function() {
                if (time == 0) {
                    clearInterval(timer);
                    btn.disabled = false;
                    btn.innerHTML = '发送';
                    time = 3; // 这个3需要重新开始
                } else {
                    btn.innerHTML = '还剩'+ time +'秒才可点击';
                    time--;
                }
            },1000);
        })
    </script>
</body>

this指向问题

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

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

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

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

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

JS执行机制

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事

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

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

同步和异步

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

同步

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

异步

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

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

        // 第一个问题
        // console.log(1);

        // setTimeout(function() {
        //     console.log(3);
        // }, 1000);

        // console.log(2);

        // 2. 第二个问题
        // console.log(1);

        // setTimeout(function() {
        //     console.log(3);
        // }, 0);

        // console.log(2);

        // 3. 第三个问题
        console.log(1);
        document.onclick = function() {
            console.log('click');
        }

        console.log(2);

        setTimeout(function() {
            console.log(3)
        }, 3000)

location 对象

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

URL

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

URL 的一般语法格式为:

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

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

在这里插入图片描述

location 对象的属性:

在这里插入图片描述

重点记住:href和search

点击跳转新的页面:

<body>
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click',function() {
            console.log(location.href);
            location.href = 'http://www.baidu.com';
        })
    </script>
</body>

5秒钟之后跳转页面:

    var div = document.querySelector('div');
    var timer = 5;
    countDo();
    setInterval(countDo,1000);
    function countDo() {   
        if(timer == 0) {
            location.href = 'http://www.baidu.com';
        } else {
            div.innerHTML = '您将在'+ timer +'秒钟之后跳转到首页';
            timer--;
        }
    }

获取URL参数数据

页面1:

    <form action="index.html">
        用户名: <input type="text" name="uname">
        <input type="submit" value="登录">
    </form>
    <!-- form 在登陆是默认是 get 提交 -->

页面2

<body>
    <div></div>
    <script>
        console.log(location.search); // ?uname=andy
        // 1. 先去掉? substr('起始的位置',截取几个字符)
        var params = location.search.substr(1); // uname=andy
        // 2. 利用=把字符分割为数组 split('=');
        var arr = params.split('=');
        console.log(arr); // ["uname","andy"]
        var div = document.querySelector('div');
        // 3. 把数据写入div 中
        div.innerHTML = arr[1] + '欢迎您';
    </script>
</body>

location 对象的方法:

<body>
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click',function() {
            // 记录浏览历史,所以可以实现后退功能
            // location.assign('http://www.baidu.cn');
            // 不记录浏览历史,所以不可以实现后退功能
            // location.replace('http://www.baidu.cn');
            // 重新加载页面,相当于刷新按钮或者 f5 
            location.reload(); //括号里如果加上 true 是强制刷新(ctrl+f5)的意思
        }) 
    </script>
</body>

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 = "";     //电脑
 }

history 对象

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

在这里插入图片描述

页面1

<body>
    <a href="list.html">点击去往列表页</a>
    <button>前进</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click',function() {
            history.forward();
        })
    </script>
</body>

页面2

<body>
    <a href="1116.html">点击去往首页</a>
    <button>后退</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click',function() {
            history.back();
        })
    </script>
</body>

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

PC端网页特效

offset

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

  • 获得元素距离带有定位父元素的位置

  • 获得元素自身的大小(宽度高度)

  • 注意: 返回的数值都不带单位

<style>
        * {
            margin: 0;
            padding: 0;
        }
        .father {
            position: relative;
            width: 200px;
            height: 200px;
            background-color: pink;
            margin: 200px;
        }
        .son {
            width: 100px;
            height: 100px;
            background-color: purple;
            margin: 45px;
        }
        .w {
            width: 100px;
            height: 100px;
            background-color: skyblue;
            margin: 0 auto 200px;
            padding: 10px;
            border: 15px solid red;
        }
    </style>

<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);
        // 3. 返回带有定位的父亲 否则返回的是body
        console.log(son.offsetParent); 
        console.log(son.parentNode); // 返回父亲 是最近一级的定位 亲爸爸 不管父亲有没有定位
    </script>
</body>

offset 与 style 区别

在这里插入图片描述

元素偏移量 offset 系列

    <style>
        .box{
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>

<body>
    <div class="box"></div>
    <script>
        var box = document.querySelector('.box');
        box.addEventListener('mousemove',function(e) {
            var x = e.pageX - this.offsetLeft;
            var y = e.pageY - this.offsetTop;
            this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
        })
    </script>
</body>

拖动模态框

<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>

<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 login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg')
        var link = document.querySelector('#link');
        var title = document.querySelector('#title');
        // 2. 点击弹出层这个链接 link  让mask 和login 显示出来
        var closeBtn = document.querySelector('#closeBtn');
        link.addEventListener('click',function() {
            mask.style.display = 'block';
            login.style.display = 'block';
        })
        // 3. 点击 closeBtn 就隐藏 mask 和 login 
        closeBtn.addEventListener('click',function() {
            login.style.display = 'none';
            mask.style.display = 'none';
        })
        // 4. 开始拖拽
        // (1) 当鼠标按下,就获得鼠标在盒子内的坐标
        title.addEventListener('mousedown',function(e) {
            var x = e.pageX -login.offsetLeft;
            var y = e.pageY -login.offsetTop;
            // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
            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>

显示效果如下:

在这里插入图片描述

元素可视区 client 系列

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

在这里插入图片描述

在这里插入图片描述

<style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border:10px solid red;
        }
    </style>

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

立即执行函数

    // 1. 立即执行函数:不需要调用,立马能够自己执行的函数
    function fn() {
        console.log(1);
    }
    fn();
    // 2. 写法 也可以传递参数进来
    // (function() {})() 或者 (function() {}());
    (function(a) {
        console.log(a);
    })(4); // 第二个小括号可以看作是调用函数
    (function sum(a,b) {
        console.log(a + b);
    } (4,5));

flexible 分析

(function flexible(window, document) {
    // 获取的html 的根元素
    var docEl = document.documentElement
        // dpr 物理像素比
    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() {
        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))

元素滚动 scroll 系列

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

在这里插入图片描述

    <style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
            border: 10px solid red;
            padding: 10px;
            overflow: auto;
        }
    </style>

<body>
    <div>
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
        我是内容
    </div>
    <script>
       // scroll 系列
       var div = document.querySelector('div');
       console.log(div.scrollHeight);
       console.log(div.clientHeight);
       // 滚动事件 当我们滚动条发送变化会触发的事件
       div.addEventListener('scroll',function() {
           console.log(div.scrollTop);
       })
    </script>
</body>

仿淘宝固定侧边栏

    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .header {
            height: 200px;
            background-color: purple;
        }
        .banner {
            height: 600px;
            background-color: blue;
        }
        .main {
            height: 800px;
            background-color: aquamarine;
        }
        .slider-bar {
            position: absolute;
            left: 50%;
            top: 300px;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;
        }
        
        .w {
            width: 1200px;
            margin: 10px auto;
        }
        span {
            display: none;
            position: absolute;
            bottom: 0;
        }
    </style>

<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.offsetTop 就是被卷去头部的大小 一定要写到滚动的外面
       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);
        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';
        }
       })
    </script>
</body>

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

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

  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

三大系列总结

在这里插入图片描述

mouseenter 和mouseover的区别:

mouseenter 鼠标事件

  • 当鼠标移动到元素上时就会触发 mouseenter 事件

  • 类似 mouseover,它们两者之间的差别是
    mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。 mouseenter 只会经过自身盒子触发

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

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

动画函数的封装

    <style>
        div {
            position: absolute;
            width: 200px;
            height: 200px;
            background-color: pink;
        }
        span {
            position: absolute;
            left: 0;
            top: 300px;
            display: block;
            width: 100px;
            height: 100px;
            background-color: red;
        }
    </style>

<body>
    <div>div</div>
    <span>span</span>
    <script>
        // 简单动画函数封装 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');
       // 调用函数
       animate(div,300);
       var span = document.querySelector('span');
       animate(span,500);
    </script>
</body>

动画函数给不同元素记录不同定时器

如果多个元素都使用这个动画函数,每次都要var 声明定时器(每次声明都会在内存中开辟新的空间,比较浪费资源)。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。

核心原理:利用 JS 是一门动态语言,可以很方便的给当前对象添加属性。

修改后代码如下:

    // 简单动画函数封装 obj 目标对象 target 目标位置
    // 给不同的元素指定了不同的定时器
    function animate(obj,target) {
        // 当我们不断地点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
        // 解决方案就是 让我们元素只有一个定时器执行
        // 先清除以前的定时器,只保留当前的一个定时器执行
        clearInterval(obj.timer);
        obj.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');
    var btn = document.querySelector('button');
    // 调用函数
    animate(div,300);
    btn.addEventListener('click',function() {
        animate(span,500);
    })

缓动效果原理

<body>
    <button class="btn500">点击开始前进至500</button>
    <button class="btn800">点击前进至800</button>
    <span>span</span>
    <script>
        // 简单动画函数封装 obj 目标对象 target 目标位置
        // 给不同的元素指定了不同的定时器
        function animate(obj,target,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();
                    }
                }
                // 把每次加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('你好吗');
                span.style.backgroundColor = '#008c8c';
            });
        })
        // 匀速动画就是 盒子是当前的位置 + 固定的值 10
        // 缓动动画就是 盒子当前的位置 + 变化的值
    </script>
</body>

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

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

  1. 单独新建一个JS文件

  2. HTML文件引入 JS 文件

function animate(obj,target,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();
            }
        }
        // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置)/ 10
        obj.style.left = obj.offsetLeft + step + 'px';
    },15);
}

动画函数的使用

    <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>
    <script src="animate.js"></script>

<body>
    <div class="sliderbar">
        <span></span>
        <div class="con">问题反馈</div>
    </div>
    <script>
        var sliderbar = document.querySelector('.sliderbar');
        var con = document.querySelector('.con');
        // 当我们鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧
        // 当我们鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧
        sliderbar.addEventListener('mouseenter',function() {
            // annimate(obj,target,callback);
            animate(con,-160,function() {
                // 当我们动画执行完毕就把 ⬅ 改为 ➡
                sliderbar.children[0].innerHTML = '➡';
            });
        })
        sliderbar.addEventListener('mouseleave',function() {
            animate(con,0,function() {
                // 当我们动画执行完毕就把 ➡ 改为 ⬅
                sliderbar.children[0].innerHTML = '⬅';
            });
        })
    </script>
</body>

筋斗云案例

    <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;
        }
        
        .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 cloud = document.querySelector('.cloud');
            var c_nav = document.querySelector('.c-nav');
            var lis = c_nav.querySelectorAll('li');
            // 2. 给所有的小li绑定事件
            // 这个current 作为筋斗云的起始位置
            var current = 0;
            for(var i = 0; i < lis.length; i++) {
                lis[i].addEventListener('mouseenter',function() {
                    animate(cloud,this.offsetLeft);
                });
                lis[i].addEventListener('mouseleave',function() {
                    animate(cloud,current);
                });
                // 当我们鼠标点击,就把当前位置作为目标值
                lis[i].addEventListener('click',function() {
                    current = this.offsetLeft;
                });
            }
        })
    </script>

<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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值