在自定义对象中,大部分是比较复杂的,一般用于高级开发中。常用的对象如下:
array(数组)对象:
普通对象:
| 属性名 |属性值 |
| name | jiojidoj |//属性名任意
数组对象
| 索引 | 元素 |
| 1 | 456 |//索引为数字,并且按顺序排列,从零往后延伸
构造函数创建数组对象:
var array=new Array();
//向数组中添加元素
数组[索引]=元素(值)
//获取数组长度
数组长度:array.length//是最大索引+1;
非连续的数组,会空置很多数组的位置;除非必要不然不要创建非连续的数组;
如果修改了length属性,就会增加计算数组的长度,空间就会变大。如果减少数组长度,空间会减小,会删除后面的元素。
向数组的最后一个索引添加元素:arr[arr.length]=值;
使用字面量创建数组对象:
var arr=[
]
//数组时中括号创建,对象是大括号创建。
使用字面创建数组时,可以在创建时,就可以创建数组元素。
索引是从0开始计算的。
var arr =new Array(123,456,789);
也可以通过构造函数创建数组对象。
var arr=[10]//创建只有值为10的数组;
var arr=new Array(10)创建一个长度为10的数组;
一般数组的长度在里面没有什么限制,可以在js中添加数组长度。
数组中的元素可以是任意的数据类型(包括对象);
调用数组中的函数arr[索引]();
调用对数组中的对象arr[索引].属性名或者arr[索引].方法名()
数组里还可以放数组:二维数组、三维数组等都可以实现;
数组对象的四个方法:
push():该方法可以向数组末尾添加一个或多个元素,并返回新数组的长度。
可以将想要添加的元素,作为方法的参数传递给数组;
该方法会将数组的新的长度返回;
向较于arr[arr.length]这个可以一次添加多个值;
pop():该方法会删除数组的最后一个元素。并将删除元素作为返回值返回。
unshift():向数组开头添加一个或多个元素,并且返回数组新的长度。向前面插入元素之后,其他元素的索引会依次调整。
shift():删除数组开头的第一个元素,并将删除元素作为返回值返回。
数组的遍历:
所谓数组的遍历,就是将数组中元素都取出来。
for(var i=0;i<arr.length;i++){
console.log(arr[arr.length]);
}
遍历数组找到满足条件的元素,放到新的数组中返回;
function getAdult(arr){
var newArr=[];
var p=arr[i];
for(var i=0;i<arr.length;i++){
if(条件){
newArr.push(p);
}
}
return newArr;
}
forEach();这个方法是支持ie8以上的浏览器;如果需要兼容ie8就不要使用forEach,移动端就不用紧。
forEach()需要函数作为参数;
arr.forEach(匿名函数);//如果使用普通函数的话会污染作用域,所以使用匿名函数最为方便;数组中有几个元素就执行几次函数。
每次浏览器都会将浏览器以实参的形式传递到函数中。浏览器会在回调函数创建三个参数,第一个参数是当前正在遍历的元素,第二个参数是遍历的索引号,第三个参数是整个数组对象。
arr.forEach(function(value,index,array){});
slice和splice:
slice ()可以用来提取数组中的元素。
slicu(start,end)//start,开始位置end,结束位置;
arr.slice(1,3);该方法不会改变原数组,而是将截取到的元素封装到一个新的数组中返回参数;
在start开启索引在end关闭索引。
如第二个参数可以省略不写,表示截下剩余全部;
索引也可以传递负值,表示从数组末尾倒数几个数开始或者关闭索引。
splice()用于删除,添加数组中的指定元素。它会对原数组有影响;
多个参数:
第一个表示删除开始索引;
第二个表示删除的数量;只是添加元素的话可以直接将第二个元素设置为0;
第三个参数开始及其以后,;会作为新元素插入到开始索引(第一个参数)的前面;
去除数组的重复元素:splice (嵌套for循环);
for(var i=0;i<arr.length;i++){
console.log(arr[i]);
for (var j=i+1;j<arr.length;j++){
if(arr[i]==arr[j]{
arr.splice(j,1);
j--;//后面元素顶上来,会跳过删除的元素后面一个元素;需要再比一次;}
)
}
}
concat()连接两个或者多个数组,返回新的数组,不会对原数组产生影响;
join():这个方法可以将数组直接转换成字符串,不会对原数组产生影响,而是将转换的结果作为返回值返回。、
在join传递第一个参数,会将数组元素作为这个参数作为数组元素之间的连接返回,如果不指定,默认使用逗号,作为连接符;
reverse()颠倒数组的顺序,翻转数组,该方法会直接修改原数组。
sort()也会影响原数组,它默认会按照unicode编码排序;
所以如果想对纯数字的数字进行排序,这种默认的情况就不行了,它会将123,首先用第一个字符做排序,123,1234,2,23;
sort(function(a,b){return a-b;})
//a表示在前的元素,b为在后的元素,如果返回值大于0,就会交换位置,如果返回等于0,不换位,如果返回负值则不交换位置。a-b>0可见的这是升序排列;
函数方法call和apply;这是函数对象的方法;fun函数结构fun()函数功能;
fun.call();
fun.apply();
fun();
都是调用函数:
在调用call和apply可以将一个对象指定为第一个参数;
fun.call(obj),也就是说函数的对象是obj;
call()/apply()可以修改这个函数的this;
fun()不行;
fun.call(对象,参数,参数)这里的参数是原函数所要传递的参数;
fun.apply(对象,[参数,参数])参数需要封装到数组中;
call()和apply()的区别在于是否需要封装到数组中;
arguments:
在调用函数是,浏览器默认会传入两个隐含的参数,一个是this,另一个就是封装实参的对象arguments;
arguments:是一个类似于数组的对象,它也可以通过索引来操作对象,也可以获取长度,在调用函数时,我们传递的实参都会在arguments中保存;
arguments[0]第一个实参,我们即使不定义形参也可以调用实参
arguments还有一个属性:arguments.callee这个属性的对应的函数对象,就是当前这个函数对象;
Date对象:
在js中使用date对象来表示一个时间;
创建一个Date对象:
var d=new Date();
如果直接使用构造函数创建一个Date对象,则会封装为当前代码执行的时间;
//创建一个指定时间
var d2= new Date("15/10/2020 16:20:59");
//年份需要填写完整的位数,不然ie浏览器会出错
var date=d2.getDate();//获取当前对象为几号;1——31;
var day= d2.getDay();//获取当前对象为周几; 0——6;0表示周日
var month=d2.getMonth()://获取当前时间返回的月份0——11;0表示1月
var year=d2.getFullYear();//返回当前对象的年份;
var time =d2.getTime();//获取当前时间的时间戳,指的是从格林威治1970年1月1日0点0分0秒到现今所经历的毫秒数;方便保存,不然在计算机硬件中各种进制的数需要耗费大量的资源;一般时间都是从时间戳转换过来的;
注意这里的是格林威治时间,一般设置时间是本地时间的多少年多少月,如果设置1970年1月1日0时0分0秒会有时区的间隔;
利用时间戳测试代码的执行性能:
var d=new Date();
var start=d.getTIme();
代码
var end=d.getTime();
代码消耗约end-start秒
Math对象:
Math和其他的函数不同,他不是构造函数,它属于一个工具类不用创建对象,它里面封装了数学运算相关的属性和方法;
Math.PI表示圆周率;相对于自己写的要更精确一点;
abs()可以用于一个数的绝对值;
ceil()对数进行上上舍入;也就是向上取整;小数位只要有值就会自动进一;
floor()对数进行向下取整;小数部分就会舍去;
parseInt对字符串,floor()是对数值的效率更高;
round()对一个数进行四舍五入取整;
random()可以生成一个0到1的随机数;
//生成一个x到y的随机数:如果只是rando,()*(y-x)但是不可能生成x和y的,可以使用Math.round(x+Math.random()*(y-x));就可以创建0和10的啦;
max()/min()最大值最小值。
pow(2.3)2的3次方;
sqrt()平方根
包装类:
在js中提供三个包装类,可以将基本数据类型数据,转换成对象;对象比基本数据类型功能要强大一些;
String()转换成string对象
Number()转换成number对象
Boolean()转换成boolean对象
var x=new String(2)
基本对象比基本数据类型更加强大;
注意:在实际应用中一般不使用基本数据类型对象,在进行比较时,可能会出现意想不到的错误。对象保存对象空间的索引,而且对象转换成布尔值都是true;
当我们对一些基本数据类型的值去调用属性和方法时;浏览器会临时使用包装类将其转化成对象,然后在调用对象的属性和方法,调用完之后再转换成基本数据类型;
var s=1223;
s=s.toString();
s.hello=hei;//加进去属性之后,对象就直接被销毁了;所以s.hello的值为undefined;
基本数据类型能调用对象的属性和方法;
字符串的方法:
在底层中字符串是字符数组保存的,所以可以使用length属性查找对应的字符;
charAt():返回字符串中的指定位置的字符,根据参数的索引获取指定的字符;
charCodeAt():返回字符串中的指定位置的字符编码;
fromCharCode():根据字符编码获取字符;
String.fromCharCode()
concat():将两个字符串拼接一个新字符串返回,不会对原字符串做出修改;
indexOf()该方法可以检索一个字符串中是否含有指定内容;如果有返回指定内容首次出现的索引;
注意indecOf()的第二个参数可以指定开始查找位置,意思是说只要检查到第二个参数大于之前使用的indexOF返回的值,就能查到字符在字符串中出现的所有位置。
lastIndexOf();从后往前查找,返回值和indexOf()相同 第二个参数也是可以选的。
slice();同样不会影响原字符串;
substring()和slice()用法相同,但是substring()里面的参数不接受,自动转化成负值,而且能够自动调整参数的位置。
substr()和splice类似:参数第一个参数是开始截取位置,第二个参数是截取长度;
split()将字符串拆分成数组和join()功能相反,将会根据字符串拆分数组,
参数表示按照什么符号拆分数组,一般为“,”;不会影响原字符串
str.split(",");
toUpperCase()转换成大写,不会改变原字符串
toLowerCase()转换成小写,不会改变原字符串
正则表达式:
检查用户输入的对不对(格式,符号等);比如检查电子邮件的格式;
邮件设置的规则:通过正则表达式来实现;
计算机根据正则表达式是否符合规则,或者将符合规则的内容提取出来;
创建正则表达式的对象;
var reg=new RegExp("正则表达式","匹配模式");
构造函数创建正则表达式:
var str="检查对象";
reg.test(str);
检查str
test()用来检查字符串是否符合正则表达式的规则;符合返回true否则返回false;
匹配模式可以作为第二个参数:
i是否区分大小写;
g是否是全局匹配;
使用字面量创建正则表达式:
var 变量=/正则表达式/匹配模式;
使用字面量创建会更简单,而构造函数会更加灵活;
/a|b/搜索a或b; |
/[a-z]/搜索a到z任意小写字母。 []包裹的内容都是或的关系
/[A-z]/任意字符
/a[b-e]c/搜索abc acc adc aec
/[^ab]/搜索除了a或b ^
字符串和正则相关的方法:
split(): 将字符串拆分成数组;
根据任意字母去拆分,方法中可以传递一个正则表达式去拆分字符串;
split([A-z]);这个方法及时不全部匹配也都是全局的
search()可以搜索字符串中是否含有指定内容;如果搜索到内容则返回搜索内容的索引,否则返回-1;这个只能查找第一个,即使设置全局匹配也没用
match()根据正则表达式,将符合条件的内容都提取出来。
默认情况下match()会搜索到第一个内容,找到后就停止检索;
我们可以设置正则表达式为全局匹配模式,这样就能匹配所有内容,
可以给正则表达式设置多个匹配模式,且顺序无所谓;
match()会将匹配的结果封装到一个数组中返回,即使值查询到一个结果;
提取一些有用的信息;
replace()可以将字符串中指定的内容替换成新的内容;
replace()第一个是替换的内容,默认只替换一个,可以设置全局匹配;如果想删除,可以通过空串替换;
str.replace(a,b);
正则表达式的语法:
量词,我们可以通过量词来设置一个内容出现的次数;{n}搜索它前面一个字符出现n次
var reg=/a{n}/;//搜索a出现n次;
var reg1=/(ab){n}/; abababab,搜索这种形式的n次,使用小括号对前面内部所有字符搜索n次;
{1,3}出现一次到三次;{m,n}出现m到n次;{m,}m次以上;
+至少一个,相当于{1,}
*表示0个或多个
?表示0个或1个
^中括号中表示除了,在外部表示以什么为开头;
$表示结尾
. 表示任意字符就连@都能检查到,这样就没有办法检测它本身就是一个单纯的点,可以使用转义字符 \. 表示单纯的点;还有如\也需要写\\,在字符串中也需要使用两个\\
当然这是使用字面量创建的;
如果是在构造函数时,由于她的参数是字符串,外面还有一层正则表达式,如果想写一个\.表示单纯的点 那么就需要写\\.;
如果是^a$表示a即使开头也是结尾,所以只能有1个a;如果表示以a开头以a结尾^a|a$;
创建一个表达式检测字符串是否是一个合法的手机号;
1.不能以一开头
2.第二位3到9;
3.三位以后任意数字且只用9个;
^1[3-9][0-9]{9}$ //$这里的表示结束,这里的^和$就限制了字符串必须完全符合正则表达式的要求,不然使用test就有很大挑战如"feuhiah13098909389jiodn"返回
true
使用test()
\w任意字母、数字、_
\W除了字母、数字、_
\d任意数字
\D除了数字
\s空格
\S除了空格
\b单词边界
\B除了单词边界\ 单词\
单词边界:
当搜索/child/
而字符串中有children时,它两不是一个单词,但是如果没有单词边界,这无法判断到底是child本身,还是包含children;
需要使用/\child\/
去除字符串中的空格:
可以使用空串来替换空格:
str.replace(/\s/g,"");//去除所有空格;
^\s开头一个空格;需要写开头多个空格\s*$,需要使用全局模式
str.replace(/^\s*|\s*$/g,"");
邮件的正则表达式:
一般格式:jioaj486@djio.com.cn
还有特殊符号的.jiod@jiofa(网址字母或者数字).com.cn
任何字母数字下划线。任意字母数字下划线@任意字母数字.任意字母{2到5位}.任意字母{2到五位};
/ ^\w{3,} (\.\w+)* @ [A-z0-9]+ (\.[A-z]{2,5}) {1.2} $/;
DOM简介:文档对象模型
js通过dom 操作html文档,只需要了解dom就能随心所欲的修改web页面;
文档表示的是就是整个的HTML网页文档
对象表示将网页中的每一个部分转换为一个对象
模型:使用模型来表示对象之间的关系,这样方便我们获取对象
文档
html
head body
titile meta { 大量模型 }
HTML DOM树 :
(Node)节点是构成网页中的基本组成部分;nodeName nodeType nodeValue
文档节点:整个html文档 document 9 null
元素节点:html文档中的html标签 标签名 1 null
属性节点: 元素的属性 属性名 2 属性值
文本节点: 文本内容 #text 3 文本内容
可以通过nodeType区分不同的节点类型;
通过DOM树可以查找不同的节点:节点可以通过修改改变文档的内容;
事件的简介:
就是用户和浏览器交互的行为;点击按钮、关闭窗口、移动鼠标;
我们可以在事件对应的属性中设置一些js代码,这样事件就能被触发,代码就会被执行;
οnclick="alert("hello第一次见面")"
var btn=document.getElementById("button");
btn.οnclick=function(){
};
//绑定一个单击事件绑定的函数,我们称为单击响应函数;
文档的加载
由于代码是一行一行执行的,如果js的触发事件在btn前面(此时btn没有定义,这时候会发生错误),所以需要将代码放在获取的节点后面,这样就可以确保页面加载完毕后执行,这样不容易产生错误;
onload事件是在整个页面加载完成时触发;
window.οnlοad=function(){alert("nihao");}
如果非要将js代码放在前面或者需要将代码到页面加载之后执行,可以将执行代码放到window.οnlοad=function(){ 代码 }中
但是先加载js不使用,就有点浪费网络资源了,最好写在下面。不过写在上面也有好处,就是很好改js容易维护。根据需求来写。而且有些代码需要在加载页面之前就要启动也需要写在前面;
dom查询:
document.getElementById("");
通过id属性获取的一个对象
document.getElementsByTagName("")
通过标签名获取一组对象(返回一个类数组对象,但不是一个数组)可以通l过length属性查询它的长度,通过获取对象的[索引]访问不同的数组对象;
document.getElementsByName("");
通过name属性获取一组对象(也是返回一个类数组对象,但不是一个数组)可以通过length查询它的长度,通过获取对象的[索引]访问不同的数组对象;
innerHTML:可以通过这个属性获得元素内部的html代码;对于自结束标签没有意义;
属性的获取:获取元素.属性就能访问相应属性.id name value这种直接元素.属性名只有class不能采用这种方式,读取class时需要使用元素.classname;(本来是不想让用户来获取class的)
info="一共有"+arr.length+"页,这是第"+index+1+"页";//这里是的+是拼串操作,如果想要加1需要将index+1用括号包裹起来
info="一共有"+arr.length+"页,这是第"+(index+1)+"页";
获取元素节点的子节点:
通过元素节点调用 元素节点.getElementsTagName()方法//之前的对象是文档对象,是从整个页面查询的。这个是在元素节点下面找;
返回当前节点的指定标签名后代节点;
childNodes属性(一组元素,类数组对象)://可以通过索引确定子节点,修改内容
表示当前节点的所有子节点;包括文本、注释、属性的所有节点 元素(子元素)间的空白被当成文本节点,注意在ie8及其以下没有将空白当成文本节点。一般标签之间都留有默认的空白。
children属性://可以通过索引确定子节点,修改内容
获取当前元素的所有子元素(一组元素,类数组对象):它不包括文本节点、注释节点;更合理一点;
firstChild属性:表示当前节点的第一个子节点;ie8不支持
获取当前节点的第一个子节点:包括文本节点;
firstElementChild:
获取当前节点的第一个子节点:不包括文本节点;
lastChild属性:表示当前节点的最后一个子节点;ie8不支持
获取当前节点的最后一个子节点:包括文本节点;
lastElementChild:
获取当前节点的第一个子节点:不包括文本节点;
获取父节点和兄弟节点:
parentNode:父节点,获取父节点
子节点.parentNode()
previousSibing:前一个兄弟节点:也可能获取到空白文本节点
previousElementSibing:前一个兄弟元素节点;
nextSibing:后一个兄弟节点:也可能获取到空白文本节点
nextElementSibing:后一个兄弟元素节点;
一直获取按钮这个一个重复性的工作,可以使用定义解决这个问题;
绑定单击响应函数:
function myClick(idStr,fun){
var btn=getElementById(idStr);
btn=fun;
}
idStr:表示传递的id
fun:单击响应函数
innerText属性:可以获取元素内部的文本内容:它会自动将内部html标签去除;
文本节点的文本内容就是nodeValue:可以通过子节点.nodeValue查看文本内容,相较于innerHTML,innerText要麻烦很多,知道意思就行。
全选/全不选:
var checkAllBox=document.getElementById("checkedAllBox");
checkAllBox.οnclick=function(){
for(var i=0;i<items.length-1;i++){
items[i].checked=this.checked;//根据自身是否选中决定其他元素是否选中
}
}
其他元素全选,让全选按钮点亮;或者其他元素没有全选让全选灭掉;
for(var i=0;i<items.length;i++){
checkAllBox.checked=ture;
for(var j=0;j<items.length;j++){
if(!items[i].checked){
checkAllBox.checked=false;
break;//不用继续判断剩余的按钮了
}
}
}
dom查询的剩余方法:
获取body本身;
方法一:document.getElementByTagname()[0];
方法二:document.body
获取html:
document.documentElement;
获取all;
var all=document.all;
all.length=6
var all=document.getElementByTagName("*");
all代表页面中的所有元素;
还有一种是获取class属性的,但是这种方法不支持ie8及其以下;(获取一组元素节点对象)
var box1=document.getElementByClassName("box1");
获取box1中的div
document.querySelector(.box1 div);
可以根据选择找相应的对象,功能特别强大;这个方法在ie8中可以使用,虽然没有上面的方法,可以使用这种方式查找;
使用这个方法只会返回一个元素(即便有多个满足条件);这是一种局限;
document.querySelectorAll(.box div);这个也支持ie8,但是不同的是,它会将查询到的所用元素节点封装到一个数组中
即使只有一个元素节点,它也会返回一个数组;
dom增删改查:
创建元素节点:createElement();
document.createElement();它需要一个标签名做参数,将会根据该标签名创建元素的节点对象;
并且将创建的对象作为返回值返回。
var li=document.createElement("li");
创建文本节点:createTextNode();
document.createTextNode();它需要一个文本内容来作为参数,创建相应的文本节点。并将新的节点返回。
var text=document.createTextNode("dkop");
向父节点中添加子节点:父元素.appendChild();
li.appendChild(text);
获取页面存在父元素:
city.appendChild(li);在页面添加节点;
removeChild();删除指定子节点;
父节点.removeChild(子节点)
子节点.parentNode.removeChild(子节点),删除自己;更常用
replaceChild();使用新节点替换旧节点
父节点.replaceChild(新节点,旧节点)
insertBefore()
在指定子节点前插入新的节点;这个方法是父节点调用的
city.insertBefore(li,li);
父节点.insertBefore(新节点,旧节点)
也可以通过:
innerHTML增删改等相关操作,且比较简单;但是这种方法会比上面一种消耗更大,相当于将整个父节点和它所有的兄弟节点都发生了更改。
上一种只对自己有影响。
添加删除记录:
超链接默认是为了跳转,有时候需要刷新页面的时候会将事件绑定在a元素上;
//删除<tr>中的员工
function delA(){
var allA=document.getElementsByTagName("a");
for(var i=0;i<allA.length;i++){
all[i].οnclick=function(){
var tr=this.parent.parent;//这里不能使用allA[i],因为响应函数在被调用的时候才会执行,而这里for循环已经执行完毕了,也就是i为allA.length+1;这是后调用allA[i]就没有结果了。
var name=document.getElementsTagName("td")[a];
var flag=confirm("确认删除"+name+"吗?");
if(flag){
tr.parent.removeChild("tr");
}
}
}
}
//添加员工;
<tr>
<td>name:</td>
<td>text:</td>
<td>salary:</td>
<td><a></a></td>
var btn=document.getElementById("addbutton");
btn.οnclick=function(){
//如果提交按钮在表单中,还需要在内部先取消默认按钮;
var name=document.getElementById("name");
var text=document.getElementById("text");
var salary=document.getElementById(salary");
var tr=createElement("tr");
var a=createElement("a");
a.href="javascript:void()"
var ntd=createElement("td");
var nte=createElement("td");
var nsal=createElement("td");
var ndel=createElement("td");
var cname=createTextNode(name);
var ctext=createTextNode(text);
var csal=createTextNode(salary);
var cdel=createTextNode("delete");
ntd.appendChild(cname);
nte.appendChild(ctext);
nsal.appendChild(csal);
a.appendChild("cdel");
ndel.appendChild(a);
tr.appendChild(ntd);
tr.appendChild(nte);
tr.appendChild(nsal);
tr.appendChild(ndel);
//获取table:
var tab=documentElement('tab")//这天添加的是table里tbody外,而一般浏览器会添加一个tbody;这样就和之前的元素节点放在不同的地方了;
// tab.appendChild(tr);
//所以需要准确的添加到tbody中
var tbod=tab.getElementByTagName("tbody");
tbod.appendChild(tr);
修改之前的单击响应函数,因为这是重新添加的内容;
delA();
为可简化代码:可以修改成innerHTML输入:但是注意这里修改的不是tbody这个父节点;而是先添加一个子节点tr再向其中使用innerHTML属性,这样就不会影响整个tbody;
var tr=document.createElement("tr");
tr.innerHTML="<td>"+name+"</td>"+ "<td>"+text+"</td>"+ "<td>"+salary+"</td>"+ "<td><a>delete</a></td>";
但是这里的超链接对象没有被创建,没有绑定单击响应函数便没有办法删除。
可以使用。
var a=tr.getElementsByTageName("a");
a.οnclick=delA;
操作内联样式:
var box1=document.getElementById("box1");
box1.style.width=120px;
box1.style.background-color=red;//这里的background-color中-在js中是不合法的,所以需要将-后面的字符改成大写。
例如:
borderTopWidth:
backgroundColor:
我们通过js中style属性修改的样式是内联样式,有较高的优先级;所以之前说不要在样式中使用!important;
通过style属性能读取内联样式,但是不能读到样式表中的样式。(能修改,不能读取)
读取元素的样式:
可以使用
元素.currentStyle.样式名 //获取当时显示的样式。如果没有该样式会显示默认值
但是这种方式只有ie支持:其他浏览器不支持;
在其他浏览器可以使用:getComputedStyle()这个只有ie8以下不支持,其他浏览器都支持
这是window的一种方法;需要两个参数
第一个需要获取样式的元素,第二个可以传递一个伪元素,一般设置为null
使用需要getComputedStyle(obj,null).width;
这个方法会返回一个对象(封装了当前元素的样式)
通过该对象.样式名;
可以查看他的当前样式,如果获取的样式没有任何样式,则会返回当前的真实的值,而不是默认值;如果没有设置 width他不回复auto而是具体的值;
设置一个兼容的函数:
function getStyle(obj,name){
//没有必要判断浏览器的版本,只要看有没有getComputedStyle方法,由于该方法返回的是一个对象,所以有那么必然是true,但是如果直接写getComputedStyle判断该变量的话需要从全局中寻找,最终还是会报错。所以这么写不行;但是加了window就会将这个方法变成window的一个属性,也就不会报错
if(window.getComputedStyle){
return getComputedStyle(obj,null)[name];//对象的调用方法有两种一种是对象名.属性 还有一种是类似于数组的索引对象名[索引]}
else{
return obj.currentStyle[name];}
return -1;
}
简化:
function getStyle(obj,name){
return window.getComputedStyle?getComputedStyle(obj,null)[name]:obj.currentStyle[name];
}
通过上面两个获取的对象是不能修改的,只能通过style属性去修改样式的值;
其他样式相关属性:
clientWidth:返回可见宽度(包括内容区和内边距不包括外框和外边距)
clientHeight:返回可见高度(包括内容区和内边距不包括外框和外边距)
以上参数是直接返回数字,可以进行计算,不带有px;由于这是计算值(多个值混合的),所以这些属性是只读的;
offsetWidth:返回元素整个宽度
offsetHeight:返回元素整个高度
offsetParent:定位父元素,如果父元素没有开启定位,就会返回祖先元素body,它返回的是离当前元素最近的开启定位的祖先元素;可以用于指导修改样式;
offsetLeft:相对于定位元素的水平偏移量
offsetTop:相对于定位元素的垂直偏移量
scollHeight:滚动高度;
scollWidth:滚动宽度;
scollLeft:滚动条到左侧的距离;
scollTop:滚动条到顶端的距离;
scollHight-scollTop=clientHeight;这样表示滚动条拖动到底部;有时候需要让用户拉动到底部才能操作其他内容;比如刷新网页,协议勾选等;
如果设置表单项disabled="disabled"表示表单项不可用;
可以设置将滚动条滚动到底是才能到底时disabled="false";需要使用的标签是下一步按钮和checkbox;
当滚动条滚动时触发检测滚动条是否滚动到底(onscoll);
创建事件:
p标签上''info"绑定滚动条;
var info=document.getElementById("info");
var inps=document.getElementsByTagName("input");
info.onscoll=function(){
if(info.clientHeight==scollHeight-scollTop){
inps[0].style.disabled=false;
inps[1].style.disabled=false;
}
}
事件对象:当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进相应函数;
在事件对象中封装了当前时间相关的一切信息,比如键盘的输入鼠标的移动,鼠标的点击,窗口的变化等等;
onmousemove:鼠标移动事件;
元素节点.οnmοusemοve=function(event){
var x=event.clientX;
var y=event.clientY;
}
clientX:鼠标指针的水平位置距离左边,但是ie8的event保存在window中所以需要使用window.event.clientX,火狐不支持这种方式 client是相当于浏览器的可见窗口
clientY:鼠标指针的垂直位置距离上边,但是ie8的event保存在window中所以需要使用window.event.clientY,火狐不支持这种方式 client是相当于浏览器的可见窗口
pageX:是获取鼠标相对于当前位置的横坐标,不兼容ie8
pageY:是获取鼠标相对于当前位置的纵坐标,不兼容ie8
解决事件对象兼容性问题:
解决方法和上面的getComputedStyle类似;
if(!event){
event=window.event;
}
简化:
event=event||window.event;
大多数浏览器有event所以使用event作为主要window.event作为防止出错的备案;
div跟随鼠标移动:
pageX/pageY不支持ie8;
一般使用
clientY=scollTop+Top+"px";
clientX=scollLeft+Left+"px";
等式左边clientX/clientY用来设置鼠标;
等式右边设置可以移动的对象;
chrome认为浏览器的滚动条是body的
firefox认为浏览器的滚动条是html的;
scollTop=document.body.scollTop||document.getElement.scollTop;
scollLeft=document.body.scollLeft||document.getElement.scollLeft;
事件的冒泡(bubble):
所谓的冒泡就是事件向上传导,当后代的事件被触发,向上的祖先元素的事件也会被触发。
先触发后代,然后是父元素,最后是祖先元素。
在开发中,冒泡大多数都是有用的。比如如果在一个顶范围内自由移动,可以通过冒泡从其他元素上经过。
如果不希望发生冒泡,可以通过事件取消冒泡直接event.concelBubble=true;注意之前要使用事件的兼容;这个表达式没有兼容性问题;
事件的委派:
之前我们给每一个超链接绑定单击响应事件,需要使用for循环遍历,而绑定之后的添加的新的超链接还需要重新绑定;这样实在太麻烦,影响性能;
我们希望只绑定一次事件即可,即使元素是后来添加的。
我们可以尝试将事件共同的祖先元素。而这个方法就是事件的委派。这样当我们后代元素触发时,会自动通过冒泡触发祖先元素,从而触发事件,通过减少事件的委派次数,提高程序的性能。
event.targent表示事件触发的对象
但是这个祖先元素可能包含不想触发事件的元素。可以通过在触发元素上绑定一个class属性假设为link;最后通过祖先元素触发事件进行判断:
if(event.target.className=="link"){触发此事件};但是这里的link有隐患,如果其中一个有多个classs属性,那么就和"link"不等,导致事件触发失效,可以使用正则表达式解决此类问题。/^[link]{1}|\slink\s|\slink$/;
事件的绑定:
通过响应函数只能当对同一个元素进行绑定同一个响应函数,绑定多个的话,后一个函数会将前一个覆盖掉;
可以通过
btn.addEventListener("click")// 这种方式可以为一个元素相同事件,绑定多个响应函数,它会按照事件绑定的顺序进行;它里面的this对象是触发事件的对象
参数:事件,事件的字符串,不用on;回调函数,当事件被触发是会调用;是否在捕获阶段触发事件,需要一个布尔值,一般为false;
去除事件:
removeEventListener("btn");
这种方法不支持ie8及其以下的浏览器;
可以使用attachEvent();这种方法也可以同时绑定多个事件,但是它是按照后绑定的先执行;它里面的this是window
两个参数:事件,字符串需要on;回调函数
dispatchEvent("btn");去除事件
兼容函数:
function bind(obj,eventStr,callback){
//需要统一方法
//需要统一event
//需要统一this
//执行顺序,也可能需要统一
if(obj.addEventListener)
{obj.addEventListener(eventStr,callback,false);}
else{
//解决this的方法,通过匿名函数call()指定obj;匿名函数是window调用的但是callback是obj调用的
//obj.attachEvent("on"+eventStr,callback);
obj.attachEvent("on"+eventStr,function(){callback.call(obj);})
}
}
事件的传播流程:
事件的传播,对于事件的传播网景公司和微软有不同的理解;
微软公司认为事件应该从内而外传播,也就是说事件应该在冒泡阶段执行;
网景公司认为事件应该从外往内传播的,也就是从祖先元素传递到内部阶段,这就是事件的捕获阶段;
w3c采用两种方案,将事件传播分为三个阶段;
1.捕获阶段:在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是此时不会对事件进行触发;
2.目标阶段:事件捕获到目标;
3.冒泡阶段:事件从目标开始向祖先元素触发事件;
如果希望在捕获事件阶段就触发事件,可以是第三个参数设置为true;ie8及其以下没有捕获这个阶段。
拖拽:
拖拽的步骤:
当鼠标按下时,元素可以被拖动;onmousedown
当鼠标移动时,元素跟着鼠标指针移动;onmousemove
当鼠标鼠标松开时,元素会停留在当前位置onmouseup
var box1=document.getElementById("box1");
box1.οnmοusedοwn=function(event){
box1.setCapturn&&box1.setCapture();
//box1.οnmοusemοve=function(event){
};
//box1.οnmοuseup=function(event){
box1.οnmοuseοver=null;
};
//上面的这个事件是给box1绑定的,会有一定的bug,比如当鼠标移动到兄弟元素上,那么就会失去这个事件的触发;所以需要将事件绑定在document上;
var ol=event.clientX-box1.offsetLeft;
var ot=event.clientY-box1.offsetTop;
document.οnmοusemοve=function(event){
//需要将鼠标指针相对于box1位置不会发生变化;之前使用clientX=Left;只能获取鼠标指针在box1左上角的位置;
//需要从点击事件时就求出偏移量(鼠标到box1左上角的位置);
var left=event.clientX-ol;
var top=event.clientY-ot;
box1.style.left=left+"px";
box1.style.top=top+"px";
};
document.οnmοuseup=function(event){
document.οnmοuseοver=null;//此时这个事件并没有取消,所以还会被触发,所以需要取消该事件:document.οnmοuseup=null;
document.οnmοuseup=null;
};
return false;
};
//这里还有一个问题,就是当我们去在一个页面去拖拽内容时,浏览器会默认去搜索引擎搜索内容;如果不希望发生这个行为,可以通过return false取消这个行为;
//但是这对ie8不起作用:设置box1设置setCapture()(点击任何按钮都会默认点击元素,移动只会移动它一个);但是这只是捕获一次,但是当鼠标再次点击,也会触发该事件,所以需要在onmouseup中取消捕获,releaseCaptrue();但是这在chrome中会报错;可以使用元素.setCapturn&&元素.setCapture();
提取专门的拖拽函数:
function dray(obj){
//box1改为obj;给目标设置一个开启定位,就可以运行了;
}
滚轮事件:
onmousewheel:鼠标滚轮的时间,会在滚轮滚动的触发该事件,但是火狐不触发该事件;
wheelDelta:鼠标滚动的方向,向上滚是正值,向下滚是负值,很多浏览器这个属性返回值不同,所以不用考虑值的大小,火狐中detail向上是-3负值,向下是3正值;
if(event.wheelDelta>0||event.detail<0){向上滚动}else{向下滚}
//当浏览器有滚动条时,如果在指定元素上滚动会触发浏览器的默认行为;,这会使浏览器窗口和元素一起发生滚动,需要取消默认行为;
在触发某个事件函数中添加event.preventDefault();当移动到指定元素,浏览不会发生滚动事件;这个属性ie8不支持
event.preventDefault&&event.preventDefault();有就使用;
键盘事件:
键盘事件一般绑定在获取焦点的对象,或者文档事件;
onkeydown:键盘事件被按下;
onkeyup:键盘事件被松开;
对于事件来说当键盘一直被按下,它会一直触发事件;第一次和第二次触发的时间稍微长一点,防止误触发;
可以通过keycode获取按键编码;也就是说判断哪个按键被按下了;
同时按下的按键怎么判断呢?
这样?if(event.keycode===19&&event.keycode===85),这是明显错误的,没有一个值能够既等于19又等于85,可以通过单独的键盘事件判断是否同时按键;
altkey
ctrlkey
shiftkey
这三个是单独的触发的:
在文本框中输入内容是文本框中的默认行为;可以通过return false;取消默认行为;,可用于指定用户输入内容功能,不然无法显示;
键盘移动:
37左
38上
39右
40下
判断键盘事件可以用swith语句来判断事件,绑定操作;
//设置变量speed可以修改变量的速度;
var speed=10;
//加速;
if(event.keyctrl){speed=30;}
switch(event.keycode)
{
case 37:
box1.style.left=box1.offsetLeft-10(speed)+"px";
break;
case 38:
box1.style.top=box1.offsetTop-10(speed)+"px";
break;
case 39:
box1.style.right=box1.offsetRight+10(speed)+"px";
break;
case 40:
box1.style.bottom=box1.offsetBottom+10(speed)+"px";
break;
}
但是这个也有个缺陷,之前说过浏览器为了防止误触发,在第一次到第二次触发的时间间隔更长。需要使用定时调用来修改;
BOM:浏览器对象模型;
BOM可以让js操作浏览器的,在bom中定义了一组对象,用来完成对浏览器的操作;
BOM对象:
Window对象:
代表浏览器的整个窗口,同时window也是网页的全局对象;
Navigator:代表当前浏览器的信息,通过该对象可以识别不同的浏览器;
Location:代表当前地址栏信息,通过Location可以获取地址栏信息,或者操作浏览器跳转页面;
History:代表浏览器的历史记录,可以通过该对象中操作浏览器的历史记录
由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页;
而且该对象访问当前访问有效;
Screen:代表用户的屏幕的信息,通过该对象可以获取到用户的显示器的信息;做移动端,响应式都需要使用;
Navigator对象:
appName:获取当前浏览器名称,除了ie9及其以下,都比较正常,而现在都会显示netscape;(通常是主流浏览器)
这里的大量属性,已经不能使用了。
以前由于ie的特殊性,很多资源不能调用,导致一些网站给ie的资源不如其他浏览器,而这也是识别ie的手段之一,后来ie就向大多数浏览器妥协,于是越来越像普通浏览器;
弃用了许多特殊的属性;就连appName也变成了netscape;
一般使用userAgent来判别浏览器信息;
userAgent就是一组字符串,不同的浏览器有不同的浏览器信息;
而这里面也有很多重复的内容;但也有区分信息,可以使用正则表达式来区分浏览器中有无浏览器信息;
var ua=Navigator.userAgent;
if(/firefox/i.test(ua){
//是否为火狐浏览器
}else if(/chrome/i.test(ua)){}
else if(/mise/i.test(ua)){测试ie10及其以下}
// ie11之后ie浏览器消除了这个方式
我们可以通过浏览器中特有的对象来判断是否是ie浏览器;
如果ActiveXObject有则判断是ie;
//if(window.ActiveXObject){这是ie浏览器;},这个也不行;,使用in来判断;它采取返回是false,一般ie采用返回true
if("ActiveXObject" in window){}//通过判断属性中有没有这个属性;有返回true;
History对象:
操作浏览器向前,向后翻页;
histoty.length:表示访问当前浏览器中历史记录的数量(单次访问的数量,不在具体的浏览器的数量),关闭时消失;
back():回退,可以用来回到上一个页面;
forward():前进,可以跳转到下一个页面;
go(n):跳转到当前页面第n个页面, n为正值前跳,n为负值后跳;
Locatiion对象:
如果直接打印location则可以获取当前地址栏上的信息;(完整的路径);
location="";如果直接修改完整的路径或者相对路径,则页面会自动跳转到该页面;并且生成相关的历史记录;
location的对象属性,将地址分为好几个部分,可以之后学习了解;
location的方法:
assign():
location.assign():和赋值的方式是一个样的。
reload();从新加载当前页面,作用和刷新按钮一样;
ctrl+f5:强制清空缓存;
location.reload(true);强制清空缓存;没有true不强制;
replace()使用新的页面替换当前页面;跳转不能回退;不会生成历史记录;
定时器简介:
for循环当调用一条语句的时候,不能看到具体的细节,如果希望程序每间隔一段时间调用一次,
就需要使用setInterval()定时调用,这个可以使函数每隔一段时执行一次,
第一个参数为回调函数,这个函数每隔一段时间调用一次,第二个参数是间隔的时间,单位毫秒;
它会以数字作为返回值,这个数字代表这个定时器的唯一标识
var x=setInterval(function(){},1000);
关闭定时器,
clearInterval()方法中需要定时器的标识关闭这个定时器:可以传递这个数字,一般来说直接将定时器赋值给一个指定的变量,然后将变量作为参数来关闭定时器;
clearInterval(x);//x可以传入任意一个类型,有效就会停止,无效也不会报错;
切换图片练习;
<img src="image/01.png" id="img1">
<script>
var img=document.getElementById("img1");
var imgArr=[image/01.png,image/02.png,image/03.png];
var index=0;
var set1=setInterval(function(){
index++;
if(index==imgArr.length){
index=0;
}
img.src=imgArr[index];
},1000)
img.οnclick=function(){
if(set1){
clearInterval(set1);
}
else{
var set1=setInterval(function(){
index++;
if(index==imgArr.length){
index=0;
}
img.src=imgArr[index];
},1000)
}
}
</script>
开启定时器之后需要及时关闭,不然容易在开启之后,会误创建多个定时器,由于set1被反复赋值,前一个的标识被后一个标识覆盖掉了,从而关闭不掉;
修改div练习:
速度交给定时器控制,方向交给键盘事件判断,然后设置一个键盘松开事件判断重置变量的方向,就能完成连贯的操作;
window.οnlοad=function(){
var speed=10;
var dir=0;
var set1= setInterval(function(dir){
switch(dir){
判断执行
}
},30)
document.οnkeydοwn=function(event){
event=event||window.event;
var dir=event.keycode;
if(event.keyctrl){
speed=50;
}};
document.οnkeyup=function(event){
dir=0;speed=10;
};
};
延时调用:
setTimeout(参数一,参数二)
这个函数参数一过参数二毫秒调用一次;应用网页上一些广告,过一段事件自动关闭;
这两个可以互相代替的的;
clearTimeout()可以清楚延时调用;
小功能:
ie浏览器没有设置的值都会返回默认;最好在使用的时候设置一个默认值;
将一个功能集成后,可以设置多个参数,如对象 属性 目标 方向 回调函数等;
其中的回调函数,可以让方法多次调用,更好的 与其他功能集成;
callback&&callback()表示有回调函数就调用回调函数。回调函数表示函数执行完毕之后才去调用的。其他的可以模仿这个设置,没有传参该如何执行;
轮播图:
轮播图的横向图片的宽度不要写死了,不然添加新的元素,会让多余的元素自动换行,应该通过计算内部轮播图片的数量定义轮播图的宽度。
创建导航链接随着轮播图一个跳动;这个的宽度和居中也不能写死,不然添加新元素后,它会变样,不居中;使用计算值,添加元素之后整体距离两端的距离(大容器的宽度-导航链接的宽度)除以2就能完成居中了;
对所有的超链接绑定单击响应函数,链接到相应图片;
还需要获取点击超链接的索引;
for (var i=0;i<allA.length;i++){
//给每一个a超链接绑定一个索引,这样就能知道点击的是哪一个超链接
all[i].num=i;
all[i].οnclick=function(){
index=this.name;
imgListLeft=index*(-520)+"px";
}
}
创建点击动画:动画执行一次向左滑动或者直接滑动到对应的位置,随着动画的执行,超链接的样式也需要发生变化。
创建轮播动画:每隔三秒会执行一次动画向左滑动;
这里的点击动画会和轮播动画产生冲突,可以设置在点击时取消轮播动画,当这个动作执行完成,设置轮播动画定时器,就可以避免这个问题;
这里还有就是到最后一张图片时,它会慢慢的往前滑动,滑动到时,可能就会跳转到下一个图片了,所以在这里需要多设置一个图片不绑定链接,当滑动到最后一张图时,直接以修改索引为第一张图片的索引。不让其参与动画。
类的操作:
通过style属性修改元素的样式,每修改一次,浏览器就需要重新渲染一次页面;当修改多个样式时,一行一行的修改样式,就会消耗大量的浏览器资源,而且在开发中,
这种js修改,还会让原本的文档更加的混乱,要修改样式还得去js中去寻找。
我们需要的做的是,
一行代码修改多个样式;
我们可以通过修改(添加)元素的class属性,来修改文本的样式,这样一来我们只需要修改一次,就能修改多个样式,浏览器只需要重新渲染一次。这种方式可以使表现和动作分离;(先在css中定义需要修改的样式;
box.className+=" b2"//b2前面有一个空格,不然的话会将两个字符串拼接在一起,从而导致原有的class属性实现,如class="b1"拼接之后有class="b1b2",需要空格隔开;
定义一个函数,用来向一个元素中指定的class属性值添加属性;
function addClass(obj,cn){
if(hasClass(obj.cn)){
obj.className+=" "+cn;}//这样会产生重复的class
}
function removeClass(obj,cn){
if(hasClass(obj,cn)){
var reg=new RegExp("\\b"+cn+"\\b");
obj.className=reg.replace(cn,"");
}
}
function hasClass(obj,cn){
//判断obj中是否有class;
var reg=/^(cn){1}\s|\s(cn){1}\s|\s(cn){1}$}/; //这种方式是没有办法设置变量,需要使用构造函数;
var reg=new RegExp("\\b"+cn+"\\b");\b表示单词边界,表示cn是独立的;
return reg.test(obj.className);
}
function toggleClass(obj,cn){
//判断有删除,没有添加;
var reg=new RegExp("\\b"+cn+"\\b");
if(hasClass(obj,cn)){
obj.className+=" "+cn;
else{
obj.className=reg.replace(cn,"");}
}
二级菜单:
实现的相同动画的方法,最好也是相同的,这样可以节省很多代码;
动画过渡的参数,可以先从控制台上输出从而获取;
动画过渡的结束之后,可能还会残留内联样式导致下一次调用动画会失败;
JSON:
服务器和客户端之间,需要存在通信;而服务器和客户端的语言不同,虽然js能够读自己的对象,但是服务器不一定认识。
JSON就是特殊格式的字符串,这个字符串任何语言都能识别,并且可以转换成任意语言的对象;这样就可以将js中的对象和其他语言的对象交互;
(javascript object notation)JSON的格式和js的对象是一样的,只不过JSON字符串中的属性名必须加双引号;
JSON有两种:
一种是对象{}包裹;
JSON:var json='{"name":"nihao","sex":"男"}';
另一种是数组[]包裹;
JSON:var json='["name":"nihao","sex":"男"]';
JSON中的允许值
1.字符串
2.数值
3.布尔值
4.对象(普通对象;不包括函数对象)
5.null
6.数组;
//undefined不能,还有就是函数不能传;
需要将字符串转换成对象:
在js中提供了一个工具类,就叫JSON;它既可以将JSON转化成对象,也可以将对象转换成JSON;
JSON.parse(json);它需要将一个JSON字符串作为参数,会将字符串转换成JSON对象;它返回一个对象/数组;
将js对象转换成JSON;
JSON.stringify()可以将一个js对象转换成JSON字符串,需要添加一对象作参数;
JSON常用,作为数据交互对象:轻量级,速度较快的数据交换格式;
但是JSON在IE7及其以下的浏览器不支持,所以在这里调用会报错。
如果需要兼容ie6,ie7;需要使用eval()函数,这个函数可以执行字符串形式的代码,并将执行结果返回;
如果执行字符串中含有大括号,它会将大括号当做代码块;
如果不希望将其当做代码块解析,需要将字符串前后江上一个()
var obj=eval("("+json+")");通过eval()将JSON很容易转换成字符串;
eval()这个函数虽然功能强大,但是也用很大的副作用,如消耗很大,安全隐患;
真要兼容ie7及以下的JSON的操作,则可以通过引入一个外部的js文件来处理;在网上能够搜索到兼容ie6,7的js;
来自尚硅谷2016年视频 笔记(李立超的)