DOM与BOM

103 阅读14分钟

BOM常用对象:

最重要的只有三个点:定时器、客户端存储技术、event
1.history对象:保存了当前窗口的历史记录(过去的url)
  前进:history.go(正数)
  后退:history.go(负数)
  刷新:history.go(0)
2.***location对象:保存了当前窗口的正在打开的url
  一个url由几部分组成:
  1、协议:http(未加密)/https(加密)/ftp(传输文件的)/ws(直   播)... - 前两个都属于叫做 请求 - 响应 模型,专门用于实现网站开发
  2、主机号|域名|IP地址:域名是需要花钱购买的,主机号|IP地址是免费的,127.0.0.1才叫主机号,只能自己访问自己
  3、端口号:https默认端口为443,http默认端口为80,只有默认端口可以省略不写
  4、***文件的相对路径|路由:百度加密了 - 如果以后学习了服务器端,我们可以配置好一些选项,用户就可以再自己的电脑上看到我们的东西了
  5、***查询字符串|请求消息:前端传输到后端的东西,前端对后端说的话(请求),就是form表单get提交带来的东西
  协议://域名:端口号/路由?请求消息
  属性:获取url的5个部分的内容,但是不需要记忆,你直接输出location对象即可查看
      协议:location.protocol
      域名:location.hostname
      端口号:location.port;
      路由:location.pathname;
      请求消息:location.search;
   方法:
     跳转:location="新url";
     跳转后,禁止后退:location.replace("新url");
     刷新:location.reload();
3.*****DOM:原本DOM是可以操作一切结构化文档的,但是再某个版本升级过后,为了方便各类程序员将DOM分为了3分布:
  1、核心DOM:无敌的,既可以操作HTML又可以操作XML,但是语法相对比较复杂
  2、HTML DOM:只能操作HTML,不能访问一些自定义的东西,但是语法比较简单	
  3、XML DOM:只能操作XML,被淘汰了,被JSON数据格式代替了
  1、*查找元素:2方面
   1、关系:前提:至少要找到一个元素,才可以调用关系网
   父:elem.parentNode;
   子:elem.children; - 集合
   第一个儿子:elem.firstElementChild;
   最后一个儿子:elem.lastElementChild;
   前一个兄弟:elem.previousElementSibling;
   后一个兄弟:elem.nextElementSibling;
  2、直接找元素:2大类:通过HTML的特性去查找元素
   1、var elems=document.getElementsByXXXXX();//返回的是一个动态集合HTMLCollection
   2、第二大类:2个:通过CSS选择器去查找元素
     1、var elem=document.querySelector("任意css选择器");
     缺点:只能找到单个元素,如果匹配到多个,也只会返回第一个,没找到,返回null,一次只能操作一个元素
     2、***var elems=document.querySelectorAll("任意css选择器");
       优点:
          1、找到了是一个集合,没找到是一个空集合
          2、复杂查找时,非常的舒服
          3、返回的是一个静态集合NodeList

	
   2、操作样式:
   1、*内联样式:
\获取:elem.style.css属性名; - 只能获取内联样式
\设置:elem.style.css属性名="css属性值";

  2、样式表样式 - 此生不见
//获取你想要操作的样式表
var sheet=document.styleSheets[i];
//获取此表中的所有样式规则
var rules=sheet.cssRules;
//去数出你要操作的时第几个样式规则
var rule=rules[i];
//操作			console.log(rule.style.background);
rule.style.background="purple"
3、操作属性:
1、*获取属性值:
核心DOM:elem.getAttribute("属性名");
HTML DOM:elem.属性名;
2、*设置属性值:
核心DOM:elem.setAttribute("属性名","属性值");
HTML DOM:elem.属性名="属性值";
3、删除属性:设置属性值为空字符串,确实某些属性可以算是删除了,但是只是删除了属性值,属性名还在,而有的属性哪怕只有一个属性名,也会具有作用!(checked、readonly、href)
 *核心DOM:elem.removeAttribute("属性名");
HTML DOM:elem.属性名="";
4、判断有没有:垃圾,只能判断有没有,不能判断是什么,推荐用elem.getAttribute("属性名")去获取到值然后自己再写比较运算进行判断
核心DOM:elem.hasAttribute("属性名");
HTML DOM:elem.属性名!="";
4、操作内容 - 你是学习完整的,innerHTML/innerText/value
5、如何创建元素以及上树:3步
  1、创建空标签:
    var elem=document.createElement("标签名");
  2、为其设置必要的属性和事件
    elem.属性名="属性值";
    elem.on事件名=function(){}
  3、上树:3种
     1、*父元素.appendChild(elem);//在父元素末尾追加一个子元素elem
     2、父元素.insertBefore(elem,已有子元素);//在父元素里面追加一个子元素elem,但是会放到你的已有子元素的前面
     3、父元素.replaceChild(elem,已有子元素);//在父元素里面追加一个子元素elem,但是会替换掉你的已有子元素
6、删除元素:elem.remove();

递归

何时使用:专门用于【遍历层级不明确】的情况 - DOM树和【数据】
	如何使用:
		function 函数名(root){
			1、root第一层要做什么直接做
			2、判断有没有下一层,如果有下一层再次调用此方法,但是传入的实参是自己的下一层
		}
                函数名(实际的根元素)
            算法:深度优先算法!优先遍历当前节点的子节点,子节点遍历完毕才会跳到兄弟节点
	缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存,我们只在一个情况使用它:【遍历层级不明确】
            递归 vs 纯循环
		递归:优点:简单易用
		           缺点:性能低

		纯循环:优点:性能高
		              缺点:难得很
         2、绑定事件:3种方式
	1、在HTML页面上书写事件属性
		<elem on事件名="函数名()"></elem>
		缺点:
			1、不符合内容(HTML)与样式(CSS)与行为(JS)的分离
			2、无法动态绑定,一次只能绑定一个元素
			3、不支持绑定多个函数对象

	2、*在JS中使用是件处理函数属性
		elem.on事件名=function(){操作}
		优点:
			1、符合内容(HTML)与样式(CSS)与行为(JS)的分离
			2、动态绑定,一次可以绑定多个元素
			3、不存在兼容性问题
		缺点:
			1、不支持绑定多个函数对象 - 个人觉得不算缺点

	3、*在JS中使用事件API:如果不用考虑老IE的话,还是不错的
		主流:elem.addEventListener("事件名",callback)
		老IE:elem.attachEvent("on事件名",callback)
		兼容:
			if(elem.addEventListener){
				elem.addEventListener("事件名",callback)
			}else{
				elem.attachEvent("on事件名",callback)
			}
		优点:
			1、符合内容(HTML)与样式(CSS)与行为(JS)的分离
			2、动态绑定,一次可以绑定多个元素
			3、支持绑定多个函数对象
		缺点:
			具有兼容性问题:老IE不能使用

		兼容性你别怕:
			1、我会教你一切兼容性的方法
			2、现在的趋势不是PC端而是移动端,不存在IE浏览器

扩展:select&option 只有他们可以简化创建和上树!
      select.add(new Option("innerHTML","value"))

属于BOM的重点只有3个:定时器+客户端存储技术+event(事件对象):

1、事件周期:从事件发生,到所有是件处理函数执行完毕的全过程:
	3个阶段:
		1、捕获阶段:由外向内,记录着要发生的事件有哪些
		2、目标优先触发:目标元素->当前点击的实际发生事件的元素
		3、冒泡触发:由内向外,依次执行我们之前记录着的要发生的事件

2、*****获取事件对象event:
	主流:会自动作为事件处理函数的第一个形参传入e
	老IE:event;
	兼容:event;//第一次见到小三上位,不光老IE可以用,主流也可以用这句话

	得到了事件对象event可以做什么呢?
		1、***获取鼠标的坐标/位置:3种
			获取鼠标相对于屏幕的坐标:e.screenX/Y;
			获取鼠标相对于浏览器窗口/客户端/文档显示区域的坐标:e.clientX/Y
			获取鼠标相对于网页的坐标:e.pageX/Y;

		2、***阻止冒泡:
			主流:e.stopPropagation();
			老IE:e.cancelBubble=true; 
			兼容:e.cancelBubble=true;//第2次见到小三上位,不光老IE可以用,主流也可以用这句话 	

		3、*****事件委托/利用冒泡:开发中常用,提升网页性能
			优化:如果多个子元素定义了 相同 或 相似的事件操作,那么最好只给【父元素】绑定一次
			为什么:每一次绑定一个事件函数,其实都是创建了一个事件对象,创建的对象越多,网页的性能越差。
			淘汰了this,他水性杨花,当前元素
			认识一个新的人叫做【目标元素】:实际触发事件的元素
			主流:e.target;
			老IE:e.srcElement;
			兼容:e.srcElement;//第3次见到小三上位,不光老IE可以用,主流也可以用这句话 

		4、***阻止浏览器的默认行为:比如:a标签默认可以跳转、提交按钮可以提交form表单,右键自带一个弹出菜单框,F12自带一个控制台,F5自带刷新...
			主流:e.preventDefault();
			老IE:e.returnValue=false;
			兼容:e.returnValue=false;//第4次见到小三上位,不光老IE可以用,主流也可以用这句话 
                
	        新学了事件:
			1、右键事件 - window.oncontextmenu
			2、键盘事件:一般用于游戏开发比较多 + 都要搭配上键盘的键码
				window.onkeydown - 按下和按住都会触发,而且任何按键都会触发!
				window.onkeypress - 按下和按住都会触发,但是只有数字、字母、回车、空格可以触发,其他不行!
				window.onkeyup - 松开的时候才会触发,而且任何按键都会触发!比手速的游戏才会用他。
					
		5、***获取键盘的键码
			e.keyCode - 可以获取到按了哪个键了,每个键都有自己对应的键码,但是不需要记忆,要么输出看,要么百度看e.keyCode表
1、事件的取消绑定:
	1、如果你用的elem.on事件名=()=>{},那么你想要取消绑定:elem.on事件名=null
	2、如果你用的elem.addEventListener("事件名",f1),那么你想要取消绑定:
		elem.removeEventListener("事件名",f1),事件名和回调函数,【必须和添加时一摸一样,是同一个】
2、*****this的指向:水性杨花,指向非常的多
	1、单个元素绑定事件,this->这个元素
	2、多个元素绑定事件,this->当前触发事件的元素
	3、箭头函数中的this->外部对象
	4、***函数中的this->当前正在调用函数的这个人
	5、定时器的this->window

3、*****ES5强制改变this的指向:- 笔试面试中,开发中偶尔也会用到
	call/apply:临时的替换了函数之中的this - 借用
		语法:
			1、函数名.call(借用的对象,实参,...) - 单独传入每个实参 
			2、函数名.apply(借用的对象,arr) - 只能传入一个实参,要求必须是一个数组:apply其实悄悄会将数组打散

		强调:call/apply,相当于立刻调用函数,是会立刻执行的,而且会还给别人,才叫借用

	bind:永久的替换了函数中的this - 买
		语法:var 新函数=函数名.bind(指定对象,永久的固定的实参);
		3件事:
			1、创建了一个和原函数功能完全相同的新函数
			2、将新函数中的this永久绑定了为指定对象,别人都借不走
			3、将新函数的部分参数永久固定的
		强调:
			1、bind绑定的新函数没办法被call/apply再次借走!
			2、买是不会立刻调用的,需要自己手动调用一下

	以后哪怕不是自己的方法,也可以使用:个人推荐:借,白嫖!
		三个固定套路:
			1、Math.max/min.apply(Math,arr);
			2、类数组转为普通数组:
				老方法:接住=Array.prototype.slice.call/apply(类数组)
				新方法:接住=Array.from(类数组)
   ES5 - 严格模式:很严格 - 可以在任意作用预的顶部写上一句话:"use strict";
		1、全局污染会报错
		2、将静默失败升级为报错!

ES6:大版本-语法变化很大:

1、学过了:
		1、*let 变量名=值;

		2const 常量名=值;

		3、*箭头函数:简化一切的回调函数(没有函数名、也没有自调过),function去掉,()和{}之间添加=>,形参一个,省略小括号,函数体一句话,省略大括号,如果函数体一句话并且是returnreturn和{}都省略

	4、*模板字符串:可以直接识别变量,不需要用+运算再去拼接了,而且实现了一个简单的JS的环境,甚至支持再里面使用API做操作
		`我的名字叫${name}`

	5、*****解构赋值
	              	顾名思义:解析结构再进行复制 - 赋值的新方式,并且得到了增强!
	              	如果赋值符号,左右两边的结构是一样的,他就会悄悄的解开/脱掉结构再一一进行赋值
		如何使用:
			1、类似数组的解构赋值
				var [a,b,c]=[1,2,3];
				console.log(a);
				console.log(b);
				console.log(c);

			2、类似对象的解构赋值
				var {a,b=默认值,c}={a:1,c:3}
				console.log(a);
				console.log(b);
				console.log(c);

			3、调用函数时,传递实参的顺序无所谓了 - 往往很多框架之中!都会用到这个解构赋值
				function zwjs({name,age=默认值,hobby}){
					return `我的名字叫${name},今年${age}岁,喜欢${hobby}`;
				}
				console.log(zwjs({age:18,hobby:"吃饭",name:"袍哥"}));

			4、函数的返回的结果,可以有多个了!
				function f1(){
					var a=1;
					var b=2;
					return [a,b];
				}
				var [a,b]=f1();
				console.log(a);
				console.log(b);

			//只要以后见到:方法名({里面放着很多很多的的键值对,那么他的底层就是用到了ES6的解构赋值,键值对写入的顺序其实是随意的})
			//见识一下layUI.js

	6、新的循环:for...of 垃圾:
		for(var v of arr){
			v - 当前值
		}

		缺点:
			1、因为没有提供过下标,不能操作原数组,只能返回新数组
			2、只能遍历索引数组,不能遍历hash数组(也不能遍历对象)

	7SetMap:两个新的数据类型
		1、*Set:有一点点用,类似于数组的一种数据格式,但是远不如数组牛逼(没几个API,能做的事少) - 【去重数组,然后再转回数组】
			[...new Set(arr)];
			... - 扩展运算符,可以脱掉数组/对象的衣服
			不需要记忆set任何的API,完全比不上数组的API

		2Map:垃圾:类似于对象的一种数据格式,完全不如对象

正则表达式:定义字符串中字符出现规则的表达式

何时使用:切割、替换、【验证】
	如何使用:语法:/正则表达式/;
		1、最简单的正则就是关键字原文:"no"	->	/no/后缀
			后缀:g:找全部		i:忽略大小写
		2、备选字符集:/[备选字符集]/;
			强调:
				1、一个中括号,只管一位字符
				2、问题:正则表达式默认只要满足了就不管后续了,而我们做验证的人,希望的是用户从头到尾完全按照我们的要求来,希望完全匹配
				     解决:前加^后加$,两者同时使用,代表要求从头到尾【完全匹配】 - /^[备选字符集]$/;
			特殊:如果备选字符集中ASCII码是连续的,那么可用-省略掉中间部分
				比如:
					一位数字:[0-9]
					一位字母:[a-zA-Z]
					一位数字、字母、下划线:[0-9A-Za-z_]
					一位汉字:[\u4e00-\u9fa5]
					一位数字、字母、下划线、波浪号、汉字:[0-9A-Za-z_~\u4e00-\u9fa5]

					除了xxx之外的:[^0-9] - 很少使用,范围太广了
					
		3、预定义字符集:前辈们提前定义了一些字符集,为了方便程序员开发 - 简化了备选字符集
			一位数字:\d
			一位数字、字母、下划线:\w
			一位空白字符:\s	-    什么叫空白字符:空格、制表符、换行

			一位除了换行外的任意字符:.		-	很少使用,范围太广了

		建议:优先使用预定义字符集,预定义满足不了再用备选字符集补充
		问题:不管是备选字符集,还是预定义字符集,一个都只管一位

		4、量词:规定一个字符集出现的次数
			1、有明确数量:
				字符集{n,m}:前边相邻的字符集最少出现n个,最多出现m个
				字符集{n,}:前边相邻的字符集最少出现n个,多了不限
				字符集{n}:前边相邻的字符集必须出现n个

			2、无明确数量:
				字符集?:前边相邻的字符集,可有可无,最多1个
				字符集*:前边相邻的字符集,可有可无,多了不限
				字符集+:前边相邻的字符集,至少一个,多了不限

		5、选择和分组:
			选择:在多个规则中选一个,选择往往都要和分组进行搭配
				规则1|规则2
			分组:将多个字符集临时组成一组子规则
				(规则1|规则2)

		6、指定匹配的位置
			开头:^
			结尾:$
			*特殊:两者如果同时使用,前加^后加$,表示从头到尾要求完全匹配 - 只要你做【验证】

		7、密码强度验证:2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字?
			/^[0-9A-Za-z]{2,4}$/
			预判公式:
				(?![0-9]+$) -> 不能全由数字组成,可能有大写、小写、汉字、日文、韩文、特殊符号...
				(?![0-9a-z]+$) -> 不能全由数字组成,也不能全由小写组成,也不能全由数字和小写的组合组成,可能有大写、汉字、日文、韩文、特殊符号...
				(?![0-9A-Za-z]+$) -> 不能全由数字组成,也不能全由小写组成,也不能全由数字和小写的组合组成,也不能全由数字和大写的组合组成,也不能全由大字和小写的组合组成,也不能全由数字和大写和小写的组合组成,

			//2-4,可以输入数字、字母、但是必须出现一位大写和一位数字的组合?
				var reg=/^(?![0-9a-z]+$)(?![A-Za-z]+$)[0-9A-Za-z]{2,4}$/;
			//2-4,可以输入数字、字母、但是必须出现3者的组合?
				var reg=/^(?![0-9a-z]+$)(?![A-Za-z]+$)(?![A-Z0-9]+$)[0-9A-Za-z]{2,4}$/;

支持正则的字符串API:

1、*切割:var arr=str.split("固定切割符"/RegExp);

	2、*****替换:很有可能出现在笔试面试中,而且真实开发也会遇到
		1、基础替换法:
			var newStr=str.replace(RegExp,"新内容");

		2、高级替换法:
			var newStr=str.replace(/[卧我握窝][槽肏操草曹糙去]+/g,function(key,i,str){
//				console.log(key);//关键字
//				console.log(i);//关键字的下标
//				console.log(str);//原文本身
				return a.length==2?"**":"***";
			});

		3、格式化:
			var idCard="500103198602215933";
			var reg=/(\d{6})(\d{4})(\d{2})(\d{2})(\d{4})/;
			var newStr=idCard.replace(reg,function(a,b,c,d,e,f,g,h){
				//在replace的时候,如果正则中出现了分组,那我们会得到更多的形参
				//在形参key的后面就会出现n形参,具体有多少个,看你有多少个分组
				//第1个分组获得的内容回保存到第2个形参之中
				//第2个分组获得的内容回保存到第3个形参之中
				//第3个分组获得的内容回保存到第4个形参之中
				//...
				//倒数第二个是下标
				//倒数第一个是原文
				return `${c}${d}${e}日`;
			})
		

3、*正则对象:
	创建:
		1、直接量:var reg=/正则表达式/后缀;
		2、构造函数:var reg=new RegExp("正则表达式","后缀");

	API:
		验证:var bool=reg.test(str);
		true->验证成功	false->验证失败
 扩展:
边输入边判断:input.oninput - 每次内容改变就会触发(选做)
鼠标按下:onmousedown
鼠标松开:onmouseup