前端之浏览器对象模型(BOM)

本文详细介绍了浏览器对象模型BOM,包括页面加载事件、URL解析、location对象、history对象、navigator对象以及定时器的使用。重点讨论了如何利用BOM进行页面跳转、操作URL和实现页面动画、倒计时等功能。同时,探讨了offset、client、scroll系列方法在获取元素位置和浏览器可视区大小中的应用,并提到了兼容性问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.BOM

概念: BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM由多个对象组成,其中代表浏览器窗口的Window对象是BOM的顶层对象,其他对象都是该对象的子对象。

通俗理解: 把浏览器当做对象,通过访问对象的属性,实现操作浏览器的一组方法

2. 页面加载事件

2.1 load事件

window.onload = function () {
  
  // 当页面加载完所有内容(包括图像、脚本文件、CSS 文件等)执行
}

2.2 unload事件

window.onunload = function () {
  // 当用户退出页面时执行(关闭页面)
}

小结:

window.onload事件 是页面所有资源加载完成时触发

window.onunload事件 是用户退出页面时触发

3.location对象

location 相当于浏览器地址栏的抽象, 通过window.location可以访问到,window可以忽略不写

我们学习location对象,目的是为了操作地址栏里面的url地址

3.1 URL

3.1.1 什么是url

概念:统一资源定位符 (Uniform Resource Locator, URL)

通俗理解: 互联网中的地址

3.1.2 URL的组成

  • scheme:通信协议

    常用的http,ftp,maito等

  • host:主机 (找计算机)

    服务器(计算机)域名系统 (DNS) 主机名或 IP 地址。

  • port:端口号 (找软件)

    整数,可选,省略时使用方案的默认端口,如http的默认端口为80。

  • path:路径

    由零或多个'/'符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。

  • query:查询

    可选,用于给动态网页传递参数,可有多个参数,用'&'符号隔开,每个参数的名和值用'='符号隔开。

例如:name=zs

fragment: 信息片断

字符串,锚点.

3.2 location有哪些成员?

成员: 属性和方法又叫做成员

  • href 返回地址栏的整个url,设置值的时候,也可以起到跳转页面的作用

  • hash 返回地址栏url的fragment

  • host 返回地址栏url的主机名

  • search 返回地址栏url的键值对参数(query)

  • reload() 设置页面刷新

                 语法: location.reload([boolean])

参数是一个布尔值,不传参数则默认是false. 普通刷新,可能会从缓存拿数据

传true的话,是强制刷新.强制浏览器去服务器获取数据

 

 

  • assign() 设置页面跳转,记录历史

                 语法: location.assign('url地址')

  • replace() 设置页面跳转,不记录历史

                 语法:location.replace('url地址')

  • href属性赋值,也可以是想页面跳转的新效果,跟assign类似
 location.href = 'http://www.itheima.com';

小结:

  • location对象代表浏览器的地址栏.

  • 学习location的目标主要是为了操作地址栏的url地址

  • 网络中的地址我们称为url

4.history对象

  • back() 返回上一个页面

    语法: history.back();

  • forward() 前进到下一个页面

    语法: history.forward();

  • go(1/-1) 前进/ 返回

    语法: history.go(number);

    正数是前进,负数是后退.

    history.go(1); //前进一步
    history.go(2); //前进两步
    history.go(-3); //后退三步

5.navigator对象

  • userAgent 返回识别客户端设备和浏览器的字符串

    语法: navigator.userAgent

6. 定时器

6.1 设置定时器

6.1.1 setTimeout()

作用: 到达间隔时间之后,只调用一次回调函数

语法: window.setTimeout(回调函数, 间隔时间)

  • window可以省略

  • 间隔时间以毫秒为单位

  • 返回这个定时器的标识符,是数字类型

// 创建一个定时器,1秒后执行
// timerId指向这个定时器的标识符
var timerId = setTimeout(function () {
  console.log('Hello World');
}, 1000);

6.1.2 setInterval()

作用: 每隔一个间隔时间,就调用一次回调函数

语法: window.setInterval(回调函数, 间隔时间)

  • window可以省略

  • 间隔时间以毫秒为单位

  • 返回这个定时器的唯一标示符,是数字类型

// 创建一个定时器,每隔1秒调用一次
//timerId 指向这个定时器的标识符
var timerId = setInterval(function () {
  var date = new Date();
  console.log(date.toLocaleTimeString());
}, 1000);

6.2 清除定时器

6.2.1 clearTimeout()

作用: 清除以setTimeout方法设置的定时器

语法: widnow.clearTimeout(定时器的标识符) window可以忽略

6.2.2 clearInterval()

作用: 清除以setInterval方法设置的定时器

语法: widnow.clearInterval(定时器的标识符) window可以忽略

小结:

  • 设置定时器 setTimeout 和 setInterval

  • 清除定时器 clearTimeout 和 clearInterval

简单动画案例

<!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>
        *{
            margin:0;
            padding:0;
        }
        #box{
            width:100px;
            height:100px;
            background-color:red;
            position:absolute;
        }
    </style>
</head>
<body>
    <button id="btn">点击盒子移动到400</button>
    <div id="box"></div>
</body>
</html>
<script>
    
    //需求: 点击按钮,让box从左往右移动400px
//    1. 获取元素 btn, box
        var btn = document.getElementById('btn');
        var box = document.getElementById('box');
        var pos = 400; //最终位置
        var timeid; //一定要写在外面,用于存储定时器的id
//    2. 给btn注册点击事件
        btn.onclick = function(){
            
                //为了避免添加多个定时器的问题,所以每一次设置新的定时器之前,要先把原来的 清除掉
            if(timeid){
                clearInterval(timeid);
            }
            
            //    3. 在事件处理函数中让box动起来
               //如果要让box自己动起来,需要把代码放到定时器里执行
            timeid = setInterval(function(){
                //     3.1 先获取当前的位置在哪
                var current =  box.offsetLeft;
                //     3.2 在当前位置的基础上加几个像素
                var target = current + 7;
                box.style.left = target + 'px';
                
                //3.3 判断一下是否到达了目标位置,如果到达了目标位置,就清除定时器
                if(target >= pos){
                    clearInterval(timeid);
                    //如果超出了目标就直接拉回去(直接设置最终位置)
                    box.style.left = pos + 'px';
                    console.log(box.offsetLeft);
                }
                
            }, 15);
        }

</script>

倒计时案例:

<!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 type="text/css">
    .time-item {
      width: 430px;
      height: 45px;
      margin: 0 auto;
    }
    
    .time-item strong {
      background: orange;
      color: #fff;
      line-height: 49px;
      font-size: 36px;
      font-family: Arial;
      padding: 0 10px;
      margin-right: 10px;
      border-radius: 5px;
      box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
    }
    
    .time-item > span {
      float: left;
      line-height: 49px;
      color: orange;
      font-size: 32px;
      margin: 0 10px;
      font-family: Arial, Helvetica, sans-serif;
    }
    
    .title {
      width: 260px;
      height: 50px;
      margin: 200px auto 50px auto;
    }
  </style>
</head>
<body>
    <h1 class="title">距离毕业,还有</h1>

    <div class="time-item">
            <span>
                <span id="day">00</span>天</span>
      <strong>
        <span id="hour">00</span>时</strong>
      <strong>
        <span id="minute">00</span>分</strong>
      <strong>
        <span id="second">00</span>秒</strong>
    </div>
    <script>

    // 需求:每隔一秒钟,就展示距离目标还差多长时间
   //  获取元素:
       var d = document.getElementById('day');
       var h = document.getElementById('hour');
       var m = document.getElementById('minute');
       var s = document.getElementById('second');
  

    // 5.让1-4步每隔一秒钟执行一次
    fn();
    setInterval(fn,1000);
    function fn() {

    // 1.获取到当前时间
         var date = +new Date();
    // 2.获取到目标事件
       var target = +new Date('2020-04-10 00:00:00');
    // 3.计算当前和目标的事件差
       var time = target - date;    //毫秒
       time /= 1000;    //把毫秒转换成秒
    // 4.根据时间差,计算还差多少天,小时,分,秒
     day = Math.floor(time/60/60/24);
     hour = Math.floor(time/60/60%24);
     minute = Math.floor(time/60 %60);
     second = Math.floor(time % 60);

    //  给元素的文本重新赋值
      d.innerText = day;
      h.innerText = hour;
      m.innerText = minute;
      s.innerText = second;
    }

    // 计算时间差的代码
    // 先获得总共还有多少秒,然后计算天,小时,分,秒
    //  day = Math.floor(interval/60/60/24);
    //  hour = Math.floor(interval/60/60%24);
    //  minute = Math.floor(interval/60 %60);
    //  second = Math.floor(interval % 60);
     
    </script> 
</body>
</html>

6. 课后综合练习

钟表案例

7. 扩展内容@

7.1 name 和top 的特殊性:

​ name 和 top 是window 对象本身存在的属性

​ name 是字符串,给name赋值为其他类型,也会转换成字符串

​ top 是只读的属性,指向window对象,不可写

注意:   在全局申明变量,不要使用name 或者top

//  name top
// console.log(window.name); //默认是一个空的字符串
// console.log(window.top); //指向window本身
  
//  var a = 1;// 在全局申明一个变量,其实就相当于给window增加了一个属性
//  window.a = 1;
//  console.log(window.a);
  
 var name = 1;
 var name = false; //如果全局有name变量,不管你赋值的是什么数据类型,都会转成字符串
 var top = 1; //如果全局有top变量,不管你赋值是什么,top永远指向window
 console.log(name);
 console.log(top);
  
//  结论: 在全局,不要使用name和top

8. 特效

8.1 offset系列

  • offsetParent 用于获取定位的父级元素

  • offsetLeft 距离定位父元素的左偏移量

  • offsetTop 距离定位父元素的上偏移量

  • offsetWidth 当前元素的宽度           content+padding+border

  • offsetHeight 当前元素的高度          content+padding+border

以下操作均是错误的:

son.offsetWidth = 300;
son.offsetWidth = '300px';
son.offsetLeft = 200;
son.offsetLeft = '200px';
son.offsetParent = document.body;
console.log(son.offsetParent);
//结论: offset系列不能赋值,只能获取

小问题:

   offsetParent和parentNode的区别?

  • offsetParent 返回的是离自己最近的定位父元素

  • parentNode 返回的是直接父元素

8.2. client系列

  • clientWidth 元素可视区的宽度                    content+padding

  • clientHeight 元素可视区的高度                   content+padding

client系列也不可以赋值: 

son.clientWidth = 300;
son.clientWidth = '300px';
//  client系列同样也不可以赋值

8.3. scroll系列

  • scrollLeft 元素中内容左侧滚动出去的距离

  • scrollTop 元素中内容顶部滚动出去的距离

  • scrollWidth 元素中内容的宽度

  • scrollHeight 元素中内容的高度

scroll事件 ,监听滚动条滚动的事件

 far.onscroll = function(){
//  console.log(1);
   console.log('left :' + far.scrollLeft);
   console.log('top :' + far.scrollTop);
 }

 scrollLeft 和 scrollTop 可以赋值,并且不需要写单位

//  far.scrollWidth = 600;
//  far.scrollWidth = '600px';
//  console.log(far.scrollWidth);
    far.scrollLeft  = 100;
    far.scrollTop  = 100;
    console.log(far.scrollLeft);
    console.log(far.scrollTop);
  //结论: scrollLeft 和 scrollTop 可以赋值,并且不需要写单位

小结:

  • offset, client, scroll系列返回的都是数字类型(Number)

  • 返回的值是所有样式渲染到页面上的最终结果

8.4. 获取浏览器可视区的大小(不可以被赋值)

  • window.innerWidth 浏览器可视区的宽度

  • window.innerHeight 浏览器可视区的高度

8.5.获取页面滚动出去的距离(也不可以被赋值)

  • window.pageYOffset 顶部滚动出去的距离

  • window.pageXOffset 左侧滚动出去的距离

9. 扩展内容@

9.1 client系列其他

  • clientLeft 返回元素左边框的宽度

  • clientTop 返回元素上边框的宽度

9.2 window.innerWidth 和 window.innerHeight的兼容问题

ie8及以下不支持

ie8及以下的浏览器中:

window.innerWidth ===> document.docuementELement.clientWidth

window.innerHeight ===> document.docuementELement.clientHeight

9.3 window.pageXOffset 和window.pageYOffset 的兼容问题

ie8及以下不支持

ie8及以下的浏览器中:

window.pageXOffset ===> document.docuementELement.scrollLeft

window.pageYOffset ===> document.docuementELement.scrollTop

拖拽案例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    
    .nav {
      height: 30px;
      background: #036663;
      border-bottom: 1px solid #369;
      line-height: 30px;
      padding-left: 30px;
    }
    
    .nav a {
      color: #fff;
      text-align: center;
      font-size: 14px;
      text-decoration: none;
      
    }
    
    .d-box {
      width: 400px;
      height: 300px;
      border: 5px solid #eee;
      box-shadow: 2px 2px 2px 2px #666;
      position: absolute;
      top: 40%;
      left: 40%;
      background-color: white;
      
      /* 不让文字被选中 */
      -webkit-user-select:none;
      -moz-user-select:none;
      -ms-user-select:none;
      user-select:none;
    }
    
    .hd {
      width: 100%;
      height: 25px;
      background-color: #7c9299;
      border-bottom: 1px solid #369;
      line-height: 25px;
      color: white;
      cursor: move; /*将鼠标编程移动标示*/
    }
    
    #box_close {
      float: right;
      cursor: pointer;
    }
  </style>
</head>
<body>
<div class="nav">
  <a href="javascript:void(0);" id="register">注册信息</a>
</div>
<div class="d-box" id="d_box">
  <div class="hd" id="drop">注册信息 (可以拖拽)
    <span id="box_close">【关闭】</span>
  </div>
  <div class="bd"></div>
</div>
</body>
</html>
<script>

   //需求: 鼠标在drop上按下的时候,鼠标移动d-box跟着移动
//  1. 获取元素 drop d-box
    var drop = document.getElementById('drop');
    var d_box = document.getElementById('d_box');
//  2. 给drop注册鼠标按下事件  mousedown
    drop.onmousedown = function(e){
//      4.2 获取鼠标按下的时候的坐标
        var downX = e.clientX;
        var downY = e.clientY;
      
        //4.4 获取鼠标按下的一瞬间,d_box所处的位置
        var posX = d_box.offsetLeft;
        var posY = d_box.offsetTop;
      
      //  3. 在按下的事件中注册鼠标移动的事件 mousemove
      document.onmousemove = function(e){
        console.log(1);
        //  4. 在鼠标移动的事件处理函数中,给d-box设置位置
//        4.1 获取到鼠标浏览器可视区的坐标
          var x = e.clientX;
          var y = e.clientY;
        
//        4.3 计算鼠标移动了多少  鼠标移动的坐标 - 鼠标按下的坐标
          var instanceX = x - downX;
          var instanceY = y - downY;
        
//        4.5 计算d_box移动时,应该处于的位置  按下时的初识位置 + 鼠标移动的距离
          var targetX = posX + instanceX;
          var targetY = posY + instanceY;
        
          d_box.style.left = targetX + 'px';
          d_box.style.top = targetY + 'px';
      }
    }
    
    //5.鼠标松开,d_box不在移动  mouseup  
    document.onmouseup = function(){
      document.onmousemove = null;
    }
       
</script>

弹出层拖拽案例:

<!DOCTYPE html>
<html>

<head lang="en">
  <meta charset="UTF-8">
  <title></title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .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 {
      width: 512px;
      height: 280px;
      position: absolute;
      border: #ebebeb solid 1px;
      left: 50%;
      right: 50%;
      background: #ffffff;
      box-shadow: 0px 0px 20px #ddd;
      z-index: 9999;
      margin-left: -256px;
      margin-top: 140px;
      display: none;
    }

    .login-title {
      width: 100%;
      margin: 10px 0px 0px 0px;
      text-align: center;
      line-height: 40px;
      height: 40px;
      font-size: 18px;
      position: relative;
      cursor: move;
      -moz-user-select: none;
      /*火狐*/
      -webkit-user-select: none;
      /*webkit浏览器*/
      -ms-user-select: none;
      /*IE10*/
      -khtml-user-select: none;
      /*早期浏览器*/
      user-select: none;
    }

    .login-input-content {
      margin-top: 20px;
      -moz-user-select: none;
      /*火狐*/
      -webkit-user-select: none;
      /*webkit浏览器*/
      -ms-user-select: none;
      /*IE10*/
      -khtml-user-select: none;
      /*早期浏览器*/
      user-select: none;
    }

    .login-button {
      width: 50%;
      margin: 30px auto 0px auto;
      line-height: 40px;
      font-size: 14px;
      border: #ebebeb 1px solid;
      text-align: center;
      -moz-user-select: none;
      /*火狐*/
      -webkit-user-select: none;
      /*webkit浏览器*/
      -ms-user-select: none;
      /*IE10*/
      -khtml-user-select: none;
      /*早期浏览器*/
      user-select: none;
    }

    .login-bg {
      width: 100%;
      height: 100%;
      position: fixed;
      top: 0px;
      left: 0px;
      background: #000000;
      filter: alpha(opacity=30);
      -moz-opacity: 0.3;
      -khtml-opacity: 0.3;
      opacity: 0.3;
      display: none;
    }

    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的href属性值中.协议名是javascript. 那么点击a标签的时候,就会执行:后面的代码-->
    <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>
</body>
</html>
<script>
  
  // 获取元素
  var link = document.getElementById('link'); //点击的文字
  var bg = document.getElementById('bg'); //遮盖层
  var login = document.getElementById('login'); //登录框
  var title = document.getElementById('title'); //登录框的标题
  var closeBtn = document.getElementById('closeBtn');
//  需求:
//      1.点击文字,展示遮盖层和登录框
//        1.1获取元素
//        1.2 给link注册点击事件
        link.onclick = function(){
          //1.3 在事件处理函数中,让login和bg展示出来
          login.style.display = 'block';
          bg.style.display = 'block';
        }
//      2. 鼠标在登录框的头部按下时,可以拖动
//      2.1 给title注册mousedown事件
        title.onmousedown = function(e){
//          2.4 获取鼠标在title上按下的坐标
          var downX = e.clientX;
          var downY = e.clientY;
          
//          2.6 获取鼠标按下时,login的初始位置
          var posX = login.offsetLeft;
          var posY = login.offsetTop;
          
          // 2.2 在mousedown中给document注册mousemove事件
          document.onmousemove = function(e){
            //2.3 获取鼠标移动的坐标
            var x = e.clientX;
            var y = e.clientY;
            
//            2.5 计算鼠标移动了多少  移动的坐标- 按下的坐标
            var instanceX = x - downX;
            var instanceY = y - downY;
            
            //2.7 计算login最终处于的位置   鼠标移动的距离 + login初始的位置
            var targetX = instanceX + posX;
            var targetY = instanceY + posY;
  
            // 3. 限制登录框的位置
//              3.1 获取最小距离和最大距离
                var maxX = window.innerWidth - login.offsetWidth -21; //可视区的宽度 - login的宽度
                var maxY = window.innerHeight - login.offsetHeight; //可视区的宽度 - login的宽度
//              3.2 判断target是否小于最小距离或者大于最大距离
                if(targetX < 0){
                  targetX = 0;
                }
                if(targetY < 21){
                  targetY = 21;
                }

                if(targetX > maxX){
                  targetX = maxX;
                }

                if(targetY > maxY){
                  targetY = maxY;
                }
            //由于target算出来的就是login应该处于的位置,但是在最后渲染的一瞬间,css中的margin又作用到了login的身上,
            // 导致位置发生了变化,为了抵消掉css中margin的值,所以应该在最后赋值的那一刻,把margin减掉
            login.style.left = targetX + 256 + 'px';
            login.style.top = targetY - 140 + 'px';
          }
        }
        
    //2.8 松手,login不在移动
    document.onmouseup = function(){
      document.onmousemove = null;
    }
</script>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值