admin管理员组

文章数量:1587993

BOM 浏览器对象模型

1. BOM 的概念

BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。

BOM 由多个对象组成,其中代表浏览器窗口的 Window 对象是 BOM 的顶层对象,其他对象都是该对象的子对象

我们在浏览器中的一些操作都可以使用BOM的方式进行编程处理,比如:刷新浏览器、后退、前 进、在浏览器中输入URL等

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

最早是网景公司给浏览器做的标准,各个浏览器厂商支持情况不同,所以兼容性比较差,接下来学习 BOM 一些没有兼容性或兼容性较好的内容

(1)DOM 和 BOM 的对比

DOM:

文档对象模型

把文档当作一个对象来看待

顶级对象是 document

主要学习的是操作页面元素

是 W3C 标准规范

BOM:

浏览器对象模型

把浏览器当作一个对象来看待

顶级对象是 window

学习的是浏览器窗口交互的一些对象

是浏览器厂商在各自浏览器上定义的,兼容性较差

(2)BOM 的构成

BOM 比 DOM 更大,它包含 DOM

window顶层对象 包含 document、location、navigation、screen、history等子对象

2. window 对象

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

  • 它是 JavaScript 访问浏览器窗口的一个接口
  • 它是一个全局对象,定义在全局作用域中的变量,函数都会变成 window 对象的属性和方法

当调用 window 下的属性和方法时,可以省略 windowalert(1); 完整写法 window.alert(2);

document 对象就是 window 的一个子对象。window.document

在全局作用域定义的全局变量,都是 window 的一个属性

注意:window下两个特殊的属性 window.name、window.top。

  • name 属性如果定义新的变量,只会在原来的 name 属性上进行赋值,并且只能是字符串格式的值
  • top 属性在 window 中,属性值指向的就是顶层对象 window ,这个属性是只读的,不能后期更改
  • 所以在全局作用域定义变量时尽量不要用 name 和 top 进行定义
  • 在局部作用域,即函数作用域内部可以用 name 和 top,不会与 window 对象里的冲突

对话框

警示框:alert()

提示框:prompt()

让用户进行确认或者取消选择的对话框 :confirm()

confirm 方法有返回值,根据按钮点击情况,如果点击确定,返回 true;如果点击取消,返回 false

注意:对话框方法存在一些弊端,真正上线的项目不会使用这三种方法,会模拟它们的效果,自己设置样式,这些样式都是统一的,不会出现不同浏览器的兼容问题

  • alert():通过点击让谁显示,让谁隐藏的方式进行模拟
  • prompt():想要接收数据,可以通过 input 等表单元素进行模拟

加载事件

1. onload 事件

window.onload = function () {};

我们可以给 window 对象或者 <img> 等元素添加 onload 加载事件,表示只有绑定事件的元素加载完毕才能触发事件,才能执行事件函数。

// Chrome 浏览器渲染加载的机制,由于图片加载时间过长,避免等待,图片在加载过程中,会先执行后面的 js 代码
// 后续需要使用到 图片的宽度或高度等尺寸,在 js 中可能获取不到
// 图片的加载事件,只要图片加载完毕渲染成功后,就能够立即执行事件函数
var sum = 0;
for (var i = 0; i < pics.length; i++) {
  pics[i].onload = function () {
    sum++;
    // 判断这一次是否加载所有图片完毕
    if (sum >= pics.length) {
      console.log(box.clientHeight);
    }
  };
}
// 若只针对某一段代码获取它的尺寸,用这种方式
// window.onload 是要等所有代码加载完才执行

其中 window 对象加载完毕:指的是所有HTML结构加载完,并且外部引入资源(js、css、img、 视频)也加载完毕

// 用 window.onload 可以把 JS 代码放在页面中的任意位置,因为 onload 是等页面全部加载完毕,再去执行处理函数
window.onload = function () {
	// 事件被触发时,页面所有内容都已经加载完毕,获取元素不会出现错误
    var box = document.getElementById("box");
    var pics = document.getElementsByTagName("img");
    console.log(box.clientHeight);
};

利用 window.onload 事件,可以将 js 代码提前到 html 结构之前。

注意:一个页面中只能有一个 window.onload 事件。(若写多个,会以最后一个为准)

2. addEventListener 方法

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

使用 addEventListener 没有个数限制,执行时,先执行最后一个,再一步一步往上执行

3. DOMContentLoaded 事件(IE9 以上支持)

document.addEventListener("DOMContentLoaded",function () {});

DOMContentLoaded 事件触发时,仅当 DOM 加载完成,不包括 css、img、flash等,如果页面的图片很多的话,从用户访问到 onload 触发可能需要较长时间,交互效果就不能实现,必会影响用户体验,此时 DOMContentLoaded 较合适

例如:图片加载不完,页面滚动条、鼠标放上去显示下拉菜单等出不来

4. 总结区别

load 等页面内容全部加载完毕,包含页面 DOM 元素、img、flash、css 等

DOMContentLoaded 是 DOM 加载完毕,不包含 img、flash、css 等就可以执行,加载速度比 load 更快一些

5. 调整窗口大小事件

window.onresize = function () {};

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

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

注意:

  • 只要窗口大小发生像素变化,就会触发这个事件
  • 我们经常利用这个事件完成响应式布局,window.innerWidth :当前屏幕宽度

案例:当屏幕宽度 <= 800 时,div 隐藏

window.addEventListener("load", function () {
  var div = document.querySelector("div");
  window.addEventListener("resize", function () {
    if (window.innerWidth <= 800) {
      div.style.display = "none";
    } else {
      div.style.display = "block";
    }
  });
});

延时器

1. 延时器

延时器是 window 对象的一个方法,类似于定时炸弹

语法:window.setTimeout(func,time); (window 可省略)

第一个参数:延时执行的函数,可以是匿名函数定义,或者是一个函数名的引用,注意不要加 () ;还有一个字符串写法 “函数名()”,但不推荐使用

第二个参数:延时的时间,以毫秒计数,1000 毫秒等于 1 秒。(单位可以省略)

功能:在指定的时间后,延迟执行一个函数

// window 在调用时可以省略
// 异步语句
// 延时器为了保证后期能够被清除,需要定义赋值给一个变量
var timeout = window.setTimeout(function () {
	console.log("boom");
}, 2000);
// 清除延时器,清除要写到定义之后
window.clearTimeout(timeout);
setTimeout(function () {
	console.log("boom");
}, 2000);
function callback() {
	console.log("boom");
}
// 页面中可能会有很多的定时器,我们经常给定时器加标识符(名字)来区别不同的定时器
var time1 = setTimeout(callback, 2000);
// setTimeout("callback()", 2000);  // 不推荐使用

setTimeout() 这个调用函数我们也称为回调函数 callback

普通函数是按照代码顺序直接调用,而这个函数需要等待时间,时间到了才去调用这个函数,因此称为回调函数

以前讲的 element.onclick = function () {} / element.addEventListener("click",fn) 里面的函数也是回调函数(点击完再去调用函数)

2. 清除延时器

window 对象的一个方法

语法:window.clearTimeout(timeout); (window 可省略)

参数:指定的延时器变量名引用。

功能:清除指定的延时器。

注意:清除的延时器需要存储到一个变量中,便于后期清除调用

案例:函数节流操作

如果用户连续点击,进行防骚扰操作,让中间的点击是无效的

// 点击输出,随机数
var btn = document.getElementById("btn");
// 绑定事件
// 函数节流操作
// 定义一个开关,给函数上一把锁,true 表示锁住状态,不能执行后面的代码;false 表示打开状态,可以执行后面的代码
// 初始状态锁是打开的
var lock = false;
btn.onclick = function () {
	// 函数内部需要判断,是否在指定的时间之外触发事件
  	// 如果锁是打开的,可以往后执行
  	// 如果锁是锁住的,不能执行后面的代码
  	if (lock) {
    	return;
  	}
  	console.log(Math.random());
  	// 执行完毕后,锁应该被锁住
  	lock = true;
  	// 隔 2 秒后,锁再次打开
  	setTimeout(function () {
    	lock = false;
  	}, 2000);
};

定时器

1. 定时器

定时器是 window 对象的一个方法,相当于定时闹钟,每隔固定的时间响一次

语法:window.setInterval(func,interval); (window 可省略)

第一个参数:每次执行的函数,可以是匿名函数定义,或者是一个函数名的引用,注意不要 加 () 。

第二个参数:时间间隔,以毫秒计数,1000 毫秒等于 1 秒。

功能:每隔一个指定的时间,周期性的执行一个函数

2. 清除定时器

window 对象的一个方法

语法:window.clearInterval(timer); (window 可省略)

参数:指定的定时器变量名引用。

功能:清除指定的定时器。

注意:清除的定时器需要存储到一个变量中,便于后期清除调用

var i = 1;
// 定时器也是异步语句
// 开启定时器,每隔 0.5 秒输出一次 i,并且让 i 每次自加
// 程序执行到定时器代码部分就相当于开启了一个定时器,不需要进行其他的打开操作
// 第一次执行函数时是在第一个时间间隔之后
//   window.setInterval(function () {
//     console.log(i++);
//   }, 500);

// 要想清除定时器,在定义的时候必须存到一个变量中
var timer = setInterval(function () {
  console.log(i++);
}, 500);
// 清除定时器,必须写到之后才会成功
window.clearInterval(timer);

案例:倒计时

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

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

<body>
    <div>
      <span class="hour">1</span>
      <span class="minute">2</span>
      <span class="second">3</span>
    </div>
    <script>
      var hour = document.querySelector(".hour");
      var minute = document.querySelector(".minute");
      var second = document.querySelector(".second");
      // 用户输入时间总的毫秒数
      var inputTime = +new Date("2021.6.29 24:00:00");
      // 先调用一次这个函数,防止第一次刷新页面有空白
      countDown();
      // 开启定时器
      setInterval(countDown, 1000);
      function countDown() {
        // 当前时间的总毫秒数
        var nowTime = +new Date();
        // 剩余时间的总秒数
        var times = (inputTime - nowTime) / 1000;
        // 时
        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>
/* css 代码 */
span {
  display: inline-block;
  width: 40px;
  height: 40px;
  background-color: gray;
  font-size: 24px;
  color: #fff;
  text-align: center;
  line-height: 40px;
}

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

注意:button 按钮里面的内容通过 innerHTML 修改,和其他表单元素不同,不是 value 值

<body>
    手机号码:<input type="number" /> <button>发送</button>
    <script>
      var btn = document.querySelector("button");
      // 定义剩下的秒数
      var time = 60;
      btn.addEventListener("click", function () {
        // 按钮点击后,会禁用
        btn.disabled = true;
        var timer = setInterval(function () {
          if (time == 0) {
            // 清除定时器
            clearInterval(timer);
            // 复原按钮
            btn.disabled = false;
            btn.innerHTML = "发送";
            // 这个 60 秒需要重新开始
            time = 60;
          } else {
            btn.innerHTML = "还剩下" + time + "秒";
            time--;
          }
        }, 1000);
      });
    </script>
</body>

简单运动

1. 原理

简单运动:是一种视觉暂留效果,只要元素变化过程时间够短,给人眼造成的效果就是一个运动的效果,人眼的视觉残留的时间 0.1-0.4 秒之间。

制作方法:通过定时器,实现每隔一个极短的时间(50-100 毫秒左右),执行函数,函数内部让运动的属性值发生变化

2. 提高运动速度的方法

(1)缩短时间间隔,增加了每秒移动的次数。

(2)加大步长,让每一次走的步长增加。

// 点击start按钮box开始向右运动,box在CSS中要加绝对定位,其中left初始值为 0 
var start = document.getElementById("start");
var end = document.getElementById("end");
var box = document.getElementById("box");
// 点击开始按钮,让 box 向右运动
// 全局变量存储 left 的属性值,会每次发生变化
// 信号量编程方法:用全局信号量掌控某一个属性值的变化
// 信号量,初始值必须与属性初始值保持一致
var nowLeft = 0;
// 全局变量,若变量不赋值,返回 undefined 很容易出问题,正好 null 是一个空对象,定时器也是个对象
var timer = null;
// 定时器写在事件函数内部,会由于事件多次被触发,导致定时器累积
// 解决方法:设表先关,每次重新开启一个定时器之前都先关闭一下之前的定时器
start.onclick = function () {
  // 定时器,制作运动过程
  // 先清除定时器
  clearInterval(timer);
  // 此处 timer 是局部变量,所以需要在外面定义一个全局变量,这样其他函数
  timer = setInterval(function () {
    // 信号量进行自加
    nowLeft += 35;
    // 判断这一次的运动是否走到了 500 的位置
    // 拉终停表,走到规定的终点位置
    if (nowLeft >= 500) {
    	// 将变量的值强制赋值为 500
        nowLeft = 500;
        // 清除定时器
        clearInterval(timer);
    }
    // 将最新的 nowLeft 的值赋值给元素的 css 属性
    box.style.left = nowLeft + "px";
  }, 100); 
  // 推荐时间间隔在 50 - 100 毫秒之间,因为有的浏览器渲染性能没有那么高
};
// 点击结束按钮,清除定时器
end.onclick = function () {
    // timer 是全局变量时,此处才能访问这个变量
	clearInterval(timer);
};

清除定时器的问题

参考上一个案例,“点击开始按钮和结束按钮”分别“开启和关闭定时器”

1. 问题1

将定时器的开始和停止过程书写在不同的事件函数内部,容易出现用户错误点击情况

(1)多次点击开始,会造成加速

原因:点击多次 start 按钮,相当于执行了多次事件函数,也就开启了多次定时器,每开启一次定时器,如果不清除,这个定时器会永远在程序中存在。每次开启定时器,每次步数加 5,如果点三次,就相当于开启了一个步长为 15 的定时器,相当于速度就增加了,所以元素会越来越快。

(2)多次点击开始,不能够再停止

原因:事件多次被触发,会开启多次定时器,点击结束按钮并不是清除每一个定时器,而是清除 timer 这个变量,在定时器开启的过程中,由于 timer 是全局变量,每次点击 start ,就相当于给 timer 赋了一个值,第二次点击时,第一个定时器相当于被替换了,timer 指向的不再是第一个定时器,而是第二个定时器,所以清除定时器的时候只能去清除当前 timer 里存储的最新的定时器,前面的定时器不再存在于变量里面,没有办法引用到,就没有办法进行清除

解决方法:

  • 设表先关
  • 每次开启新定时器之前,都清除一次前面的定时器

2. 问题2

需求:要求元素走到指定位置停止,例如让元素停止在 500px 的位置

问题:如果步长设置的不合理,停止的位置可能不是正好在 500 处

例如:要求走到500 ,若步长是20,则走25步刚好停在500处;但若步长是35,则走14步到达490处,此时不满足 >= 500 的条件,所以还需走一步,也就是停在了 490 + 35 = 525 处

解决方法:

  • 拉终停表
  • 在定时器内部每次都要判断是否走到了终点,要不要停止定时器
  • 如果走到或超过了终点,强行拉到终点,并停止定时器

3. 问题3

需求:在规定时间内让元素走到规定的结束位置,时间间隔可以更改

例如:让元素在 2 秒钟内,left 属性从 0 走到 500px

解决方法:

  • 步标整除
  • 总距离 = 步长 * 次数;
  • 时间间隔自定义,总时长固定
  • 求出总次数 = 总时间 / 时间间隔
  • 定义计数器变量,每执行一次定时器函数增加计数 1,直到执行达到总次数,停止定时器
var start = document.getElementById("start");
var box = document.getElementById("box");
// 已知 开始位置、结束位置、总时长、时间间隔
// 总距离 = 步长 * 总次数
// 总距离 = 结束位置 - 起始位置
// 总次数 = 总时长 / 时间间隔
// 步长 = (结束位置 - 起始位置) / (总时长 / 时间间隔)
// 信号量,也相当于初始值,与 CSS 中设置的相同
var nowLeft = 0;
// 结束位置
var endLeft = 500;
// 总时长 转换为毫秒
var time = 2000;
// 时间间隔
var interval = 50;
// 总次数
var maxcount = time / interval;
// 计算步长
var step = (endLeft - nowLeft) / maxcount;
//   console.log(step);
// 定义一个次数的累加器
var count = 0;
// 开始定时器
var timer = null;
start.onclick = function () {
	timer = setInterval(function () {
    // 让元素的属性每一次变化一个步长
    nowLeft += step;
    // 每运动一次让次数累加器加1
    count++;
    // 停止定时器
    // 如果定义的 time 和 interval 不是整除的,而 count 每次都加 1,所以说最后一次,count 有可能 大于/等于 maxcount
    if (count >= maxcount) {
    	// 拉终停表
      	nowLeft = endLeft;
      	clearInterval(timer);
    }
    // 给属性赋值
    box.style.left = nowLeft + "px";
  }, interval);
};

封装动画函数

// 补充:获取计算后样式的方法(得到的都是字符串的值)
console.dir(window.getComputedStyle(box));
console.log(window.getComputedStyle(box).width);
console.log(window.getComputedStyle(box).height);
console.log(window.getComputedStyle(box).backgroundColor);
console.log(window.getComputedStyle(box)["background-color"]);
console.log(window.getComputedStyle(box)["opacity"]);

多属性动画:将封装好的动画函数单独放到一个 js 文件中,使用时引用这个 js 文件即可

// 多属性运动
// 共同点:总时间、时间间隔是相同的,自定义
// 不同的:起始位置(通过程序方法自动获取当前页面最终显示效果)和结束位置(自定义指定的)

// 函数参数
// 参数1:元素对象,它要进行运动
// 参数2:结束位置,以对象数据方式传递
// 参数3:总时间
// 自定义动画函数
function animate(ele, end, time) {
	// 已知结束位置,总时间,时间间隔 50,缺少起始位置
  	// 起始位置要根据结束位置提供的属性进行获取
  	// 起始位置的对象,需要先定义一个空对象
  	var now = {};
  	// end 对象遍历,获取属性名
  	for (var k in end) {
    	now[k] = parseFloat(window.getComputedStyle(ele)[k]);
    }
    // console.log(start);  // {left: 0, width: 100, height: 100, opacity: 0.5}
    // 自定义时间间隔
    var interval = 50;
    // 计算总次数
    var maxcount = time / interval;
    // 次数累加器
    var count = 0;
    // 对象中的每个属性都有自己的步长,也可以放到一个步长对象中
    var step = {};
    // 遍历结束对象,计算每个属性的步长
    for (var k in end) {
      step[k] = (end[k] - now[k]) / maxcount;
    }
    // console.log(step);
    // =====================准备工作结束,开启定时器======================
	var timer = null;
	timer = setInterval(function () {
		// 让每个属性发生变化,赋值给 now 对象中的每一项
  		for (var k in end) {
    		now[k] += step[k];
  		}
  		// 累计运动次数
  		count++;
  		// 判断定时器是否结束
  		if (count >= maxcount) {
    		// 拉终停表
    		for (var k in end) {
      			now[k] = end[k];
    		}
    	clearInterval(timer);
  		}
  		// 赋值给对应元素对象属性
  		for (var k in now) {
    		// 判断如果是 不透明度属性 ,不要加 px 单位
    		if (k === "opacity") {
      			ele.style[k] = now[k];
    		}
    		ele.style[k] = now[k] + "px";
  		}
	}, interval);
}

使用时:animate(box, { left: 400, width: 300, height: 200, opacity: 1 }, 2000);

<body>
    <input type="button" id="start" value="开始" />
    <div class="box" id="box"></div>
    <script src="animate.js"></script>
    <script>
      var start = document.getElementById("start");
      var box = document.getElementById("box");
      // box 是需要运动的元素
      // 调用函数
      start.onclick = function () {
        animate(box, { left: 400, width: 300, height: 200, opacity: 1 }, 2000);
      };
    </script>
</body>

页面特效

1. 简单无缝滚动

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      .scroll {
        position: relative;
        width: 830px;
        height: 130px;
        border: 10px solid #000;
        margin: 100px auto;
        overflow: hidden;
      }
      .scroll ul {
        position: absolute;
        left: 0;
        top: 0;
        width: 5000px;
        height: 130px;
      }
      .scroll ul li {
        float: left;
        width: 200px;
        height: 130px;
        margin-right: 10px;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div class="scroll" id="scroll">
      <ul id="munit">
        <li><img src="images/shuzi/0.png" alt="" /></li>
        <li><img src="images/shuzi/1.png" alt="" /></li>
        <li><img src="images/shuzi/3.png" alt="" /></li>
        <li><img src="images/shuzi/4.png" alt="" /></li>
        <li><img src="images/shuzi/5.png" alt="" /></li>
        <li><img src="images/shuzi/6.png" alt="" /></li>
        <li><img src="images/shuzi/0.png" alt="" /></li>
        <li><img src="images/shuzi/1.png" alt="" /></li>
        <li><img src="images/shuzi/3.png" alt="" /></li>
        <li><img src="images/shuzi/4.png" alt="" /></li>
        <li><img src="images/shuzi/5.png" alt="" /></li>
        <li><img src="images/shuzi/6.png" alt="" /></li>
      </ul>
    </div>
    <script>
      var scroll = document.getElementById("scroll");
      var munit = document.getElementById("munit");
      // 自动播放
      var nowLeft = 0;
      // 关键点:找到 ul 元素的运动的折返点
      var back = -1260;
      var timer = null;
      timer = setInterval(run, 5);
      // 鼠标移上 scroll 元素,让运动停止
      scroll.onmouseover = function () {
        clearInterval(timer);
      };
      // 鼠标离开 scroll 元素,让运动重新开始
      scroll.onmouseout = function () {
        timer = setInterval(run, 5);
      };

      // 运动函数
      function run() {
        // nowLeft 进行自减
        nowLeft -= 1;
        // 每次都要判断,是否走到了折返点,如果走到了,让它瞬间切换到 0
        if (nowLeft <= back) {
          nowLeft = 0;
        }
        // 给 ul 赋值
        munit.style.left = nowLeft + "px";
      }
    </script>
  </body>
</html>

2. 高级无缝滚动

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3/1999/xhtml" xml:lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .scroll {
        width: 830px;
        height: 130px;
        border: 10px solid #000;
        margin: 100px auto;
        overflow: hidden;
      }
      .scroll .inner {
        position: relative;
        width: 5000px;
      }
      .scroll .inner ul {
        position: absolute;
        top: 0;
        left: 0;
        height: 130px;
        list-style: none;
      }
      .scroll ul li {
        float: left;
        margin-right: 10px;
      }
    </style>
    <script>
      window.onload = function () {
        // 获取元素
        var scroll = document.getElementById("scroll");
        var munit = document.getElementById("munit");
        // 2.折返点计算需要通过 js 自动计算
        var back = -munit.offsetWidth;
        console.log(back);
        // 1.自动生成另一组对应的图片结构 li
        munit.innerHTML += munit.innerHTML;
        // 自己进行滚动播放
        var nowLeft = 0;
        var timer;
        timer = setInterval(run, 5);
        // 3.鼠标移上 scroll 元素,让运动停止
        scroll.onmouseover = function () {
          clearInterval(timer);
        };
        // 4.鼠标离开 scroll 元素,让运动重新开始
        scroll.onmouseout = function () {
          timer = setInterval(run, 5);
        };

        // 运动函数
        function run() {
          // nowLeft 进行自减
          nowLeft -= 1;
          // 每次都要判断,是否走到了折返点,如果走到了,让他瞬间切换到 0
          if (nowLeft <= back) {
            nowLeft = 0;
          }
          // 给ul 赋值
          munit.style.left = nowLeft + "px";
        }
      };
    </script>
  </head>

  <body>
    <div class="scroll" id="scroll">
      <div class="inner">
        <ul id="munit">
          <li><img src="images/shuzi/0.png" alt="" /></li>
          <li><img src="images/shuzi/1.png" alt="" /></li>
          <li><img src="images/shuzi/2.png" alt="" /></li>
          <li><img src="images/shuzi/3.png" alt="" /></li>
          <li><img src="images/shuzi/4.png" alt="" /></li>
          <li><img src="images/shuzi/5.png" alt="" /></li>
          <li><img src="images/shuzi/6.png" alt="" /></li>
        </ul>
      </div>
    </div>
  </body>
</html>

3. 完整切换效果轮播图

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      ul,
      ol {
        list-style: none;
      }
      a {
        text-decoration: none;
      }
      .carousel {
        position: relative;
        width: 880px;
        height: 550px;
        border: 1px solid #333;
        margin: 50px auto;
      }
      .pic li {
        position: absolute;
        top: 0;
        left: 0;
        width: 880px;
        height: 550px;
        display: none;
      }
      .pic li.current {
        display: block;
      }
      .btn a {
        position: absolute;
        top: 50%;
        width: 80px;
        height: 80px;
        margin-top: -40px;
        background: rgba(225, 225, 225, 0.3);
        color: #444;
        text-align: center;
        line-height: 80px;
        font-size: 60px;
        font-family: "SimSun";
      }
      .btn .left {
        left: 10px;
      }
      .btn .right {
        right: 10px;
      }
      .btn a:hover {
        background: rgba(225, 225, 225, 0.7);
      }
      .sub {
        position: absolute;
        bottom: 30px;
        left: 50%;
        width: 200px;
        height: 40px;
        margin-left: -100px;
        border-radius: 20px;
        background-color: rgba(255, 255, 255, 0.3);
      }
      .sub li {
        float: left;
        width: 20px;
        height: 20px;
        margin: 10px;
        border-radius: 50%;
        background-color: #ccc;
        cursor: pointer;
      }
      .sub li.current {
        background-color: #0ff;
      }
    </style>
  </head>
  <body>
    <div class="carousel" id="carousel">
      <ul class="pic" id="pic">
        <li class="current"><img src="images/lunbo/01.jpg" alt="" /></li>
        <li><img src="images/lunbo/02.jpg" alt="" /></li>
        <li><img src="images/lunbo/03.jpg" alt="" /></li>
        <li><img src="images/lunbo/04.jpg" alt="" /></li>
        <li><img src="images/lunbo/05.jpg" alt="" /></li>
      </ul>
      <div class="btn" id="btn">
        <a href="javascript:;" class="left" id="leftbtn">&lt;</a>
        <a href="javascript:;" class="right" id="rightbtn">&gt;</a>
      </div>
      <ol class="sub" id="sub"></ol>
    </div>
    <script>
      // 编程思路:信号量编程,通过一个全局变量的信号量,在不同的事件函数中进行信息传递,让多个事件进行协同作业
      var carousel = document.getElementById("carousel");
      var ul = document.getElementById("pic");
      var ulLis = ul.children;
      var leftbtn = document.getElementById("leftbtn");
      var rightbtn = document.getElementById("rightbtn");
      var ol = document.getElementById("sub");
      var olLis = ol.children;
      // 全局信号量,存储的是要展示的图片所在的 li 的下标
      var idx = 0;
      // 1.右按钮事件,切换到下一张
      rightbtn.onclick = rightHandle;
      // 2.左按钮事件,切换到上一张
      leftbtn.onclick = function () {
        // 信号量自减
        idx--;
        // 判断 idx 是否是超过最小的下标,如果是,就相当于从第一张要切换到最后一张
        if (idx < 0) {
          idx = ulLis.length - 1;
        }
        // 调用一个切换函数
        change();
      };
      // 动态生成小圆点
      for (var i = 0; i < ulLis.length; i++) {
        var li = document.createElement("li");
        li.setAttribute("index", i);
        ol.appendChild(li);
        // 默认第一项为选中状态
        ol.children[0].className = "current";
        // 3.下标小圆点事件,点哪个小圆点,对应展示图片
        for (var j = 0; j < ol.children.length; j++) {
          console.log(j);
          // 存储自己的下标
          ol.children[j].index = j;
          ol.children[j].onclick = function () {
            // 获取当前点击的元素的下标
            idx = this.index;
            // console.log(idx);
            change();
          };
        }
      }
      // 4.轮播图自动播放,执行类似右按钮的事件
      var timer = null;
      timer = setInterval(rightHandle, 3000);
      // 5.鼠标移上轮播图,停止自动播放
      carousel.onmouseover = function () {
        clearInterval(timer);
      };
      // 6.鼠标离开轮播图,重新开始自动轮播
      carousel.onmouseout = function () {
        timer = setInterval(rightHandle, 3000);
      };

      // 定义右按钮事件函数
      function rightHandle() {
        // 信号量自加
        idx++;
        // 判断 idx 是否是超过最大的下标,如果是,就相当于从最后一张要切换到第一张
        if (idx > ulLis.length - 1) {
          idx = 0;
        }
        // 调用一个切换函数
        change();
      }
      // 定义切换函数
      function change() {
        for (var i = 0; i < ulLis.length; i++) {
          ulLis[i].className = "";
          olLis[i].className = "";
        }
        ulLis[idx].className = "current";
        olLis[idx].className = "current";
      }
    </script>
  </body>
</html>

4. 返回顶部特效

// 获取页面卷动的距离
// document.body.scrollTop
// document.documentElement.scrollTop
// 获取元素
var header = document.getElementById("top");
var backtop = document.getElementById("totop");
// 1.在页面往下卷动到一定距离后,让 header 高度变低,让 返回顶部按钮出现
// 添加页面滚动事件
window.onscroll =  function () {
  // 判断卷动走的距离,如果超过 10 px,就让 header变低,让 返回顶部按钮出现
  scrollTops = document.body.scrollTop || document.documentElement.scrollTop;
  if (scrollTops > 10) {
    header.className = "header fixed";
    backtop.style.display = "block";
  } else {
    header.className = "header";
    backtop.style.display = "none";
  }
  // console.log(scrollTops);
};
// 变量存储定时器
var timer = null;
// 2.点击返回顶部,让页面以动画的方式跳转到页面顶部
backtop.onclick = function () {
  // 终点
  var target = 0;
  // 起始点
  var current = document.documentElement.scrollTop;
  // 步长
  var step = 30;
  timer = setInterval(function () {
    // 获取当前卷动的值,每次递减一个步长
    current -= step;
    // 拉终停表
    if(current <= target){
      current = target;
      clearInterval(timer);
    }
    // 重新赋值
    document.documentElement.scrollTop = current;
  },10);
};

location 对象

1. location 对象

location 对象是 window 对象下的一个属性,使用的时候可以省略 window 对象

location 可以获取或者设置浏览器地址栏的 URL,并且可以用于解析 URL ,因为这个属性返回的是一个对象,所以将这个属性也称为 location 对象

2. URL

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

URL的组成:scheme://host:port/path?query#fragment

例如:http://www.baidu:80/a/b/index.html?name=zs&age=18#bottom

  • scheme:通信协议,常用的http,ftp,maito等
  • host:主机,服务器(计算机)域名系统 (DNS) 主机名或 IP 地址。
  • port:端口号,整数,可选,省略时使用方案的默认端口,如http的默认端口为80。
  • path:路径,由零或多个’/'符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。
  • query:查询,可选,用于给动态网页传递参数,可有多个参数,用’&‘符号隔开,每个参数的名和值用’='符号隔开。例如:name=zs
  • fragment:信息片断,字符串,锚点

3. location 对象的属性

使用 chrome 的控制台查看

查 MDN:https://developer.mozilla/zh-CN/

**location.href:获取/设置 整个 URL ,重新赋值,可以跳转到新页面,并且记录历史

location.host:返回主机(域名)

location.port:返回端口号,如果未写返回空字符串

location.pathname:返回路径

**location.search:返回参数(例如:在页面地址中添加?name=andy&age=18,返回"?name=andy&age=18")

location.hash:返回片段,# 后面内容 常见于链接、锚点(例如:在页面地址中添加#top,返回"#top")

案例:5秒种之后自动跳转页面

var div = document.querySelector("div");
var timer = 5;
// 先调用一次函数,防止第一次刷新页面有空白
countDown();
setInterval(countDown, 1000);
function countDown() {
  if (timer == 0) {
    location.href = "http://www.baidu";
  } else {
    div.innerHTML = "您还有" + timer + "秒之后跳转到首页";
    timer--;
  }
}

案例:获取 URL 参数数据

主要练习数据在不同页面中的传递

在 index.html 中能够使用 login.html 中的数据

<!-- login.html -->
<form action="index.html">
	<!-- 默认 get 提交,不要用 post,有 name 才能提交 -->
    用户名:<input type="text" name="uname" />
    <input type="submit" value="登录" />
</form>
<!-- index.html -->
<body>
    <div></div>
    <script>
      var div = document.querySelector("div");
      console.log(location.search); // ?uname=andy
      // 先去掉 ? ,用 substr() 截取字符串
      var params = location.search.substr(1);
      console.log(params); // uname=andy

      // 利用 = 把字符串分割成数组 split()
      var arr = params.split("=");
      console.log(arr); // (2) ["uname", "andy"]

      // 把数据写入 div 中
      div.innerHTML = arr[1] + "欢迎您";  // 例如:andy欢迎您
      // 注意:若用户输入用户名为中文时,会出现乱码,之后学习解决方法
    </script>
</body>

4. location 对象的方法

(1)location.assign()

  • assign 委派
  • assign() 方法的作用与 href 属性一样,可以设置页面跳转的地址(也称为重定向页面),并且记录历史,可以后退页面
  • 例如:location.assign("https://www.baidu");

(2)location.replace()

  • replace 替换
  • 功能:替换掉地址栏中当前的网址,但是不记录历史,不能后退页面
  • 例如:location.replace("https://www.baidu");

(3)location.reload()

  • reload 重新加载
  • 类似 键盘中 f5 功能,类似于 false 效果;ctrl+f5 强制刷新,从服务器获取页面,相当于 true 的效果
  • 参数:true 强制从服务器获取页面,false 如果浏览器有缓存网页的话,会直接从缓存中获取页面
  • 例如:location.reload(true);

navigator 对象

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

userAgent 里包含了浏览器相关信息,名称、版本号,还可得到系统版本号

// 下面代码可判断用户用哪个终端打开页面,实现跳转(了解即可)
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 = "PC 端页面的地址"; // 电脑
}

history 对象

history 对象是 window 对象下的一个属性,使用的时候可以省略 window 对象

history 对象可以与浏览器历史记录进行交互,浏览器历史记录是对用户所访问的页面按时 间顺序进行的记录和保存。

  • back():可以后退功能(相当于浏览器窗口的 ←)
  • forward(): 可以前进功能(相当于浏览器窗口的 →)
  • go(参数):前进后退功能,参数若是1,前进1个页面;若是-1,后退1个页面(参数也可以是2、3等等)

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

OA:办公自动化(office auto)

this 指向问题

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

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

// 以下都指向 this
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);  // 指向 o 这个对象
	}
}
o.sayHi;
btn.onclick = function () {
	console.log(this); // 指向 btn 按钮对象
}

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

function Fun () {
	console.log(this);  // 指向 fun 实例对象
}
var fun = new Fun();  // 对象实例化后赋给了 fun
// this 指向创建的新对象,实例化后赋值给 fun,所以 this 指向 fun

本文标签: 模型浏览器对象BOM