JavaScript网页编程之BOM浏览器对象模型

257 阅读9分钟

BOM概念

  • BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM 由多个对象组成,其中代表浏览器窗口的 Window对象是 BOM 的顶层对象,其他对象都是该对象的子对象。
  • 我们在浏览器中的一些操作都可以使用BOM的方式进行编程处理,比如:刷新浏览器、后退、前进、在浏览器中输入URL等。

window对象

  • window 是浏览器的顶级对象,当调用 window 下的属性和方法时,可以省略 window
  • 注意:window下两个特殊的属性 window.name、window.top。
  // 在全局作用域定义的全局变量,都是window的一个属性
  var age = 18;
  console.log(window.age);
  // window中的特殊属性name,如果定义新的变量,只会在原来的name属性上进行赋值,  并且只能是字符串格式的值
  var name = 12;
  console.log(window.name);  // "12"
  
  // top属性在window中,属性值指向的就是顶层对象window,这个属性是只读的,不能后  期更改。
  var top = 23;
  console.log(window.top);  // window

对话框

alert()

prompt() 有返回值

confirm() 有返回值

案例

// 警示框
alert("Hello");
// 提示框(有返回值)
var num = prompt("请输入一个数字",12);
// 让用户进行确认或者取消选择的对话框
// confirm 方法有返回值,true or false
var isTrue = confirm("请问,您确定要删除这条数据吗?");
  • 注意:一般只有在demo中使用这些提示框方法。防止不同浏览器出现兼容问题,所以在项目中,基本不使用这样的语句,因为不可控。此时我们可以使用自己通过js和css定义文本框的样式来解决,就不会出现兼容问题。

加载事件

onload事件

  • 给 window 对象或者 等元素添加 onload 加载事件,表示只有绑定事件的元 素加载完毕才能触发事件,才能执行事件函数。
  • 其中 window 对象加载完毕:指的是所有HTML结构加载完,并且外部引入资源(js、css、img、视频)也加载完毕。

案例

  • chrome浏览器渲染加载的机制,由于图片加载事件过长,避免等待,图片在加载过程中,会先执行后面的js代码。后续需要使用到图片的宽度或高度等尺寸,在js中可能获取不到。
  • 解决方案1
<script>
        var box = document.getElementById("box");
        var imgs = box.getElementsByTagName("img");
        // 获取自身的高度
        // console.log(box.clientHeight);  // 0 这里输出0,显然不正确
        /* 想要得到的结果,是在div的内部图片全部加载完成后,
           图片将div撑起来的高度
        */
       var num = 0;
       for(var i = 0;i < imgs.length; i++){
           //给每个图片都绑定一个onload事件
          imgs[i].onload = function(){
            num++;
            if(num >= imgs.length){
                console.log(box.clientHeight);
            }
          } 
       }
    </script>
  • 解决方案2
// 事件被触发时,页面中的所有元素都已经加载完成,获取任何属性都不会出错
        window.onload = function(){
            var box = document.getElementById("box");
            var imgs = box.getElementsByTagName("img");
            // 获取自身的高度
            console.log(box.clientHeight);  
        }

应用

  • 利用window.onload事件,可以将js代码提前到html结构之前
  • 注意:一个页面中只能有一个window.onload事件。因为onload是window的一个属性,多次赋值会进行覆盖。

延时器

  • 延时器是 window 对象的一个方法,类似于定时炸弹。
  • 语法:window.setTimeout(func,time);
    • 第一个参数:延时执行的函数,可以是匿名函数定义,或者是一个函数名的引用,注意不要加()
    • 第二个参数:延时的时间,以毫秒计数,1000 毫秒等于 1 秒。
  • 功能:在指定的时间后,延迟执行一个函数。
  • 延时器采用的异步语句
  • 执行代码
//延时器为了保证后期能够被清除,需要定义赋值给一个变量
var timeout = window.setTimeout(function() {
  console.log("boom");
},2000);

清除延时器(需要延时器变量名引用)

  • window 对象的一个方法
  • 语法:window.clearTimeout(timeout);
  • 参数:指定的延时器变量名引用。
  • 功能:清除指定的延时器。
  • 注意:清除的延时器需要存储到一个变量中,便于后期清除调用。
//清除延时器
window.clearTimeout(timeout);

应用:函数节流

  • 为什么要函数节流?
    • 答:防止有人恶意点击。如果程序代码很多,但是你很快的点击,程序一次还没有运行出结果,就有可能导致程序出错。
  • 代码展现
    <script>
        // 获取事件源
        var btn = document.getElementById("btn");
        // 绑定事件
        /* 需要一个变量作为开关,来控制点击
           true 表示锁住状态,不能执行后面的代码;
           false 表示打开状态,执行后面的代码
        */
        // 初始状态是打开的
        var lock = false;
        btn.onclick = function(){
            if(lock){
                return;
            }
            console.log(Math.random());
            //执行完毕后,锁应该被锁住
            lock = true;
            //隔2秒后,锁再次打开
            window.setTimeout(function (){
                lock = false;
            },2000);
        }
    </script>

定时器

  • 定时器是 window 对象的一个方法,相当于定时闹钟,每隔固定的时间响一次。
  • 语法:window.setInterval(func,interval);
  • 第一个参数:每次执行的函数,可以是匿名函数定义,或者是一个函数名的引用,注意不要加 () 。
  • 第二个参数:时间间隔,以毫秒计数,1000 毫秒等于 1 秒。
  • 功能:每隔一个指定的时间,周期性的执行一个函数。
       //创建一个定时器
        var start = 0;
        var timer = setInterval(function (){
            console.log(start++);
        },4000);  // 1000毫秒是1秒

清除定时器

  • window 对象的一个方法
  • 语法:window.clearInterval(timer);
  • 参数:指定的定时器变量名引用。
  • 功能:清除指定的定时器。
  • 注意:清除的定时器需要存储到一个变量中,便于后期清除调用。
       //清除定时器,需要用到定时器的引用
        clearInterval(timer);

简单运动

原理

  • 简单运动:是一种视觉暂留效果,只要元素变化过程时间够短,给人眼造成的效果就是一个运动的效果,人眼的视觉残留的时间 0.1-0.4 秒之间。
  • 制作方法:通过定时器,实现每隔一个极短的时间(50-100 毫秒左右),执行函数,函数内部让运动的属性值发生变化。
  • 实践代码
    <input type="button" value="开始" id = "start">
    <div id ="box"></div>
    <script>
        // 获取事件源
        var start = document.getElementById("start");
        var box = document.getElementById("box");

        // 信号量,初始值必须与属性初始值保持一致
        var newleft = 0;
        start.onclick = function (){
            //创建定时器
              setInterval(function (){
                  //设置步长,信号量进行自加
                  newleft += 10;
                  // 将最新的newleft的值赋给元素的css属性
                  // 千万不要忘记加"px"
                  box.style.left = newleft + "px";
              },100);
        }   
    </script>
  • 注意:千万不要忘记加"px"

提高运动速度的方法

  • 缩短时间间隔,增加了每秒移动的次数。
        start.onclick = function (){
            //创建定时器
              setInterval(function (){
                  //设置步长,信号量进行自加
                  newleft += 10;
                  // 将最新的newleft的值赋给元素的css属性
                  // 千万不要忘记加"px"
                  box.style.left = newleft + "px";
              },100);  // 缩短时间间隔,就是将100换成50
        }   
  • 加大步长,让每一次走的步长增加。
  // 加大步长,时间间隔不变
  start.onclick = function (){
      //创建定时器
        setInterval(function (){
            //设置步长,信号量进行自加
            newleft += 30;  //加大步长
            // 将最新的newleft的值赋给元素的css属性
            // 千万不要忘记加"px"
            box.style.left = newleft + "px";
        },100);
  }   

清除定时器的问题

问题1

  • 将定时器的开始和停止过程中书写在不同的事件函数内部,容易出现用户错误点击情况
    • 1.多次点击开始,会造成加速(因为开启多个定时器后,步长会直接累加)
    • 2.多次点击开始,不能够再停止(因为定时器是赋值给一个变量存储的,多次赋值就会将之前的值覆盖,只记住最后一个,因此只能关闭最后一个定时器)
  • 问题代码
<script>
        // 获取事件源
        var start = document.getElementById("start");
        var end = document.getElementById("end");
        var box = document.getElementById("box");

        var newleft = 0;
        start.onclick = function (){
            //创建定时器
            var timer = setInterval(function (){
                //设置步长
                newleft += 3;
                box.style.left = newleft + "px";
            },100);

        //此时end的点击事件,只能关闭最后一次点击生成的定时器,但是盒子不会停下来
        end.onclick = function (){
            clearInterval(timer);
        }
    }
    </script>

解决方法

  • 设表先关:每次开启新定时器之前,都清除一次前面的定时器
<script>
        var newleft = 0;
        var timer;
        //因此需要将定时器的开始和停止过程中书写在同一个事件函数内部
        // 采用设表先关方法
        start.onclick = function (){
            //清除定时器
            clearInterval(timer);
            //创建定时器
            timer = setInterval(function (){
                //设置步长
                newleft += 3;
                box.style.left = newleft + "px";
            },100);

        end.onclick = function (){
            clearInterval(timer);
        }
    }
    </script>

问题2

  • 需求:要求元素走到指定位置停止,例如让元素停止在 500px 的位置.
  • 问题:如果步长设置的不合理,停止的位置可能不是正好在 500 处。

解决方法

  • 拉终停表
    • 在定时器内部每次都要判断是否走到了终点,要不要停止定时器
    • 如果走到或超过了终点,强行拉到重点,并停止定时器
  • 解决代码
        var newleft = 0;
        var timer;
        //因此需要将定时器的开始和停止过程中书写在同一个事件函数内部
        // 采用设表先关方法
        start.onclick = function (){
            //清除定时器
            clearInterval(timer);
            //创建定时器
            timer = setInterval(function (){
                //设置步长
                newleft += 11;
                //如果走到或超过了终点,强行拉到重点,并停止定时器
                if(newleft >= 500){
                //此时已经到了要停的位置,将要停的值500强制赋给元素的left属性
                    newleft = 500;
                    //清除定时器
                    clearInterval(timer);
                }
                box.style.left = newleft + "px";
            },100);

        // //此时end的点击事件,只能关闭最后一次点击生成的定时器,但是盒子不会停下来
        end.onclick = function (){
            clearInterval(timer);
        }
    }

问题3

  • 需求:在规定时间内让元素走到规定的结束位置,时间间隔可以更改
  • 例如:让元素在 2 秒钟内,left 属性从 0 走到 500px.

解决方法

  • 步标整除
  • 代码演示
// 要求:让元素在2秒钟内,left属性从0走到500px
        /* 分析:
               总时间:2000
               end: 500
               start: 0
               总距离 = 步长 * 次数
               时间间隔自定义,总时长固定
               总次数 = 总时长 / 时间间隔
               步长 = (end - start) / (总时长 / 时间间隔)
        */
       // 结束位置
        var endLeft = 500;
        // 开始位置
        var startLeft = 0;
        // 总时长
        var time = 2000;
        // 时间间隔
        var interval = 50;
        // 次数
        var maxCount = time / interval;
        // 步长
        var step = (endLeft - startLeft) / maxCount;
       
        // 定义信号量
        var nowLeft = startLeft;
        // 定义一个次数的累加器
        var num = 0;
        // 存储定时器变量
        var timer;

        // 绑定事件
        start.onclick = function (){
            clearInterval(timer);
            timer = setInterval(function (){
                nowLeft += step;
                num++;
                /* 使用结束位置作为判断条件
                   但是,这种判断方式更适用在:单一动画
                        当在多属性动画时,就显得比较麻烦了
                        因为:需要列出各个方向的最终位置判断
                    改进方法:将判断语句中的“最终位置”改为“次数”
                */
               // 改进前:
                // if(nowLeft >= endLeft){
                //     nowLeft = endLeft;
                //     clearInterval(timer);
                // }
                // 改进后:
                if(num >= maxCount){
                    nowLeft = endLeft;
                    clearInterval(timer);
                }
                box.style.left = nowLeft + "px";
            },interval);
        }

封装动画函数

  • 单一动画
  • 多属性动画
// 结束位置
        var endLeft = 500;
        var endWidth = 200;
        // 开始位置:自动获取
        // offsetLeft:偏移位置:偏移参考父级边框以内 到 自己的边框外 -> 不包含偏移参考父级的边框,不包含自己的边框
        // offsetWidth:自己当前实际的宽度
        var startLeft = box.offsetLeft;
        var startWidth = box.offsetWidth;

        // 总时长
        var time = 2000;
        // 时间间隔
        var interval = 50;
        // 次数
        var maxCount = time / interval;
        // 步长
        var stepLeft = (endLeft - startLeft) / maxCount;
        var stepWidth = (endWidth - startWidth) / maxCount;
       
        // 定义一个次数的累加器
        var num = 0;
        // 存储定时器变量
        var timer;

        // 绑定事件
        start.onclick = function (){
            clearInterval(timer);
            timer = setInterval(function (){
                startLeft += stepLeft;
                startWidth += stepWidth;
                num++;
                /* 使用结束位置作为判断条件
                   但是,这种判断方式更适用在:单一动画
                        当在多属性动画时,就显得比较麻烦了
                        因为:需要列出各个方向的最终位置判断
                    改进方法:将判断语句中的“最终位置”改为“次数”
                */
               // 改进前:
                // if(nowLeft >= endLeft){
                //     nowLeft = endLeft;
                //     clearInterval(timer);
                // }
                // 改进后:
                if(num >= maxCount){
                    startLeft = endLeft;
                    startWidth = endWidth;
                    clearInterval(timer);
                }
                box.style.left = startLeft + "px";
                box.style.width = startWidth + "px";
            },interval);
        }
  • 注意:在写程序的时候,尽量避免自己直接写数值上去。可采用变量或自动获取方法来替代手写数值

页面特效

案例

  • 简单无缝滚动
  • 高级无缝滚动
  • 点击切换的轮播图
  • 返回顶部

location对象

  • location对象是window对象下的一个属性,使用的时候可以省略window对象
  • location可以获取或者设置浏览器地址栏的URL