Javascript面向对象基础 - BOM篇

BOM简介

  • BOM的概念

    • BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
    • BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。
    • BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是Netscape 浏览器标准的一部分。
  • DOM与BOM的区别
    | DOM | BOM |
    | 文档对象模型 | 浏览器对象模型 |
    | 将[文档]当作一个[对象]来看待 | 将[浏览器]当作一个[对象]来看待 |
    | 顶级对象是document | 顶级对象是window |
    | 操作页面元素 | 浏览器窗口的一些对象 |
    | W3C标准规范 | 浏览器厂商各自定义,兼容性差 |

  • BOM的构成

    • BOM 比 DOM 更大,它包含 DOM。
    • window -> document location navigation screen history

顶级对象window

  • 具有的双重角色
    • window是JS访问浏览器窗口的一个接口
    • window是一个全局对象,定义在全局作用域中的变量,函数都会变成window对象的属性和方法
    • 在调用时可以省略window,如alert() prompt()等都属于window对象方法

window对象 页面(窗口)加载事件

  • 第一种方式

    • window.onload = function(){}
      • window.onload 是窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数。
      • 有了window.onload就可以把JS代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数
      • window.onload传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload为准
    • window.addEventListener("load", function(){});
      • 如果使用addEventListener则没有限制
  • 第二种方式

    • document.addEventListener('DOMContentLoaded', function(){})
    • DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。IE9以上才支持
    • 如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。
    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);
    })

window对象 调整窗口大小事件

  • 调整窗口大小事件

    • window.onresize = function(){}
    • window.addEventListener('resize', function(){})
  • window.onresize 是调整窗口大小加载事件, 当触发时就调用的处理函数。

    • 只要窗口大小发生像素变化,就会触发这个事件。
    • 我们经常利用这个事件完成响应式布局。
    • window.innerWidth 当前屏幕的宽度
    <script>
        // 注册页面加载事件
        window.addEventListener('load', function() {
            var div = document.querySelector('div');
        	// 注册调整窗口大小事件
            window.addEventListener('resize', function() {
                // window.innerWidth 获取窗口大小
                console.log('变化了');
                if (window.innerWidth <= 800) {
                    div.style.display = 'none';
                } else {
                    div.style.display = 'block';
                }
            })
        })
    </script>
    <div></div>

window对象 定时器

  • setTimeout() 炸弹定时器
    • 开启定时器
      • window.setTimeout(callback, timer);
        • window可以省略
        • 这个调用函数可以直接写函数,或者写函数名,或者采取字符串'函数名()'三种方式,第三种不推荐
        • 延迟的毫秒数省略默认是0,如果写,必须是毫秒数
        • 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
    • 停止定时器
      • window.clearTimeout(timeoutID)
      • 此方法取消了先前通过调用setTimeout()建立的定时器
      • window可以省略
      • 里面的参数就是定时器的标识符
    // 回调函数是一个匿名函数
    setTimeout(function() {
            console.log('时间到了');
    }, 10000);
    function callback() {
        console.log('爆炸了');
    }
    // 回调函数是一个有名函数
    var timer1 = setTimeout(callback, 20000);
    var timer2 = setTimeout(callback, 30000);
    <button>点击停止定时器</button>
    <script>
        var btn = document.querySelector('button');
		// 开启定时器
        var timer = setTimeout(function() {
            console.log('爆炸了');
        }, 5000);
		// 给按钮注册单击事件
        btn.addEventListener('click', function() {
            // 停止定时器
            clearTimeout(timer);
        })
    </script>
  // 多次定时
  for (var i = 1; i <= 5; i++) {
    setTimeout(function(i) {
      return function(){
        console.log(i);
      }
    }(i), i*1000);
  }
  console.log(i);
    // 5秒定时关闭
    var div = document.createElement('div');
    document.body.appendChild(div);
    var styles = [
        'width:50px;',
        'height:50px;',
        'background:bisque;'
    ];
    div.style = styles.join('');
    // 开启定时器
    setTimeout(function() {
        div.style.display = 'none';
    }, 5000);
  • setInterval() 闹钟定时器

    • 开启定时器
      • window.setInterval(callback, [timer]) 此方法重复调用一个函数,每隔固定时间调用一次
      • window可以省略
      • 这个调用函数可以直接写函数,或者写函数名,或者采取字符串'函数名()'三种方式
      • 延迟的毫秒数省略默认是0,如果写,必须是毫秒数
      • 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
      • 第一次执行也是间隔毫秒数之后执行
    • 停止定时器
      • clearInterval() 此方法取消了先前通过调用setInterval()建立的定时器
      • window可以省略
      • 里面的参数就是定时器的标识符
  • 倒计时

    <div>
        <span class="day">1</span>
        <span class="hour">1</span>
        <span class="minute">2</span>
        <span class="second">3</span>
    </div>
    <script>
        // 1. 获取元素(时分秒盒子) 
        var day = document.querySelector('.day'); // 小时的黑色盒子
        var hour = document.querySelector('.hour'); // 小时的黑色盒子
        var minute = document.querySelector('.minute'); // 分钟的黑色盒子
        var second = document.querySelector('.second'); // 秒数的黑色盒子
        var inputTime = +new Date('2020-10-1 18:00:00'); // 返回的是用户输入时间总的毫秒数
        countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白 
        // 2. 开启定时器
        setInterval(countDown, 1000);
        function countDown() {
            var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
            var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数 
            var d = parseInt(times / 60 / 60 / 24); 
            d = d < 10 ? '0' + d : d;
            day.innerHTML = '还剩'+d+'天 | ';
            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>
  • 发送短信倒计时
    • 点击按钮后,该按钮60秒之内不能再次点击,防止重复发送短信。
    手机号码: <input type="number"> <button>发送</button>
    <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 = '发送';
                } else {
                    btn.innerHTML = '还剩下' + time + '秒';
                    time--;
                }
            }, 1000);
        });
    </script>

window对象 this指向问题

  • this指向问题

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

    • 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
    • 方法调用中谁调用this指向谁
    • 构造函数中this指向构造函数的实例
    <button>点击</button>
    <script>
        // this 指向问题 一般情况下this的最终指向的是那个调用它的对象
        // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
        console.log(this);
        function fn() {
            console.log(this);
        }
        window.fn();
        window.setTimeout(function() {
            console.log(this);
        }, 1000);
        // 2. 方法调用中谁调用this指向谁
        var o = {
            sayHi: function() {
                console.log(this); // this指向的是 o 这个对象
            }
        }
        o.sayHi();
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
                console.log(this); // 事件处理函数中的this指向的是btn这个按钮对象
            })
        // 3. 构造函数中this指向构造函数的实例
        function Fun() {
            console.log(this); // this 指向的是fun 实例对象
        }
        var fun = new Fun();
    </script>

location对象

  • 概念

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

    • 统一资源定位符是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
    • URL的一般语法格式为
    • protocol"//host[:port]/path/[?query]#fragment
      • http://www.baidu.com/index.html?name=andy&age=18#link
      • protocol 通信协议,常用的http ftp maito
      • host 主机(域名)
      • port 端口号 可选,省略时使用默认端口号 如HTTP的端口号为80
      • path 路径
      • query 参数 以键值对的形式 通过&符号分隔开来
      • fragment 片段 #后面的内容常见于链接 锚点
  • location对象的属性

    • location.href 获取或者设置整个url
    • location.host 返回主机(域名)
    • location.post 返回端口号 如果未写,返回空字符串
    • location.pathname 返回路径
    • location.seach 返回参数
    • location.hash 返回片段 #后面内容 常见于链接 锚点
  • 5分钟自动跳转页面

    <button>点击</button>
    <div></div>
    <script>
        var btn = document.querySelector('button');
        var div = document.querySelector('div');
        btn.addEventListener('click', function() {
            // console.log(location.href);
            location.href = 'http://www.itcast.cn';
        })
        var timer = 5;
        setInterval(function() {
            if (timer == 0) {
                location.href = 'http://www.itcast.cn';
            } else {
                div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页';
                timer--;
            }
        }, 1000);
    </script>
  • 获取URL参数
    <div></div>
	<script>
        console.log(location.search); // ?uname=andy
        // 1.先去掉?  substr('起始的位置',截取几个字符);
        var params = location.search.substr(1); // uname=andy
        console.log(params);
        // 2. 利用=把字符串分割为数组 split('=');
        var arr = params.split('=');
        console.log(arr); // ["uname", "ANDY"]
        var div = document.querySelector('div');
        // 3.把数据写入div中
        div.innerHTML = arr[1] + '欢迎您';
    </script>
  • location对象的常见方法
    • location.assign() 跟href一样,可以跳转页面(也称为重定向页面)
    • location.replace() 替换当前页面,因为不记录历史,所以不能后退页面
    • location.reload() 重新加载页面,相当于刷新页面,如果参数为true,强制刷新ctrl+F5
    <button>点击</button>
    <script>
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
            // 记录浏览历史,所以可以实现后退功能
            // location.assign('http://www.itcast.cn');
            // 不记录浏览历史,所以不可以实现后退功能
            // location.replace('http://www.itcast.cn');
            location.reload(true);
        })
    </script>
  • 概念

    • 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 = "";     //填写电脑端地址
 }
  • navigator对象的属性与方法
    • navigator.cookieEnabled 是否启用cookie
    • navigator.userAgent 用户代理

history对象

  • 概念

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

    • history.back() 后退页面
    • history.forward() 前进页面
    • history.go() 参数为1,前进页面,参数为-1,后退页面

screen对象

  • 概念

    • screen对象用于返回当前渲染窗口中与屏幕相关的属性信息
    • 需要注意的是,每个浏览器中的screen对象都包含不同的属性
  • screen对象的属性

    • height 返回整个屏幕的高
    • width 返回整个屏幕的宽
    • availHeight 返回浏览器窗口在屏幕上可占用的垂直空间
    • availWidth 返回浏览器窗口在屏幕上可占用的水平空间
    • colorDepth 返回屏幕的颜色深度
    • pixelDepth 返回屏幕的位深度/色彩深度

JS执行机制

  • 引入:以下代码执行的结果是什么?
 console.log(1);
 setTimeout(function () {
     console.log(3);
 }, 0);
 console.log(2);
  • JS 是单线程

    • JavaScript语言的一大特点就是单线程,也就是说,同一个时间点只能做一件事
    • 单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
    • 这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
  • 同步任务和异步任务

    • 为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,
    • 允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制。
    • 于是,JS 中出现了同步任务异步任务
  • 同步任务

    • 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
    • 前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
    • 比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。
    • 同步任务都在主线程上执行,形成一个执行线
  • 异步任务

    • 不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。
    • 你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。
    • 比如做饭的异步做法,我们在烧水的同时,利用这10分钟,去切菜,炒菜。
    • JS的异步都是通过回调函数实现的
    • 一般而言,异步任务有以下三种类型
      • 普通事件,如click resize等
      • 资源加载,如load error等
      • 定时器,包括setInterval setTimeout等
    • 异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
  • JS执行机制(事件循环)

    • 先执行栈中的同步任务
    • 异步任务(回调函数)放入任务队列中
    • 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务
    • 于是被读取的异步任务结束等待状态,进入执行栈,开始执行
    • 由于主线程不断的重复获得任务,执行任务,再获得任务,在执行,所以这种机制被称为事件循环

元素偏移量 offset 系列

  • offset概述

    • 使用 offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
      • 获得元素距离带有定位父元素的位置
      • 获得元素自身的大小(宽度高度)
      • 注意:返回的数值都不带单位
  • offset系列的属性

    • element.offsetParent 返回作为该元素带有定位的父级元素 如果父级都没有定位ze返回body
    • element.offsetTop 返回元素相对带有定位父元素上方的偏移
    • element.offsetLeft 返回元素相对带有定位父元素左边框的偏移
    • element.offsetWidth 返回自身包括Padding、边框、内容区的宽度,返回数值不带单位
    • element.offsetHeight 返回自身包括Padding、边框、内容区的高度,返回数值不带单位
  • offset 与 style 区别

    • offset
      • offset 可以得到任意样式表中的样式值
      • offset 系列获得的数值是没有单位的
      • offsetWidth 包含padding + border + width
      • offsetWidth 等属性是只读属性,只能获取不能赋值
      • 所以,我们想要获取元素大小位置,用offset更合适
    • style
      • style 只能得到行内样式表中的样式值
      • style.width 获得的是带有单位的字符串
      • style.width 获得不包含padding和border的值
      • style.width 是可读写属性,可以获取也可以赋值
      • 所以,我们想要给元素更改值,则需要用style改变
  • 因为平时我们都是给元素注册触摸事件,所以重点记住 targetTocuhes

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

    • 我们在盒子内点击,想要得到鼠标距离盒子左右的距离。
    • 首先得到鼠标在页面中的坐标(e.pageX, e.pageY)
    • 其次得到盒子在页面中的距离 ( box.offsetLeft, box.offsetTop)
    • 用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标
    • 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动
  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;
  })
  • 案例:模态框拖拽

    • 弹出框,我们也称为模态框。
    • 点击弹出层,会弹出模态框, 并且显示灰色半透明的遮挡层。
    • 点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层。
    • 鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动。
    • 鼠标松开,可以停止拖动模态框移动
  • 案例分析

    • 点击弹出层, 模态框和遮挡层就会显示出来 display:block;
    • 点击关闭按钮,模态框和遮挡层就会隐藏起来 display:none;
    • 在页面中拖拽的原理:鼠标按下并且移动, 之后松开鼠标
    • 触发事件是鼠标按下mousedown,鼠标移动mousemove 鼠标松开 mouseup
    • 拖拽过程:  鼠标移动过程中,获得最新的值赋值给模态框的left和top值,这样模态框可以跟着鼠标走了
    • 鼠标按下触发的事件源是最上面一行,就是  id 为 title
    • 鼠标的坐标减去 鼠标在盒子内的坐标, 才是模态框真正的位置。
    • 鼠标按下,我们要得到鼠标在盒子的坐标。
    • 鼠标移动,就让模态框的坐标  设置为  :鼠标坐标 减去盒子坐标即可,注意移动事件写到按下事件里面。
    • 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
        // 1. 获取元素
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var closeBtn = document.querySelector('#closeBtn');
        var title = document.querySelector('#title');
        // 2. 点击弹出层这个链接 link  让mask 和login 显示出来
        link.addEventListener('click', function() {
                mask.style.display = 'block';
                login.style.display = 'block';
            })
            // 3. 点击 closeBtn 就隐藏 mask 和 login 
        closeBtn.addEventListener('click', function() {
                mask.style.display = 'none';
                login.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);
            })
        })
  • 案例:仿京东放大镜

    • 整个案例可以分为三个功能模块
    • 鼠标经过小图片盒子,黄色的遮挡层和大图片盒子显示,离开隐藏2个盒子功能
    • 黄色的遮挡层跟随鼠标功能。
    • 移动黄色遮挡层,大图片跟随移动功能。
  • 案例分析

    • 黄色的遮挡层跟随鼠标功能。
    • 把鼠标坐标给遮挡层不合适。因为遮挡层坐标以父盒子为准。
    • 首先是获得鼠标在盒子的坐标。
    • 之后把数值给遮挡层做为left 和top值。
    • 此时用到鼠标移动事件,但是还是在小图片盒子内移动。
    • 发现,遮挡层位置不对,需要再减去盒子自身高度和宽度的一半。
    • 遮挡层不能超出小图片盒子范围。
    • 如果小于零,就把坐标设置为0
    • 如果大于遮挡层最大的移动距离,就把坐标设置为最大的移动距离
    • 遮挡层的最大移动距离:小图片盒子宽度 减去 遮挡层盒子宽度
window.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. 鼠标移动的时候,让黄色的盒子跟着鼠标来走
    preview_img.addEventListener('mousemove', function(e) {
        // (1). 先计算出鼠标在盒子内的坐标
        var x = e.pageX - this.offsetLeft;
        var y = e.pageY - this.offsetTop;
        // console.log(x, y);
        // (2) 减去盒子高度 300的一半 是 150 就是我们mask 的最终 left 和top值了
        // (3) 我们mask 移动的距离
        var maskX = x - mask.offsetWidth / 2;
        var maskY = y - mask.offsetHeight / 2;
        // (4) 如果x 坐标小于了0 就让他停在0 的位置
        // 遮挡层的最大移动距离
        var maskMax = preview_img.offsetWidth - mask.offsetWidth;
        if (maskX <= 0) {
            maskX = 0;
        } else if (maskX >= maskMax) {
            maskX = maskMax;
        }
        if (maskY <= 0) {
            maskY = 0;
        } else if (maskY >= maskMax) {
            maskY = maskMax;
        }
        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 bigY = maskY * bigMax / maskMax;
        bigIMg.style.left = -bigX + 'px';
        bigIMg.style.top = -bigY + 'px';
    })
})

元素可视区 client 系列

  • client概述

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

    • element.clientTop 返回元素上边框的大小
    • element.clientLeft 返回元素左边框的大小
    • element.clientWidth 返回自身包括padding 内容区的宽度,不含边框,返回数值不带单位
    • element.clientHeight 返回自身包括padding 内容区的高度,不含边框,返回数值不带单位

元素滚动 scroll 系列

  • scroll 概述

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

    • element.scrollTop 返回被卷去的上侧距离,返回数值不带单位
    • element.scrollLeft 返回被卷去的左侧距离,返回数值不带单位
    • element.scrollWidth 返回自身实际的宽度,不含边框,返回数值不带单位
    • element.scrollHeight 返回自身实际的高度,不含边框,返回数值不带单位
  • 页面被卷去的头部

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

    • 原先侧边栏是绝对定位
    • 当页面滚动到一定位置,侧边栏改为固定定位
    • 页面继续滚动,会让 返回顶部显示出来
  • 案例分析

    • 需要用到页面滚动事件 scroll  因为是页面滚动,所以事件源是document
    • 滚动到某个位置,就是判断页面被卷去的上部值。
    • 页面被卷去的头部:可以通过window.pageYOffset获得如果是被卷去的左侧window.pageXOffset
    • 注意,元素被卷去的头部是element.scrollTop, 如果是页面被卷去的头部 则是 window.pageYOffset
    • 其实这个值 可以通过盒子的 offsetTop可以得到,如果大于等于这个值,就可以让盒子固定定位了
  //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';
      }

  })
  • 页面被卷去的头部兼容性解决方案
    • 需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
    • 声明了 DTD,使用 document.documentElement.scrollTop
    • 未声明 DTD,使用  document.body.scrollTop
    • 新方法 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
    };
 } 

 var left = getScroll().left;
 var top = getScroll().top;

三大系列总结

  • 三大系列属性对比

    • element.offsetWidth 返回自身包括padding 边框 内容区的宽度,返回值不带单位
    • element.clientWidth 返回自身包括padding 内容区的宽度,不含边框,返回值不带单位
    • element.scrollWidth 返回自身实际的宽度,不含边框,返回值不带单位
  • 主要应用

    • offset系列 经常用于获得元素位置 offsetLeft  offsetTop
    • client经常用于获取元素大小 clientWidth clientHeight
    • scroll 经常用于获取滚动距离 scrollTop  scrollLeft
    • 注意页面滚动的距离通过 window.pageXOffset 获得
  • mouseentermouseover的区别

    • 当鼠标移动到元素上时就会触发mouseenter事件
    • 类似mouseover,它们两者之间的差别如下
    • mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter只会经过自身盒子触发
    • 之所以这样,就是因为mouseenter不会冒泡
    • mouseenter搭配鼠标离开mouseleave同样不会冒泡
posted @ 2020-08-25 08:24  wing1377  阅读(168)  评论(0编辑  收藏  举报