整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

大神的Javascript基础总结,还不收藏起来?

者:HXGNMSL来源:CSDN原文:https://blog.csdn.net/HXGNMSL/article/details/89076476

Javascript的历史来源

94年网景公司 研发出世界上第一款浏览器。

95年 sun公司 java语言诞生

网景公司和sun合作。

Javascript ===> javascript

JavaScript和ECMAScript的关系

简单来说ECMAScript不是一门语言,而是一个标准。符合这个标准的比较常见的有:JavaScript、Action Script(Flash中用的语言)

JavaScript的基本结构:

JavaScript的语法:

JavaScript的基础语法

变量的声明及使用

数据类型

运算符

逻辑控制语句

注释

语法规则

变量的声明语法:

var变量名;

例如:

Var num;

然后进行赋值:num = 10;也可以声明时直接赋值:

Var num =10;

在JavaScript中,提供了常用的基本数据类型:

undefined 未定义;

null 空;

string 字符串类型;

boolean 布尔类型;

number 数值类型;

运算符:

算数运算符:+、-、*、/、%、++、–;

比较运算符:>、<、> =、< =、==、!=;

逻辑运算符:&&、||、!;

赋值运算符:=;

逻辑控制语句:

JavaScript的逻辑控制语句也分为两类:条件结构和循环机构。

条件结构

条件机构分为if结构和switch结构:

If…else

Switch

循环结构

JavaScript的循环结构的执行顺序与Java类似,主要包括以下几种结构:

for循环

while循环

do…while循环

for…inx循环

示例:

for(var i=0;i<10;i++){

Document.write(“*”);

}

输出结果:**********

循环中断:

用于循环中断的语句有以下两种:

break.

continue.

与Java用法一样,break是跳出循环,continue是跳入下一次循环。

函数

函数有两种:一种是系统函数,一种是自定义函数

常用的系统函数包括:

parseInt():转换为整数。

parseFloat():转换为浮点型。

isNaN():判断非数字。

Eval():计算表达式值。

自定义函数:

自定义函数的语法

function 函数名(参数1,参数2,…){

…//语句

Return 返回值;//可选

}

函数的调用:

函数的调用方式有以下两种

事件名=函数名(传递的实参值),例如:

“函数名()”

直接使用函数名(传递的实参值),例如:

var recult = add(2,3);

匿名函数

匿名函数的语法

var sumFun=function(num1,num2){

return(nun1,num2);

} ;

在语法中:

var sunFun=function(num1,num2)表示声明一个变量等于某个函数体。

{…};是把整个函数体放在变量的后面,并把末尾添加一个分号。

匿名函数的调用:

由于匿名函数定义的整个语句,可以像赋值一样赋给一个变量进行保存,所以可以使用如下方式调用语法中的匿名函数:

var sum=sumFun(2,3)

BOM概述

使用BOM可以移动窗口,改变状态栏中的文本,执行其他与页面内容不直接相关的动作。它包含的对象主要有以下几种;

Window对象

Window对象是指整个窗口对象,可以通过操作Window对象的属性和方法控制窗口,例如,打开或关闭一个窗口。

History对象

浏览器访问过的历史页面对应History对象,通过History对象的属性和方法实现浏览器的前进或后退的功能。

Location对象

浏览器的地址栏对应Location对象,通过Location对象的属性和方法控制页面跳转。

Document对象

浏览器内的网页内容对应Document对象,通过Document对象的属性和方法,控制页面元素。

Window常用的属性有:

history:有关客户访问过的URL的信息。

location:有关当前URL的信息。

Screen: 有关客户端的屏幕和显示性能的信息。

Window对象常用的方法:

prompt():显示可提示用户输入的对话框。

alert():显示带有一段消息和一个人“确认”按钮的警告框。

confirm():显示带有一段消息以及“确认”按钮“取消”按钮的对话框。

close():关闭浏览器窗口。

open():打开一个新的浏览器窗口,加载给定URL所指定的文档。

setTimeout():用于在指定(以毫秒计)后调用函数或计算表达式。

setTneerval():按照指定的周期 (以毫秒计)数来调用函数或计算表达式。

Window对象常用窗口特征属性

height、width:窗口文档显示区的高度、宽度,以像素计。

left、top:窗口的x坐标y坐标,以像素计。

toolbar:yes|no|1|0:是否显示浏览器的工具栏,默认是yes。

scrollbars =yes|no|1|0:是否显示滚动条,默认是yes。

locationyes|no|1|0:是否显示地址栏,默认是yes。

status|no|1|0:是否添加地址栏,默认是yes。

menubar|no|1|0:是否显示菜单栏,默认是yes。

resizable|no|1|0:窗口是否可调节尺寸,默认是yes。

Window对象的常用事件:

onload:一个页面或一副图像完成加载。

onmouseover:鼠标指针移到某元素之上。

onclick:单击某个对象。

onkeydown:某个键盘按键被按下。

onchange:域的内容被改变。

History对象的方法:

back():加载History对象列表中的上一个URL。

forward():加载History对象列表中的下一个URL。

go():加载History对象列表中的某个具体URL。

Location对象的属性:

host:设置或返回主机名和当前URL的端口号。

hostname:设置或返回当前URL的主机名。

href:设置或返回完整的URL。

Location对象的方法:

reload():重新加载当前文档。

replace():用新的文档替换当前文档。

Document对象常用的属性:

referrer:返回载入当前文档的URL。

URL:返回当前文档的URL。

Document对象的常用方法:

getElementById():返回对拥有指定id的第一个对象的引用。

getElementsByName():返回带有指定名称的对象的集合。

getElementsByTagName():返回带有指定标签名的对象的集合。

write():向文档写文本、HTML表达式代码。

内置对象

系统的内置对象有Date对象、Array对象、String对象和Math对象等。

Date:用于操作日期和时间。

Array:用于在单独的变量名中储存一系列的值。

String:用于支持对字符串的处理。

Math:用于执行数学任务,包含了若干数字常量和函数。

Date对象:

1:创建日期对象

Date对象包含日期和时间两个信息,创建日期对象的基本语法有两种:

创建日期的基本语法1: var 日期实例化=new Date(参数);

创建日期的基本语法2: var 日期实例化=new Date();

Date对象的常用方法:

getDate():从Date对象返回一个月中的某一天,其值介于1到31之间。

getDay():从Date对象返回星期中的某一天,其值介于0到6之间。

getHours():返回Date对象的小时,其值介于0到23之间。

getMinutes():返回Date对象的分钟,其值介于0到59之间。

getSeconds():返回Date对象的秒数,其值介于0到59之间。

getMonth():返回Date对象的月份,其值介于0到11之间。

getFullYear():返回Date对象的年份,其值为4位数。

getTime():返回自某一时刻(2010年1月1日)以来的毫秒数。

DOM概述

什么是DOM

DOM是文档对象的缩写,和语言无关。它提供了访问、动态修改结构文档的接口,W3C制定了DOM规范,主流浏览器都支持。

使用Core DOM操作节点

访问节点:

使用getElement系列方法访问指定节点。

getElementById():返回对拥有指定id的第一个对象的引用。

getElementsByName():返回带有指定名称的对象的集合。

getElementsByTagName():返回带有指定标签名的对象的集合。

使用层次关系访问节点。

parenNode:返回节点的父节点。

firstChild:返回节点的首个节点。文本和属性节点没有父节点,会返回一个空数组,对于元素节点,若是没有子节点会返回null。

lastChild:返回节点的最后一个子节点,返回值同firstChild。

操作节点属性值

CoreDOM的标准方法包括以下两种:

getAttribute(“属性名”):获取属性值。

getAttribute(“属性名”,“属性值”):设置属性值

创建和增加节点:

创建节点

createElement(tagName):按照给定的标签名称创建一个新的元素节点

appendChild(nodeName):向以存在节点列表的末尾添加新的节点。

inserBefore(newNode,oldNode):向指定的节点之前插入一个新的子节点。

cloneNode(deep):复制某个指定的节点。

删除和替换节点

removeChild(node):删除指定的节点。

replaceChild(newNode,oldNode):用其他的节点替换指定的节点。

Table对象的属性和方法

属性:

rows[]:返回包含表格中所有行的一个数组。

rows[]用于返回表格中所有行的一个数组。

方法:

inserRow():在表格中插入一个新行。

deleteRow():从表格中删除一行。

数组

数组是具有相同数据类型的一个或多个值得集合

创建数组的语法:

var 数组名称=new Array(size);

数组的赋值的两种方式:

先声明在赋值

var province = new Array(4);

province[0]=“河北省”;

province[1]=“河南省”;

索引也可以使用标识(字符串),例如:

var province=new Array(4);

province[‘河北省’]=“河北省”;

province[‘河南省’]=“河南省”;

声明时同时初始化

var province=new Array(“河北省”,“河南省”,“湖北省”,“广东省”);

Array对象的常用属性和方法:

属性:

length:设置或返回数组中元素的数目。

方法:

join():把数组的所有元素放入一个字符串,通过一个分隔符进行分割。

sort():对数组的元素进行排序。

理 | 屠敏
出品 | CSDN(ID:CSDNnews)

一直以来,操作系统的「时间、日期、时区」,是让很多程序员在开发程序时比较敏感与特别关注的问题。

  • 还记得即将步入 2000 年的“千年虫”(Year 2000 Problem,简称“Y2K”)事件,由于早期的计算机配置比较低,那时为了节省空间就把年份只用后两位数表示,如 1999 就表示为 99,导致新千年时电脑把 2000 年认为是 1900 年,出现 Bug,进而引发各种各样的系统功能紊乱甚至崩溃。

  • 2012 年,有用户发现低内核版 Linux 开启 NTP 服务器会遇到闰秒 Bug,导致服务器重启。

  • 2016 年,很多网友“作了一把”,将 iPhone 的日期设置到 1970 年 1 月 1 日,无意中触发系统 Bug,一时间导致 iPhone 重启失败,手机直接变板砖。

就在近日,一个新的关于时间 Bug 出现在 Windows 系统中。据 Ars Technica 报道,有一位挪威数据中心的工程师 Simen 遇到了一个令人费解的时间 Bug, 它会导致 Windows Server 突然将系统时钟重置到未来 55 天。

时间 Bug 带来的混乱

事实上,这并不是 Simen 第一次遇到这个问题。

在去年 8 月,Simen 曾遇到过类似的错误,当时一台运行 Windows Server 2019 的机器将时钟重置到了 2023 年 1 月,但过了没多久又自动跳回来了。

后来,直到事件日志被清除后才发现这一问题,但那时无法分析具体是什么原因导致的。

现在,他又在一台运行 Windows Server 2016 的机器上遇到了这个问题。

对于普通用户而言,时间的错乱带来的短暂影响也许可以忽略不计。但是对于工程师而言,却是一个让人崩溃的存在。

Simen 的主要工作是在 Windows Server 维护一个路由表(存储在联网计算机中的电子表格(文件)或类数据库),这个路由表实时跟踪手机号码从一个运营商转到另一个运营商的过程。

当服务器出现时间 Bug 时,系统时钟跳到八周后,这就带来一个不可估量的后果,譬如,此前尚未迁移的号码被列入已经迁移、已经转移的号码被列为待处理状态,整个都乱掉了。

无独有偶

本来以为这只是一个特例,但是搜索一下,网络上遇到这个问题的工程师不在少数。

去年,有一位名叫 Ken 的工程师也发现了类似的“时间跳跃”现象,当时在 2-3 台服务器上,时钟时不时会跳跃到几周后,甚至有一次直接跳到了 2159 年。

据 Ars Technica 披露,Ken 在一封邮件中写道:“受此影响的服务器呈指数增长,越来越多。在 5000 台服务器(虚拟机)中,我们总共有 20 台左右的服务器(虚拟机)遇到过这种情况。这种情况通常发生在数据库服务器上。当数据库服务器在时间上发生跳跃时,就会造成严重破坏,只要服务器在时间上有如此大的偏移,备份也就无法运行。对于我们的客户来说,这一点至关重要。”

除了 Simen 和 Ken 之外,追溯到 2017 年,一位 Reddit 用户 zanatwo 发帖称他在一所大学工作,某一天,其发现校园内的几台 Windows 10 计算机开始出现错误的时间。这些计算机上显示的时间 Bug 完全是随机的,在某些情况下,他的设备时间直接跳到了 31 个小时之前。

通过深入分析,当时 Reddit 用户发现,时间变化与 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\SecureTimeLimits 中的 Windows 注册表键相关。进一步的调查显示,当一些人试图访问大学网站时,这些错误报告称网站使用的有效 SSL 证书无效。

Windows 官方发布的功能惹了祸?

经过排查之后,以上几位工程师将罪魁祸首统一定位到了 Windows 上一个鲜为人知的功能—— Secure Time Seeding(简称 STS)中。

这是微软在 2016 年引入 Windows 的功能,主要作用就是在 Windows 设备无法通过安全连接与时间服务器通信的情况下,改进对正确时间的记录。简单来看,这也是设备在断电情况下也能保证准确的时间。默认情况下,这一功能在 Windows 系统及服务器下是打开的。

从工作原理来看,为确定当前时间,STS 会调用 SSL(Secure Sockets Layer)握手过程中包含的一组元数据。具体来说,这些数据包括:

  • ServerUnixTime,日期和时间表示法,显示自 1970 年 1 月 1 日 00:00:00 UTC 时起已过去的秒数。

  • 从远程服务器 SSL 证书中获取的加密签名数据,显示该证书是否已根据所谓的 "在线证书状态协议 "机制被撤销。

在发布这一功能时,微软工程师在官方文档中写道,他们使用 ServerUnixTime 数据是 "假定它在一定程度上是准确的",但在同一句话中又承认它 "也可能是不正确的"。

为了防止 STS 根据单个不同步远程服务器提供的数据重置系统时钟,STS 会随机穿插 SSL 连接到多个服务器,以得出当前时间的可靠范围。

然后,该机制会将 ServerUnixTime 与 OCSP(Online Certificate Status Protocol,在线证书状态协议 )有效期合并,以产生尽可能小的时间范围,并为其分配置信度分数。

当分数达到足够高的阈值时,Windows 就会将数据归类为 STSHC(Secure Time Seed of High Confidence,高置信度安全时间种子)。然后,STSHC 用于监控系统时钟是否存在 "严重错误",并对其进行纠正。

尽管 STS 内建了检查和平衡机制,以确保其提供准确的时间估计,但长期以来工程师遇到的“时间跳跃”事件表明,该功能有时会做出误差数天、数周、数月甚至数年的胡乱猜测。

Ars Technica 报道的文章中,其分享了来自工程师 Ken 遇到时间跳跃时的具体截图。

第一张图片中的选定行上方的 "预计安全时间 "条目显示,Windows 预计当前日期为 2023 年 10 月 20 日,比系统时钟显示的时间晚四个多月。然后,STS 会更改系统时钟,使其与"目标系统时间 "中显示的错误的预计安全时间相匹配。

第二张图片显示了类似的情况,其中 STS 将日期从 2023 年 6 月 10 日改为 2023 年 7 月 5 日。

在遇到这一问题后,Ken 和 Simen 都向微软进行了反馈,遗憾的是,他们并没有得到实质性的回应与解决方案。

微软工程师个人曾发出警告:主动关闭 STS 功能

那要问有没有解决方法,其实去年一位微软 Windows 高级工程师 Ryan Ries 发过推文提供过用户,其写到“大家好,如果你们管理 Active Directory 域控制器,我想给你们一些非官方的建议,这完全是我的个人意见:在您的 DC 上禁用 w32time 的 STS。”

当有网友进一步询问原因时,Ryan Ries 表示,「因为在它咬你的屁股之前,这只是一个时间问题」。

这也不禁让人好奇,连微软自家工程师都觉得这个功能有问题,为什么官方还有做保留。

就在众人存疑时,微软在给 Ars Technica 的一份声明中写道:

STS 功能是一种基于启发式的计时方法,在某些软件/固件/硬件计时失效的情况下也有助于校正系统时间。该功能已在所有默认 Windows 配置中默认启用,并已证明在默认配置中发挥了预期功能。

每次部署的时间分配都是独一无二的,客户通常会根据自己的特殊需求来配置机器。鉴于 "STS"的启发式性质以及客户可能使用的各种部署,我们提供了禁用该功能的选项,以满足客户的需求。我们的理解是,在客户遇到 STS 问题的部署中,很可能存在独特、专有、复杂的因素,而这些客户并不能从目前实施的这一功能中受益。在这些个别情况下,我们只能建议在部署中禁用该功能。

具体来看,要禁用 STS,可以在受影响的机器上设置一个注册表项。这是 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config 目录中的 UtilizeSslTimeData 密钥,其类型为 REG_DWORD。如果设置为 0,则停用 STS。如果设置为 1,则可以重新激活该功能。

STS 的异常,有没有解决方案?

截至目前,似乎除了关闭此功能之外,并没有太过合适的解决方案,因此,很多人对于微软的回应并不买账。在 HN 上,网友也展开了激烈的讨论,甚至有人吐槽:是时候应该买块手表来核对服务器上的时间了!

另外,有网友 @theqmann 分析认为,「这听起来像是一种统计方法,如果在给定时间内收到 N 个时间戳相似的数据包/连接,就会改变时钟。我可以看到这样一个问题:一台 Windows Server 每分钟全天候提供数千或数百万个 OpenSSL 数据包,而它恰好随机接收到 N 个数据包,这些数据包彼此非常接近,足以满足统计阈值的要求。通过随机跳转,连续跳转十多次时间都是有可能的」。

@jmuguy 则表示:

在我做 IT 人员的这些年里,Windows Time 是我处理过的最烦人的事情之一。注册和取消注册 w32time,尝试不同的 NTP 服务器。试图弄明白为什么域系统无法从 DC 获取时间。这总让人感觉很......愚蠢。在设备上设置正确的时间肯定没那么复杂。事实证明,并不复杂,除非你使用的是 Windows 系统。有点讽刺的是,如今我唯一需要处理的 Windows 系统就是我的游戏电脑。它拒绝与 time.windows.com 同步。

除了 Windows 系统之外,还有人称在 Linux 中也遇到了同样的问题。

@nicolaslem 表示:

我的 Linux 笔记本电脑有时也会遇到类似的问题,把电脑从睡眠中唤醒时,时间会跳到 2077 年。我猜这是硬件故障,因为它并不经常发生,但一旦发生就会造成很大影响。我无法想象在生产服务器上发生类似情况会有多大影响。

你是否遇到过类似的问题?

参考:

https://arstechnica.com/security/2023/08/windows-feature-that-resets-system-clocks-based-on-random-data-is-wreaking-havoc/

https://news.ycombinator.com/item?id=37151220

https://www.reddit.com/r/sysadmin/comments/61o8p0/system_time_jumping_back_on_windows_10_caused_by/

ouseout和mouseleave的区别

二者都是鼠标移出。mouseout冒泡。 mouseleave不冒泡。(出去冒泡,离开不冒泡)

mouseout对应上面的mouseover ,mouseleave对应上面的mouseenter。

注册事件的第二种方法(监听法)

就是谁发生、怎么发生、发生了什么 的第二种表达方式。

谁发生.addEventListener(怎么发生,发生了什么的函数)
  • 怎么发生:这里的触发事件不带on,比如click
  • 发什么了什么的函数: function() { 要发生的事情 };
  • //例如上面的唐伯虎点秋香例子
    btn.addEventListener('click', function() {
    	alert('点秋香');
    })

    节点操作01

    • 改变元素内容
    element.innerText
    //从起始位置到终止位置的内容。但它去除html标签,同时空格和换行也会去掉
    element.innerHTML
    //起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行

    innerText 和 innerHTML的区别

    1. innerText 不识别html标签 非标准 去除空格和换行
    2. innerHTML 识别html标签 按照W3C标准 保留空格和换行
    3. 这两个属性都是可读写的,可以获取元素里面的内容。例如:
    <p>2333</p>
    <script>
    	var p = document.getElementByTagName('p');
    	console.log(p.innerText);
    	console.log(p.innerHTML);
    </script>

    常见元素的属性操作

    三种操作情况:

    innerText 、innerHTML 改变元素内容

    src、 href

    id、alt、title

    表单元素的属性操作

    利用DOM可以操作如下表单元素的属性:

    type , value , checked , selected , disabled

    <body>
    	<button>按钮</button>
    	<input type="text" value="输入内容" />
    	<script>
    		//1,获取元素
    		var btn = document.querySelector('button');
    		var inp = document.querySelector('input');
    		//2,注册事件--谁发生 怎么发生 发生什么
    		btn.addEventListener('click', function() {
    		//inp.innerHTML = '被点击了'; 这个是 普通盒子 比如div标签里面的内容被修改,不是value里的内容被改变
    		//表单里面的值 文字内容是通过valve来修改的
    			inp.value = '我被点击了';
    		//如果想要某个表单被禁用,不能重复点击disabled 我们想要这个按钮 button禁用
    		//btn.disbled = true; 这样就被禁用了
    		this.disabled = true;//这里的this就是btn,因为是btn发生的,这里的this就特指btn了。
    		//this指向的是发生的那个元素 btn
    		})
    	</script>
    </body>

    案例:京东登陆界面的密码表单输入密码时,默认不显示密码。点击小眼睛图标时,显示密码。再点击又不显示密码。


    //2,注册事件 谁发生 怎么发生 发生什么
    var flag = 0;
    eye.addEventListener('click', function() {
    	//每次点击 flag一定要变化
    	if(flag == 0) {
    		pwd.type = 'text';
    		eye.src = '---';
    		flag = 1;//这里就是要变化了。原来是0,这里就要变成1
    	} else {
    			pwd.type = 'password';
    			eye.src = '---';
    			flag = 0;//这里又变化了。原来是1,点过一次就变成0了
    		}
    })

    样式属性操作

    我们可以通过JS修改元素的大小、颜色、位置等样式。

    element.style = ’ ';行内样式操作

    element.className 类名样式操作

    注意:

    JS 里面的样式采取驼峰命名法 比如 fontSize , backgroundColor 。注意,这里没有连接的 - 了。

    JS修改style 样式操作,产生的是行内样式,css权重比较高。

    className 会直接更改元素的类名,会覆盖原先的类名。

    第3条里,如果原来的类名还想保留,那就可以这样做,假如原来的类名是class=‘first’ ,现在要用的是class='change’并且不想把原来的first类型替换掉,那就写成 元素.className = ‘first change’ 就阔以了。

    <body>
    	<div></div>
    	<script>
    		//1,获取元素
    		var div = document.querySelector('div');
    		//2,注册事件。谁发生 怎么发生 发生什么
    		div.onclick = function() {
    			//div.style里面的属性  采取驼峰命名法
    			this.style.backgroundColor = 'purple';
    			this.style.width = '200px';
    		}
    	</script>
    </body>

    这里是this是指向函数的调用者,即div在调用这个函数。 相当于div.style (如上图的div)

    如果调用者不是当前的元素,就不能用this了。(如下图function里的box.style 就不能写成this.style)

    因为是btn在调用函数,然后让box产生变化。 如果用了this,就是指btn在发生变化了。所以这里不能用this。

    当一个元素需要更改的样式较多时,适合用element.className来完成。

    <head>
    <style>
    .change {
    	background-color: purple;
    	color: #fff;
    	font-size: 25px;
    	margin-top: 100px;
    }
    </style>
    </head>
    
    <body>
    	<div>文本</div>
    	<script>
    		//当元素样式较多或者功能复杂的情况下,
    		//使用element.className获得修改元素样式,
    		var div = document.querySelector('div');
    		div.onclick = function() {
    			this.className = 'change';
    		}
    	</script>
    </body>

    JS排他思想

    如果有同一组元素,我们想要其中一个元素实现某种样式的情况下,不想让其他同样的元素跟着实现这种样式,就需要用到循环的排他思想算法:

    1. 所有元素全部清除样式(干掉其他人)
    2. 给当前元素设置样式(留下我自己)
    3. 注意顺序不能颠倒。首先干掉其他人,再设置自己。
    <ul class='baidu'>
    	<li><img src='1' /></li>
    	<li><img src='1' /></li>
    	<li><img src='1' /></li>
    </ul>
    <script>
    	//1,获取元素 
    	var imgs = document.querySelector('.baidu').querySelectorAll('img');
    	//console.log(imgs);
    	//2,循环注册事件
    	for(var i = 0; i < imgs.length; i++) {
    		imgs[i].onclick = function() {
    		//this.src 就是我们点击的图片的路径
    		//console.log(this.src);
    		//把这个路径this.src给body就可以了
    			document.body.style.backgroundImage = 'url(' + this.src + ')';
    		}
    	}
    </script>

    说白了,就是先让包括自己的所有人都不显示,然后再让自己显示。 这样在自己显示的时候,别人就不显示了。

    全选反选案例

    <script>
    	//1,全选和取消全选的做法: 
    	//让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
    	//获取元素
    	var j_acAll = document.getElementById('j_cbAll');
    	var j_tbs = document.getElementById('j_tb').getElementByTagName('input');
    	//即 选出下面所有的复选框
    	//注册时间 谁发生 怎么发生 发生什么
    	j_cbAll.onclick = function() {
    		//this.checked 它可以得到当前复选框的选中状态 
    		//如果是true 就是选中, 如果是false 就是未选中
    		console.log(this.checked);
    		for(var i = 0; i < j_tbs.length; i++) {
    			j_tbs[i].checked = this.checked;
    		}
    	}
    	//2,下面的复选框需要全部选中,上面全选才能选中做法:
    	//给下面所有复选框绑定点击事件,每次点击,都要循环看是否都选中了
    	for(var i = 0; i < j_tbs.length; i++) {
    		j_tbs[i].onclick = function() {
    			//flag控制全选按钮是否选中
    			var flag = true;
    			//每次点击下面的复选框都要循环检查这4个小按钮是否全被选中
    			for(var i = 0; i < j_tbs.length; i++) {
    				if( !j_tbs[i].checked) {
    					flag = false;
    					break;
    				//退出for循环 这样可以提高运行效率
    				//因为只要一个没有选中,剩下的就无需再循环判断了
    				}
    			}
    			j_cbAll.checked = flag;
    		}
    	}
    </script>
    //每次点击,都要循环

    操作属性

    自定义属性的操作

    获取属性值

    • element.属性 获取属性值
    • 作用:获取内置属性值,即元素本身自带的属性
    • element.getAttribute(‘属性’);
    • 作用:可以获得原有属性值,也可以获得自定义的元素值。主要获取自定义的属性 (标准) 我们程序员自定义的属性。

    获取、设置、移除元素属性的应用例子:

    <body>
    	<div id="demo" index="1"></div>
    	<script>
    		var div = document.querySelector('div');
    		//1,获取元素的属性值
    		//(1)element.属性
    		console.log(div.id);//demo
    		//(2)element.getAttribute('属性')
    		//程序员自己添加的属性,我们称为自定义属性,比如这里的 index
    		console.log(div.getAttribute('id'));//demo
    		console.log(div.getAttribute('index'));//1
    		//2,设置元素的属性值
    		//(1)element.属性 = ‘值’;
    		div.id = 'test';
    		div.className = 'navs';
    		//(2)element.setAttribute('属性','值');
    		//主要针对自定义属性
    		div.setAttribute('index', 2);
    		div.setAttribute('class', 'footer');
    		//class特殊 这里写的就是class 不是className
    		//3,移除属性 element.removeAttribute('属性');
    		div.removeAttribute('index');
    	</script>
    </body>

    属性操作案例(必须会写)

    <script>
    	//获取元素
    	var tab_list = document.querySelector('.tab_list');
    	var lis = tab_list.querySelectorAll('li');
    	var items = document.querySelectorAll('.item');
    	//for循环绑定点击事件
    	for(var i = 0; i < lis.length; i++) {
    		//开始给5个小li设置索引号index
    		lis[i].setAttribute('index',i);
    		lis[i].onclick = function() {
    			//1,上面的模块选项卡,点击某一个,当前这个底色会是红色,其他选项卡不变色。
    			//所以用到排他思想。干掉所有人,其余的li清除class这个类
    			for(var i = 0; i < lis.length; i++) {         		
    				lis[i].className = '';		
    			}
    			//留下我自己
    			this.className = 'current';
    			//2,下面的显示内容模块
    			var index = this.getAttribute('index');
    			console.log(index);
    			//干掉所有人 让其余的item 这些div 隐藏
    			for(var i = 0; i < items.length; i++) {
    				items[i].style.display = 'none';
    			}
    			//留下我自己 让对应的item显示出来
    			items[index].style.display = 'block';
    		}
    	}
    </script>

    关于自定义属性

    H5自定义属性

    自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。

    1.设置H5自定义属性

    H5规定自定义属性data- 开头做为属性名并且赋值。说白了就是,自定义属性要用data- 做开头。比如:

    <div data-index="1"></div>

    或者使用JS设置:

    element.setAttribute('data-index', 2)

    2.获取H5自定义属性

    1,element.getAttribute(‘data-index’) 兼容性好

    2,H5新增 element.dataset.index 或者element.dataset[‘index’] , ie11才开始支持,而且只能取data- 开头的自定义元素属性。

    如果自定义属性里有多个 - 连接的单词,我们获取的时候,采取驼峰命名法。如 div.dataset.listName 或 div.dataset[‘listName’]

    节点操作02

    网页中的所有内容都是节点(标签,属性,文本,注释,空格等),在DOM中,节点使用node来表示。

    HTML DOM树中的所有节点均可通过JS进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。

    一般地,节点至少拥有nodeType(节点类型),nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

    • 元素节点 nodeType 为1
    • 属性节点 nodeType 为2
    • 文本节点 nodeType 为3(文本节点包含文字,空格,换行等)

    我们实际开发中,节点操作主要操作的是元素节点。

    节点层级

    利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄弟层级关系。

    1,父级节点

    node.parentNode
  • parentNode属性可返回某节点的父节点,注意是最近的一个父节点(亲爸爸)
  • 如果指定的节点没有父节点,则返回null。
  • <div class="demo">
    	<div class="box">
    		<span class="erweima">X</span>
    	</div>
    </div>
    
    <script>
    	//1,父节点parentNode
    	var erweima = document.querySelector('.erweima');
    	//var box = document.querySelector('.box');
    	//得到的是离元素最近的父级节点(亲爸爸)
    	//如果找不到父节点,就返回null
    	console.log(erweima.parentNode);
    </script>

    2,子节点

    有两种获得方式,标准和非标准。

    第一种: parentNode.childNodes(标准)
    //虽然是标准的,但是不提倡使用

    parentNode.childNodes 返回包含指定节点的子节点的集合。该集合为即时更新的集合。

    注意:返回值里面包含了所有的子节点,包括元素节点,文本节点(文字,空格,换行等)等。

    如果只想要获得里面的元素节点,则需要专门处理。所以我们**一般不提倡使用childNodes** 。 专门处理需要的代码:

    var ul = document.querySelector('ul');
    for(var i = 0; i < ul.childNodes.length; i++) {
    	if(ul.childNodes[i].nodeType == 1) {
    		//即 ul.childNodes[i]是元素节点
    		console.log(ul.childNodes[i];
    	}
    }
    第二种: parentNode.children(非标准)
    //虽然是非标准,但是可以得到我们想要的元素节点,
    //所以推荐使用这个

    parentNode.children是一个只读属性,返回所有子元素节点,其余节点不返回。所以重点掌握这个方法。

    获取 第一个子元素和最后一个子元素

    实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而firstElementChild 和 lastElementChild又有兼容性问题。那么我们如何获取第一个子元素节点或最后一个子元素节点呢?

    解决方案:

    1.获取第一个子元素节点, parentNode.children[0];

    2,获取最后一个子元素节点,

    parentNode.children[parentNode.children.length - 1]

    这样既可以获得想要的元素节点,又不存在兼容性问题。

    节点操作案例:


    <script>
    	//1,获取元素
    	var nav = document.querySelector('.nav');
    	var lis = nav.children;//得到4个小li
    	//2,注册循环事件 点谁谁发生
    	for(var i = 0; i < lis.length; i++) {
    		lis[i].onmouseover = function() {
    			this.children[i].style.display = 'block';
    		}
    		lis[i].onmouseout = function() {
    			this.children[i].style.display = 'none';
    		}
    	}
    </script>

    节点层级--兄弟节点

    1. node.nextSibling返回当前元素的下一个兄弟节点,找不到则返回null 。同样,也是包含所有的节点。
    2. node.previousSibling返回当前元素上一个兄弟节点,找不到则返回null。同样,也包含所有的节点。
    3. node.nextElementSibling返回当前元素下一个兄弟元素节点,找不到则返回null。
    4. node.previousElementSibling返回当前元素的上一个兄弟元素节点,找不到则返回null。

    1和2 取兄弟节点的时候,会把空格文本节点也取到。不适合用。

    3和4取出来的确实是想要的兄弟节点,但是会有兼容性问题。

    如何解决兼容性问题?

    需要自己封装一个函数。

    function getNextElementSibling(element) {
    	var el = element;
    	while(el == el.nextSibling) {
    		if(el.nodeType === 1) {
    			return el;
    		}
    	}
    	return null;
    }

    不过兄弟节点用的较少。

    创建元素节点

    document.createElement('tagName');

    创建 由tagName指定的HTML元素。因为这些元素原先不存在,是根据我们的需求 动态生成的,所以我们也称为动态创建元素节点。

    添加节点:先创建,后添加

    1. node.appendChild(child)将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素。node是父节点,child是子级。
    2. node.insertBefore(child,指定元素)将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素。
    <body>
    	<ul>
    		<li>2333</li>
    	</ul>
    	<script>
    		//1,创建元素节点
    		var li = document.createElement('li');
    		//2,添加后节点 node.appendChild(child)
    		var ul = document.querySelector('ul');
    		ul.appendChild(li);
    		//添加前节点 node.insertBefore(child,指定元素);
    		var lili = document.creatrElement('li');
    		ul.insertBefore(lili,ul.children[0]);
    	</script>
    </body>

    发布留言板案例:

    <body>
    	<textarea name="" id=""></textarea>
    	<button>发布</button>
    	<ul>
    	</ul>
    	<script>
    		//1,获取元素
    		var btn = document.querySelector('button');
    		var text = document.querySelector('textarea');
    		var ul = document.querySelector('ul');
    		//2,注册事件 谁发生 怎么发生 发生什么
    		btn.onclick = function() {
    			if(text.value == "") {
    				alert('内容不能为空!');
    				return false;
    			} else {
    					//(1)创建元素节点
    					var li = document.createElement('li');
    					//先创建li 才能赋值
    					li.innerHTML = text.value;
    					//(2)添加节点
    					ul.insertBefore(li,ul.children[0]);
    				}
    		}
    	</script>
    </body>

    删除子节点

    node.removeChild(child)
    //举例:
    ul.removeChild(ul.children[0]);

    从DOM中删除一个子节点,返回删除的节点。

    复制(克隆)节点:先克隆,再添加

    node.cloneNode()
    //返回调用该方法的节点的一个副本。
    //这里的node是要被克隆的那个元素节点

    注意:

    1. 如果括号参数为空或者false,则是浅克隆,即只克隆节点本身,不克隆里面的子节点。
    2. 如果括号里面的参数为true,则是深克隆,会复制节点本身以及里面所有的子节点。
    <body>

    三种动态创建元素的区别

    1. document.write()
    2. element.innerHTML
    3. document.createElement()

    区别:

    • document.write()是直接将内容写入页面的内容流,但是文档流执行完毕,它会导致页面全部重绘。
    • innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘。
    • innerHTML创建多个元素效率更高,不需要拼接字符串,采取数组形式拼接,结构稍微复杂。
    • createElement()创建多个元素效率稍微低一点点,但是结构更清晰。
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="uft-8" />
    	</head>
    	<body>
    		<button>点击</button>
    		<div class="inner"></div>
    		<ul class="create"></ul>
    		<script>
    			//1,document.write()创建元素
    				var btn = document.querySelector('button');
    				btn.onclick = function() {
    					document.write('<div>2333</div>');
    				}
    				//2,innerHTML 创建元素
    				var inner = document.querySelector('.inner');
    				var arr = [];
    				for(var i = 0; i <= 10; i++) {
    					arr.push('<a href="">233</a>');
    				}
    				inner.innerHTML = arr.join(' ');
    				//3,document.createElement()创建元素
    				var create = document.querySelector('.create');
    				for (var i = 0; i <= 10; i++) {
    					var li = document.createElement('li');
    					create.appendChild(li);
    				}
    		</script>
    	</body>
    </html>

    DOM事件流

    • 事件流描述的是从页面中接收事件的顺序。
    • 事件发生时,会在元素节点之间按照特定的顺序传播,这个传播过程就是DOM事件流。

    事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。

    事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。

    注意:

    1,JS代码中只能执行捕获或者冒泡其中的一个阶段。二者只能选其一。

    2,onclick和attachEvent只能得到冒泡阶段。

    3,addEventListener()中function()后面的参数,如果是true,表示在事件捕获阶段条用事件处理程序;如果是不写参数或者参数是false,表示在事件冒泡阶段调用事件处理程序。

    4,实际开发中我们很少使用事件捕获,我们更关注事件冒泡。

    5,有些事件是没有冒泡的,比如 onblur,onfocus,onmouseenter,onmouseleave。

    事件对象

    什么是事件对象?

    eventTarget.onclick = function(event) { };
    或
    eventTarget.addEventListener('click', function(event) { })
    //这个event就是事件对象。可以写成e或者evt。
    //这个参数在前面学习中是没有写出来的。

    官方解释:event对象代表事件的状态,比如键盘按键的状态,鼠标的位置,鼠标按钮的状态。

    简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法。

    比如:

    1,谁绑定了这个事件。

    2,鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。

    3,键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。

    这个event是个形参,系统帮我们设定为事件对象,不需要传递实参过去。

    当我们注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(即事件处理函数)。

    兼容性问题

    事件对象的兼容性方案

    事件对象本身的获取存在兼容性问题:

    1,标准浏览器中是浏览器给方法传递的参数,只需要定义形参3 就可以获得到。 2,在IE6~8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找。

    解决:

    e = e || window.event;


    阻止事件冒泡的两种方式

    事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点。

    事件冒泡本身的特性,会带来坏处,也会带来好处,需要我们灵活掌握。

    阻止事件冒泡

    • 标准写法:利用事件对象里面的e.stopPropagation()方法
    • 非标准写法:IE6-8使用。 利用事件对象cancelBubble属性。

    常用的是标准写法。IE浏览器因为兼容问题,不经常用。如果用了非标准写法,可以调试一下兼容性:

    if(e && e.stopPropagation) {
    	e.stopPropagation();
    } else {
    	window.event.cancelBubble = true;	
    }

    用法:

    <body>
    	<div class="father">
    		<div class="son">son儿子</div>
    	</div>
    	<script>
    		//常见事件对象的属性和方法
    		//阻止冒泡 dom 推荐的标准 stopPropagation()
    		var son = document.querySelector('.son');
    		son.addEventListener('click', function(e) {
    		alert('son');
    		e.stopPropagation();//停止传播
    		e.canselBubble = true;//非标准 取消泡泡
    },false);
    var father = document.querySelector('.father');
    father.addEventListener('click', function() {
    	alert('father');	
    },false);
    document.addEventListener('click', function() {
    	alert('document');
    }
    	</script>
    </body>

    事件委托

    事件委托也称为事件代理,在jQuery里面称为事件委派。

    事件委托的原理

    不是每个子节点单独设置事件监听器,而是事件监听器在其父节点上,然后利用冒泡原理影响设置每个子节点。

    比如,给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。

    事件委托的作用

    我们只操作了依次DOM,提高了程序的性能。

    <body>
    	<ul>
    		<li>2333</li>
    		<li>2333</li>
    		<li>2333</li>
    		<li>2333</li>
    	</ul>
    	<script>
    		//事件委托的核心原理:给父节点添加监听器,
    		//利用事件冒泡影响每一个子节点。
    		var ul = document.querySelector('ul');
    		ul.addEventListener('click', function(e) {
    			//alert('2333');
    			//e.target 可以得到我们点击的对象
    			e.target.style.backgroundColor = 'pink';
    		})
    	</script>
    </body>

    鼠标事件对象

    event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象mouseevent和键盘事件对象keyboardevent。


    <style>
    	img {
    		position: absolute;
    		top: 2px;
    	}
    </style>
    <body>
    	<img src=''>
    	<script>
    		var pic = document.querySelector('img');
    		document.addEventListener('mousemove', function(e) {
    		var x = e.pageX;
    		var y = e.pageY;
    		console.log(x, y);//输出x 和 y坐标
    		//千万不要忘记给left和top添加px单位!
    		pic.style.left = x + 'px';
    		pic.style.top = y + 'px';
    		});
    	</script>
    </body>

    常用的键盘事件

    注意:

    1,如果使用addEventListener,就不需要加on

    2,三个事件的执行顺序是: keydown-keypress-keyup


    键盘事件对象


    注意:onkeydown和onkeyup不区分字母大小写,onkeypress区分字母大小写。

    在我们实际开发中,我们更多的使用keydown和keyup,它能识别所有的键(包括功能键)

    Keypress不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值。

    注意:keydown和keyup在文本框里面的特点:他们两个事件触发的时候,文字还没有落入文本框中。keyup事件触发的时候,文字已经落入文本框里面了。因为键已经松开了。

    案例:按下s键,搜索框获得焦点

    <body>
    	<input type="text">
    	<script>
    		//核心思路:检测用户是否按下了s键。
    		//如果按下了s键,就把光标定位到搜索框里面。
    		//使用键盘事件对象里面的keyCode,
    		//判断用户按下的是否是s键。
    		//搜索框获得焦点:使用js里面的focus()方法
    		var sch = document.querySelector('input');
    		document.addEventListener('keyup', function(e) {
    			if(e.keyCode == 83) {
    				sch.focus();
    			}
    		})
    	</script>
    </body>

    --------------------DOM---end------------------------

    BOM浏览器对象模型

    什么是BOM?

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

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

    BOM缺乏标准,JS语法的标准化阻止是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape(就是网景公司)浏览器标准的一部分。

    BOM构成

    BOM比DOM更大,它包含DOM。

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

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

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

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

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

    window对象的常用事件

    窗口加载事件

    这样就可以把js放在任何一个地方了,js代码都会执行了。

    window.onload = function() { }
    或者
    window.addEventListener('load', function() { })(推荐使用,因为没有次数限制)

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

    注意:

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

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

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

    另一种情况:(加载较慢的情况)

    document.addEventListener('DOMContenLoaded', function() { })

    DOMContentLoaded事件触发时,仅当DOM加载完成时,不包括样式表,图片,flash等等。

    IE9以上才支持。

    如果页面的图片很多的话,从用户访问到onload触发可能需要较长的事件,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded事件比较合适。

    调整窗口大小事件

    window.onresize = function() {}
    window.addEventListener('resize', function() {})

    window.onresize是调整窗口大小加载事件,当触发时就调用的处理函数。注意:1,只要窗口大小发生像素变化,就会触发这个事件。2,我们经常利用这个事件完成响应式布局。window.innerWidth是当前屏幕的宽度。

    两种定时器

    第一种定时器:setTimeout()定时器

    window.setTimeout(调用函数,延迟的毫秒数);

    setTimeout()方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。

    注意:

    1,window可以省略。

    2,这个调用函数可以直接写函数,或者写函数名, 或者 '函数名()'三种形式。但是不推荐最后一种写法。

    3,延迟的毫秒数可以省略,默认是0,如果写,必须是毫秒数。不需要带单位。

    4,因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

    //语法规范: window.setTimeout(调用函数,延迟时间);
    //setTimeout(function() {
    //	console.log('午时已到');
    //}, 2000);
    function callback() {
    	console.log('立即斩首');
    }
    setTimeout(callback, 3000);

    回调函数 callback

    window.setTimeout(调用函数,延迟的毫秒数);

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

    普通函数是按照代码顺序直接调用。

    而这个函数,需要等待时间,时间到了才能取调用这个函数,因此我们称为回调函数。

    简单理解:回调,就是回头调用的意思。上一件事干完,再回头调用这个函数。

    以前讲的element.onclick = function() {}或者element.addEventListener(‘click’, fn);里面的函数也是回调函数。

    停止定时器(让定时器停下来,别执行函数里的程序了)

    clearTimeout(定时器名字);

    window.clearTimeout(timeout ID)

    注意:1,window可以省略。2,里面的参数就是定时器的标识符。

    第二种定时器 setInterval()

    window.setInterval(回调函数,间隔的毫秒数);

    setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。

    这是与setTimeout()最大的不同。setTimeout()定时器只调用一次回调函数。

    注意:

    1,window可以省略。

    2,这个调用函数可以直接写函数,或者函数名或者采用字符串 ’ 函数名() ’ 三种形式。

    3,间隔的毫秒数可以省略,默认是0,如果写,必须是毫秒数,不用带单位。

    4,因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

    案例:自动倒计时

    <body>
    	<div>
    		<span class="hour">1</span>
    		<span class="minute">2</span>
    		<span class="second">3</span>
    	</div>
    	<script>
    		//1,获取元素
    		var hour = document.querySelector('.hour');
    		var minute = document.querySelector('.minute');
    		var second = document.querySelector('.second');
    		var inputTime = +new Date('2019-5-1 18: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>

    案例:发送短信验证


    JS执行机制

    JS是单线程:同一时间只做一件事。代码是从上到下一行一行的执行。

    同步和异步: 最新的js可以创建多个任务了。

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

    同步

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

    异步

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

    同步任务

    同步任务都在主线程上执行,形成一个执行线。

    异步任务

    JS的异步是通过回调函数实现的。 一般而言,异步任务有以下三种类型: 1,普通事件,如click,resize等 2,资源加载,如load,error等 3,定时器,包括setTimeout,setInterval等。

    异步任务相关回调函数添加到任务队列中,任务队列也称为消息队列。

    执行机制:任务分成同步任务和异步任务。先执行完同步任务,再去执行异步任务。

    1,先执行执行栈中的同步任务。

    2,异步任务(回调函数)放入任务队列中。

    3,一旦执行栈中的所有同步任务执行完毕,系统就会按照次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

    由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)。

    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对象的属性

    案例:获取URL参数数据:数据在不同网页中传递

    第一个页面:输入信息的界面

    <body>
    	<form action="index.html">
    		用户名:<input type="text" name="uname">
    		<input type="submit" value="登录" />
    	</form>
    </body>

    第二个页面:接收信息的界面

    <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对象的方法

    navigator对象:知道用户用了什么浏览器

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

    下面前端代码可以判断用户哪个中断打开的页面,实现跳转:

    if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobild|BlackBerry|IEMobild|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
    window.location.href = ""; //手机
    } else {
    	window.location.href = ""; //电脑
    }
    //把这个代码赋值到<script></script>里面就阔以了。
    //要查哪个网页地址,就把地址补齐到href里。

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

    history.back();history.forward();history.go(1);

    PC网页端特效

    知识点:

    1. offset
    2. client
    3. scroll
    4. 封装简单动画函数
    5. 网页轮播图

    offset系列属性

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

    • 获得元素举例带有定位父元素的位置
    • 获得元素自身的大小(宽度高度)
    • 注意:返回的数值都不带单位

    offset系列常用属性:

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

    • 获得元素举例带有定位父元素的位置
    • 获得元素自身的大小(宽度高度)
    • 注意:返回的数值都不带单位

    offset系列常用属性:


    只有上和左,没有下和右。

    offset和style的区别

    案例:获取鼠标在盒子内的动态位置

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200427005033196.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3R1emkwMDdh,size_16,color_FFFFFF,t_70)

    元素可视区client系列

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

    注意和offset的区别。clientWidth是不含边框的。

    立即执行函数

    <body>
    	<script>
    		//1,立即执行函数:不需要调用,立马能够子级执行的函数
    		function fn() {
    			console.log(1);
    		}
    		fn();
    		//2,写法也可以传递参数进来
    		//(function() {})()或者(function() {}())
    		(function(a, b) {
    			console.log(a + b);
    			var num = 10;
    		})(1, 2);//第二个小括号可以看作是调用函数
    		(function sun(a, b) {
    			console.log(a + b);
    			var num = 10;//局部变量
    		}(2, 3));
    		//3,立即执行函数最大的作用就是 独立创建了一个作用域,
    		//里面所有的变量都是局部变量,不会右命名冲突的情况。
    	</script>
    </body>

    元素滚动scroll系列

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


    常用的是 element.scrollTop和element.scrollLeft。

    window.pageXOffset 和 window.pageYOffset属性,返回文档在窗口左上角水平和垂直方向滚动的像素。

    pageXOffset设置或返回当前网页相对于窗口显示区左上角的X位置。pageYOffset设置或返回当前页面相对于窗口显示区左上角的Y位置。

    pageXOffset 和pageYOffset属性相当于scrollX和scrollY属性。

    这些属性是只读的。

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

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

    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

    动画函数封装

    动画实现原理:

    实现步骤:

    1. 获得盒子当前的位置
    2. 让盒子在当前位置加上1个移动距离
    3. 利用定时器不断重复这个操作
    4. 加一个结束定时器的条件
    5. 注意:此元素需要添加定位,才能使用element.style.left
      因为要让盒子脱离标准流,所以要添加定位。
      函数封装:
    <script>
    	//简单动画函数封装obj目标对象 target 目标位置
    	function animate(obj, target) {
    		var timer = setInterval(function() {
    			if (obj.offsetLeft >= target) {
    			//运动到一定距离,就停止计时器
    				clearInterval(timer);
    			}
    			obj.style.left = obj.offsetLeft + 1 + 'px';
    		}, 200);
    	}
    	var div = document.querySelector('div');
    	//调用函数
    	animate(div, 300);
    </script>

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

    如果多个元素都使用这个动画函数,每次都要var声明定时器。我们可以给不同元素使用不同的定时器(自己专门用自己的定时器)


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

    <script>
    	//var obj = {};
    	//obj.name = 'andy';
    	//简单动画函数封装obj是目标对象 target 是目标位置
    	//给不同的元素指定了不同的定时器
    	function animate(obj, target) {
    		obj.timer = setInterval(function() {
    			if(obj.offsetLeft >= target) {
    				clearInterval(obj.timer);
    			}
    				obj.style.left = obj.offsetLeft + 1 + 'px';
    		}, 200);
    	}
    	var div = document.querySelector('div');
    	var span = document.querySelector('span');
    	//调用函数
    	animate(div,300);
    	animate(span, 200);
    </script>

    改进版:

    <script>
    	//当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
    	//解决方案就是 让我们元素只有一个定时器执行
    	//先清除以前的定时器,只保留当前一个定时器执行
    	clearInterval(obj.timer);
    	function animate(obj, target) {
    		obj.timer = setInterval(function() {
    			if(obj.offsetLeft >= target) {
    				clearInterval(obj.timer);
    			}
    				obj.style.left = obj.offsetLeft + 1 + 'px';
    		}, 200);
    	}
    	var div = document.querySelector('div');
    	var span = document.querySelector('span');
    	//调用函数
    	animate(div,300);
    	animate(span, 200);
    </script>

    案例:淘宝网页轮播图,也叫焦点图

    节流阀

    防止轮播图按钮连续点击造成播放过快。


    节流阀目的:当 上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。


    核心思路:利用回调函数,添加要给变量来控制,锁住函数和解锁函数。

    //开始设置一个变量 
    var flag = true;
    if(flag) {
    	flag = false;
    	do something...//关闭水龙头
    }
    //利用回调函数,动画执行完毕后,
    flag = true;//打开水龙头

    案例:淘宝侧边栏的返回顶部

    window.scroll(x,y) 整个窗口滚动到文档中的特定位置。

    x是距离文档左边的距离,y是距离文档顶部的距离。x和y都不带单位。