起源发展

在前端中,我们一直都只是在使用JavaScript中的DOM、BOM部分的API,操作HTML网页标签,来进行达到专业编程
DOM0 初级阶段

最初浏览器中为了方便检索界面上的元素提供了非常方便的api,查询页面上的元素。实验性质的api称为DOM0

document.form[0]

document.images[0]

随着JavaScript的普及,不同了浏览器分别扩展了JavaScript,此时程序员就苦逼了

document.layers["d1"] //Netscape

document.all["d1"] //IE

DOM1

规定了节点的类型Node

为了统一浏览器之间的差异W3C制定了DOM1。

比如获取浏览器的元素,不同浏览器下都可以使用

document.getElementById()

DOM2
DOM3

DOM

文档(Document):

就是指HTML或者XML文件

DOM(Document Object Model) -- 文档对象模型,又称为文档🌲模型。

就是将HTML/XML文档中描述为一个树状结构的文档(文档树),将文档中每一块的内容当成一个个的节点对象,挂在树上,这个树形结构的标准模型就称为DOM,又称DOM树。是一套API。

简而言之:DOM就是html文档的模型抽象。数据以树的形式在内存中排列。

document是文档对象模型的一部分。

DOM是一个复合的数据类型。

DOM的数据结构(树状) 解析过程

HTML加载完毕,渲染引擎会在内存中把HTML文档,生成一个DOM树,getElementById是获取内中DOM上的元素节点。然后操作的时候修改的是该元素的属性。

DOM就是浏览器将html文档转成一个个对象,然后给js留的一些JS语言的API,供其操作页面元素,所以说DOM,是js的一个模块的API

用途:

对元素节点进行

  • 查:直接获取、访问关系间接获取
  • 改:改属性、改样式、事件绑定
js跟css代码其实很像,都有内嵌,外链,行内,都是一块区域,前者是写方法,写操作,后者是写选择器,写样式

行内:

js是css一样的,都是在HTML标签里写东西

当是内嵌/外链的时候,怎么将标签与css样式 / js方法联系在一起?

css:标签与自己调用的样式,保持两者类名、id一致,编译器自己就会将它们联系到一块

js:我们必须在JS文件中手动获取到这个标签,来给这个标签加事件。多了一步获取标签。

节点

什么是节点

节点(Node):HTML文件中的所有内容都可以称之为节点。节点是DOM的组成单位。

根据类型分为:

元素节点(html中叫标签,js中叫元素)

根元素节点:又称文档元素,文档中的第一个元素<html>

属性节点(标签属性)

文本节点(标签的文本内容)

区分方法:nodeType: 1是标签,2是属性,3是文本

根据层级关系:父节点、子节点、兄弟节点.

除了nodeType,还有两个节点属性:

nodeName    标签名字/属性名字/文本名字(#text)

nodeValue    null/id值/文本的内容

节点是一个对象,有属性和方法。获取方式有很多种。通过DOM的方法获取到某一个节点,然后console.log,在控制台打印,就可以看到这个元素节点就是以对象方式呈现的,可以看到节点对象的属性和方法。

DOM节点对象的获取

DOM节点对象的获取,有五种方法:API是BOM顶级对象window.document.方法()

其中html/body/head/title例外,API是作为window.document.属性

普通节点对象的获取


常用的两种:

根据标签ID来获取

var div = document.getElementById("demo");

根据标签名来获取

var arr1 = document.getElementsByTagName("div");

根据类名来获取,h5新增,IE5.6.7.8中无效

var arr2 = document.getElementsByClassName("demoClass");

不常用的两种:

根据name属性来获取,表单控件中设置的name的比较多

var arr3 = document.getElementsByName("");

根据命名空间来获取,XML中使用

var arr4 = document.getElementsByTagNameNS();

只有第一种,返回值是一个标签,可以直接使用。获得属性值,设置属性。

剩下四种的返回值都是标签数组,习惯性是遍历之后再使用。

特殊情况:数组中的值只有1个。

document.getElementsByTagName("div")[0];取数组中第一个元素

document.getElementsByClassName("a")[0];取数组中第一个元素

注意:

1. getElementsByTagName()是节点的方法,document能调,我们自己获取的节点也能调,前者是在整个html文档中找,后者是在调用方法的标签里找,缩小范围,节省性能,最好用这个,也免得误操作了其他的元素



html/body/head/title节点的获取

document.title --- 文档标题;

document.head --- 文档的头标签

document.body --- 文档的body标签;

document.documentElement --- 这个很重要

它表示文档的html标签, 也就是说,基本结构当中的html标签并不是通过document.html 去访问的,而是document.documentElement 。

声明DTD

DTD的概念

dtd声明是为了让老版本浏览器,支持一些新的api(个人理解:相当于给把给老版本浏览器导入一个系统框架,会替换已有的一些api)

IE9的时候微软将浏览器推翻重做,外观差不多,但是底层实现原理改了许多(叫Spartan斯巴达),所以一些兼容问题是,IE8是个分界点


判断代码有没有声明DTD。

document.compatMode === "BackCompat"

BackCompat 未声明

CSS1Compat 已经声明

IE678默认识别CSS1Compat ,无论有没有dtd,即默认帮文档声明DTD

注意大小写


这里之所以提到这个,是因为document.body、document.documentElement的选择与是否声明DTD有关系

document.body

没有声明dtd的时候用,声明以后就不能用这个了

(谷歌只认这个api,下面这个就是声明了,也不支持)

document.documentElement

声明dtd的时候使用

(IE 678只认这个api,而且ie678默认网页已声明dtd)

IE9+ 、火狐这俩个都识别。

之所以有这个分歧,是有人认为界面是body在滚动,有人认识是html(documentElement代指html)在滚动。现在认为是body在滚动的人多。


DOM里的API是做为DOM节点对象的属性和方法存在的。其用途总而言之来说就是:对节点查改增删

我们下面根据用途划分模块,分来讲解:

节点属性 -> 查节点

又叫通过访问关系获取

节点的访问关系,是以节点.属性的方式存在的。

DOM的节点并不是孤立的,因此可以通过DOM节点之间的相对关系对它们进行访问。

访问关系:父节点、子节点、兄弟节点.

重点是两个属性:parentNode、children

Ⅰ父节点 ( parentNode )

调用者就是节点。一个节点只有一个父节点。调用方式就是节点.parentNode.

Ⅱ子节点 - 单个子节点
firstChild:调用者是父节点。

IE678中指第一个子元素节点(标签)。

在火狐谷歌IE9+以后都指的是第一个节点(包括空文档和换行节点)。

firstElementChild:

在火狐谷歌IE9都指的第一个元素节点。

写法:

第一个子节点=父节点.firstElementChild || 父节点.firstChild


lastChild:调用者是父节点。

IE678中指最后一个子元素节点(标签)。

在火狐谷歌IE9+以后都指的是最后一个节点(包括空文档和换行节点)。

lastElementChild:

在火狐谷歌IE9都指的最后一个元素节点。

写法:

第一个子节点=父节点.lastElementChild|| 父节点.lastChild


Ⅱ子节点 - 所有子节点
childNodes:

它是标准属性,它返回指定元素的子元素集合,包括HTML节点,所有属性,文本节点 (他还是W3C的亲儿子 )

火狐 谷歌等高本版会把换行也看做是子节点

nodeType == 1 表示的是元素节点(标签)

nodeType == 2 表示是属性节点

nodeType == 3 是文本节点

写法:

子节点数组 = 父节点.childNodes; 获取所有节点。


children:

非标准属性,它返回指定元素的子元素集合。

但它只返回HTML节点,甚至不返回文本节点,虽然不是标准的DOM属性,但它和innerHTML方法一样,得到了几乎所有浏览器的支持。

children在IE6/7/8中包含注释节点,在IE678中,注释节点不要写在里面。

写法:

子节点数组 = 父节点.children; //用的最多。


Ⅲ兄弟节点(sibling)

Sibling就是兄弟的意思。

Next:下一个的意思。

Previous:前一个的意思。

nextSibling

IE678中指下一个元素节点(标签)。

在火狐谷歌IE9+以后都指的是下一个节点(包括空文档和换行节点)。

nextElementSibling

在火狐谷歌IE9都指的是下一个元素节点。IE678不支持此方法

写法:

在IE678中用nextSibling,在火狐谷歌IE9+以后用nextElementSibling

下一个兄弟节点=节点.nextElementSibling || 节点.nextSibling


previousSibling:

IE678中指前一个元素节点(标签)。

在火狐谷歌IE9+以后都指的是前一个节点(包括空文档和换行节点)。

previousElementSibling:

在火狐谷歌IE9都指的是前一个元素节点。

写法:

在IE678中用previousSibling,在火狐谷歌IE9+以后用previousElementSibling。

下一个兄弟节点=节点.previousElementSibling|| 节点.previousSibling

获取兄弟节点

获取任意兄弟节点

节点自己.parentNode.children[index];

获取除自己外所有兄弟节点

function siblings(elm) {

var a = [ ];

var p = elm.parentNode.children;

for(var i =0,pl= p.length ; i < pl ; i++) {

if(p[i] !== elm) a.push(p[i]);

}

return a;

}

定义一个函数。必须传递自己。定义一个数组,获得自己的父亲,在获得自己父亲的所有儿子(包括自己)。遍历所有的儿子,只要不是自己就放进数组中。

节点属性 -> 改节点

步骤:先查找得到元素节点 --> 修改属性/样式

改属性

节点属性值:(标签大多属性都推荐使用css来代替设置,所以这里,属性就这几种,其中表单控件的属性比较特殊,重点说)

html标签的属性

在DOM中,是通过DOM对象的属性来取值/赋值的

两种方法:

1.操作标签对应的DOM对象属性,会反映到标签上:.属性/["属性"]

2.DOM-API直接操作标签:set/get/removeAttribute("")


节点的属性与HTML的标签属性基本名字基本上是一致的。


两个重点属性:

InnerHtml

获取元素节点内的所有内容,包括标签

用的地方很多,当我们要创建很多标签的时候,可以通过给innerHTML赋值,比如:.innerHTML = "<li>内容</li><li>内容</li>"

innerText

获取元素节点中的内容,不包括标签,老版本火狐,不支持Innertext.,支持textContent

其他:

name

获取input类型元素节点name属性的值

Value

获取input类型元素节点value属性的值

classname

类名,class是关键字,所以是className

此外,还有input元素节点的disabled、checked(多选单选的默认选中)属性,还有select的size属性(设置select标签有多少项的高度),select下拉列表中option项的selected属性

select标签的value值 = 被选中的option标签的value值。如果是多选,value值为被选中option中,最上面那个option标签的value值

注意:

disabled、checked、以及selected属性:

1. 只要在标签的行内出现了这个属性,不管赋不赋值,赋任何值,这个属性都生效(通过DOM代码设置时,这个值才能当做是个Boolean值来看)

2. 前面说过,节点.属性 给标签增加属性时,如果这个属性是系统已存在的属性,那么也会显示在标签中,但checked、selected这两个是例外,不会显示在浏览器控制台标签内(setAttribute设置,不管是什么属性都显示)

.className = "xx"

.className += " xx",多调用一个类选择器

修改属性

DOM中的API

获取:getAttribute(名称)

设置:setAttribute(名称, 值)

删除:removeAttribute(名称)

注意:IE6、7不支持。

调用者:节点。

有参数。

没有返回值。

修改元素属性:

元素节点.属性/['属性']

元素节点.setAttribute()(DOM的API中,不再是className,而是class)

两者区别:

get/set/removeAttribute是操作的标签本身

.属性/['属性']操作的是html对应的js-DOM的节点对象。修改节点对象,有时候会反映不到控制台的标签中,也就是显示不了


当操作的是系统原生的属性,没什么区别,都会显示在浏览器控制台的标签中(对于.属性来说,checked、selected是例外,不知道还有没有其他的),如果添加的是不存在的属性,后者,依旧会显示,前者不会显示

添加/修改属性,当是非原生属性时,这两个方法不能交替使用,赋值和获取值必须用一个方法,各自负责的非原生属性只能自己这个方法能获取到。如果是原生属性,两个方法是可以交替的。(但最好别混用)

改样式(也涉及document几个方法)

获取样式
获取行内样式,也是唯一可以读写的方式

div.style.width/["width"]


获取任何行内/内嵌/外链样式 (只读属性)

window.getComputedStyle(元素,null)

参数1:获取属性的元素。

参数2:伪元素,C3学习。


div.currentStyle //IE678


这两个方法获取的是个样式的object对象,我们要取值的样式就是这个对象的属性,进行属性取值就行了:.语法/[""]

兼容方法获取元素样式

function getStyle(ele,attr){

if(window.getComputedStyle){

return window.getComputedStyle(ele,null)[attr];

}

return ele.currentStyle[attr];

}


使用style的注意项:

1.通过style只能获取到元素节点的行内样式,不能获取内嵌和外链的样式。改完之后也是加到行内样式中

2.style是对象

3.样式名字的命名规则变成了驼峰命名。与CSS中用横杠隔开是不一样的

4.style.样式 — 值是字符串,不设置值是""

5.box.style.cssText = “字符串形式的样式”;可以设置多个属性

比如:box.style.cssText = "width: 200px; height: 200px; background-color: red;”;

.style.xx是获取的元素行内样式style中的设置,修改之后,也是加到元素行内样式style中


改变样式有两种方式:

1.通过元素节点.style.样式/style["attr"],来一一改变(当需要改变的样式少的时候使用这个)

注意:当我们封装方法,通过传入的样式值来操作的时候,用.语法根本实现不了,只能用style["attr"]

2.通过修改元素节点的class,来调用另外的类选择器,改变样式,而且这个方法,维护方便,也实现了css/js的分离

注意:当我们要修改整个body.style.top/left是不生效的,我们只能调用window.scorllTo(x,y)修改x,y的值,来让body滚动

事件event

概念

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。比如:事件被触发时,关于键盘和鼠标的一些信息。都是作为event的属性存在的

所有浏览器都支持event对象,但支持的方式不同。

获取

普通浏览器支持 event(传参)(参数就是event)

比如:ele.onclick = function (e){

e就是event,可以直接用,或者直接在这里使用event (说是event是事件中的一个内置对象)

}

ie 678 不支持 function()里面传参,然后当做event。只能使用 window.event ,来获取事件对象

常用的兼容写法:

function(event) { // 可以起其他名字,但是一般都用这个

event = event || window.event;

}

常见的事件有哪些
事件名 说明
鼠标相关的事件
onclick 鼠标单击
onmouseenter = onmouseover 鼠标悬停,即鼠标停留在图片等的上方,前者不冒泡
onmouseleave = onmouseout 鼠标移出,即离开图片等所在的区域,前者不冒泡
onmousedown 鼠标按下
onmousemove 鼠标在标签上移动,移动1px也会触发
onmouseup 鼠标抬起
ondblclick 鼠标双击
onkeyup 按下并释放键盘上的一个键时触发
input表单的事件
onfocus 获得键盘输入焦点,常用于文本框。
onblur 失去键盘输入焦点
onchange 文本内容或下拉菜单中的选项发生改变
onsubmit 表单提交事件
onreset 重置表单时
window的事件:
onload 网页文档加载事件
onunload 关闭网页时
onresize 浏览器窗口大小被拖拽改变,哪怕1px都触发
(texture标签也可以拖拽,但是这个事件对它不生效)
onscroll 盒子内容滚动时,滚动1像素都调用。
可绑定有滚动条的盒子、body/html、window

onload

什么条件下触动这个事件呢?页面加载(文本和图片)完毕的时候。

用途

js的加载时和html同步加载的,如果使用元素在定义元素之间,容易报错。

window.onload可以预防使用标签在定义标签之前。让整个页面上所有元素加载完毕在执行js内容

onscroll

滚动事件(window.onscroll = fun...)

屏幕每滚动一次,哪怕只有1像素都会触发这个事件。这样就可以用来检测屏幕滚动了。

只能有一个,写了多个以最后一个为准,同理 window.onload

onchange

input上传文件控件,onchange检测上传文件,value是文件路径

事件的属性

PageY和pageX的兼容写法(很重要): pageY/pageX=event.clientY/clientX+scroll().top/scroll().left

获取event的事件源,兼容写法

//兼容写法获取元素ID,IE678支持srcElement

var event = event || window.event;

var targetId = event.target ? event.target.id : event.srcElement.id;

事件冒泡机制

首先,我们需要了解事件响应链:

OC是button — self.view — window — application,然后hitTest,一步步向下定位找到合适的控件,然后触发绑定的事件。

JS的事件传播分为三个阶段:捕获阶段、目标阶段、冒泡阶段

一旦有事件触发,直接从window开始向下找,直到找到事件的原始元素(target)。这一过程叫做捕获阶段

然后从原始元素(target)开始向上,父系元素中所有绑定此事件的都会被触发。这一过程被称为事件冒泡

这个事件从原始元素开始一直冒泡到DOM树的最上层。(BUG)

无论是.onclick或者addEventListener绑定的,都会响应冒泡机制。


注意:

事件冒泡过程中,所有层级父盒子中绑定此事件的,都会执行事件对应方法,但是这些方法中的event都是指从原始元素传过来的那个,这些方法中的event.target都是被点击的那个原始元素。这是事件委托的理论基础。

不过,这些父盒子事件驱动程序中的this依旧是代表各自父盒子本身,这个是不会变的

冒泡的顺序

冒泡顺序

IE 6.0:

div -> body -> html -> document

其他浏览器:

div -> body -> html -> document -> window

不是所有的事件都能冒泡。以下事件不冒泡:blur、focus、load、unload、onmouseenter、onmouseleave

阻止冒泡

w3c的方法是:(火狐、谷歌、IE11)

event.stopPropagation()

IE10以下则是使用:

event.cancelBubble = true

兼容代码如下:

var event = event || window.event;

if(event && event.stopPropagation){

event.stopPropagation();

}else{

event.cancelBubble = true;

}

冒泡的用途

1. 事件委托:简而言之就是,本来应该是绑定在子元素节点身上的事件,绑定到了父元素上,然后在事件对应的方法中,判断event.target.id/class是不是该子元素,如果是再执行相应的方法

事件带来的浏览器默认行为

浏览器都有它自己的默认行为

比如:

在form中按回车键就会提交表单

单击鼠标右键就会弹出context menu


点击a标签,会跳转页面,也是默认行为(为a标签绑定click方法,方法里可调用下面的那两个方法,取消默认行为)


在onfocus()事件中的浏览器默认行为:为input,增加轮廓框

这个默认行为,好像去不掉,因为在进到这个方法内部的时候,浏览器默认行为已经产生了。


在ondrag事件中的浏览器默认行为:

目标元素,只要没有在dragover事件中,取消浏览器默认行为,那么就不会执行ondrop方法

取消浏览器默认行为的两个方法:在绑定的方法中

1. e.preventDefault();

2. 在绑定的方法的最后 return false;

事件绑定和移除

步骤:获取元素节点 --> 绑定事件 --> 给事件绑定一个函数(又叫事件驱动程序)

事件概述

JS是以事件驱动为核心的一门语言。

事件绑定三要素

事件源、事件、事件驱动程序。

绑定事件+对应方法(事件驱动程序)

两种注册方式,都可以看做是给事件源加了一个属性,值是个function方法。可以用事件源.onclick或者事件源["onclick"]取出来,打印出来是个function

第一种绑定方式:事件源.onclick/事件源["onclick"] =

DOM0版本规定的,几乎所有浏览器都支持

这个方法绑定的事件,后来的会把前面的层叠


1.直接绑定一个方法(方法名有没有无所谓,一般都没有,没有叫匿名绑定)

div.onclick = function () {

}

2.方法名绑定

div.onclick = fn; // 不要写括号,否则就成返回值了


function fn() {

}

3.行内绑定

<div id="box" onclick="fn()"></div> //要写括号,很与众不同。里面也可以直接写JS代码


function fn(){

//这个方法定义不能写在window.onload方法里,也就说方法:fn不能是局部变量

//此时,这个方法里的this是指window,如果要this代指div标签,上面应该写"fn(this)"

}

1. 事件驱动中,可以多用this,谁调用表示this代表是谁.

2. 方法中,改变标签的style时,可以直接用html标签的Id,比如“boxid”,然后boxid.style,原理是如果在JS中找不到boxid这个变量,就会去找HTML中id为boxid的标签,但是不允许这么做(只有id可以这样,类名标签名不支持)

3. 超链接的事件驱动程序中,return false;可以禁止跳转,也可以在行内写 onclick = “fn(); return false;”

第二种绑定方法:addEventListener(IE9之前是attachEvent)

DOM2规定的,现代浏览器+IE9支持,IE9之前使用attachEvent

可以给同一个事件注册多个事件处理程序,不会被层叠(更适合团队开发)

可以选择捕获或者冒泡


addEventListener与attachEvent的区别:

1.参数的区别

addEventListener第一个参数,是不带on的 比如:addEventListener(“click”,code)

attachEvent第一个参数,是带on的,比如:attachEvent(“onclick”,code)

2.this的区别

addEventLisener:事件处理程序会在当前对象的作用域运行,因此,时间处理程序的this就是当前对象

attachEvent:事件处理程序是在全局作用域下运行因此this就是window


addEventListener的第三个参数:boolean,决定事件是在捕获过程中执行还是在冒泡过程中执行

addEventListener第三个参数,默认为false,就是默认的事件响应链的流程(冒泡过程中执行,由里向外)。如果某个事件绑定的时候设置为true,表示将事件提前到了在捕获过程中一旦捕获到了,马上执行。(顺序从外到里)

注意:设置为false,大多数浏览器都支持,设置为true,老版本的控制器是不支持的。很少有人会使用捕获


移除事件的两种方法

element.onclick = null;

removeEventListener

IE9以前detachEvent

如果注册的时候使用的是匿名函数,则无法移除

解绑方法与绑定方法是对应使用的,否则解绑是起不到效果的

注意:

事件驱动程序绑定的时候是不执行方法里面的代码的,只有当事件被触发时才调用,跟UIButton点击事件一样的道理,绑定的时候就只是绑定了一个方法名

方法被调用的时候,里面的变量再从script 里找,去取值

清除选中的内容

除了超链接里的文字,其他标签里的文字内容,我们鼠标双击的时候,都会或多或少地选中一些文字,方便我们赋值粘贴用的,这好像是浏览器底层默认功能。

处理方法:在事件绑定方法中,清除选中的内容

//兼容写法

window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();


IE9、Firefox、Safari、Chrome和Opera支持:window.getSelection()

IE9以下支持:document.selection

或者:如果是文字点击,就用超链接来做,然后在绑定的方法里写:return false,就不会发生跳转

  实战经验

2.输入框占位符的制作

淘宝输入框:label for id + onInput制作,label的内容就是占位符

节点方法 -> 增节点(也涉及document几个方法)

步骤:创建新的元素 --> 添加到已有节点中

创建DOM节点的几种方法

//第一种创建方式:document.write(); 不常用,因为容易覆盖原来的页面。

document.write("<li>我是document.write创建的</li>");


//第二种:直接调用父元素的innerHTNL方法赋值内容。(innerText方法不识别标签) //用的比较多。绑定属性和内容比较方便。(节点套节点时使用)

ul.innerHTML += "<li id='xxx'>我是innerHTML创建的</li>"


//第三种:利用DOM的API创建元素,设置内容属性,然后插入append到父节点。 //也是比较多的,指定数量的时候一般用它。

var newLi = document.createElement("li");

ul.appendChild(newLi);

创建新节点

新的标签(节点) = document.createElement(“标签名”);

复制已有节点

新节点=要复制的节点.cloneNode(参数) ; 参数可选复制节点

用于复制节点, 接受一个布尔值参数, true 表示深复制(复制节点及其所有子节点), false 表示浅复制(复制节点本身,不复制子节点)

插入节点(使用节点)

父节点.appendChild(新节点); 父节点的最后插入一个新节点

父节点.insertBefore(要插入的节点,参考节点);//如果参考节点为null,那么他将在节点最后插入一个节点。

实战:根据服务器返回的数据创建新节点赋值

ios获取数据,铺到界面步骤

获取数据数组,取出中间一个个字典,转model,将model一个个值,赋值给控件铺数据

前端步骤:

请求数组数据,截取其中的JSON串(因为JS中JSON就是对象的字面量,也就是对象,所以不用转model了,现成的model),将数据取出来拼接,赋值给控件的innerHtml属性

innerHTML='' //赋值时建议单引号,因为里面有大量属性,都是双引号


节点方法 -> 删节点

删除节点

父节点.removeChild(子节点);必须制定要删除的子节点

节点自己删除自己:

不知道父级的情况下,可以这么写:node.parentNode.removeChild(node)

动态创建表格

操作tr

rows:返回值是数组 (只读,table和textarea能用)

insertRow() (只有table能调用)

参数:索引值,在指定索引值之前插入

deleteRow() (只有table能调用)

参数:索引值,删除指定行

操作td

cells (只读,tr和textarea能用)

insertCell() (只有tr能调用)

参数:索引值

deleteCell() (只有tr能调用)

参数:索引值

BOM

BOM

浏览器对象模型,window作为BOM的顶级对象,使用的时候,属性和方法都是window来调用

window对象

window对象是JavaScript中的顶级对象

window对象下的属性和方法调用的时候可以省略window

所有定义在全局作用域中的变量、函数都会变成window对象的属性和方法,比如alert()、confirm()、prompt()这些方法本质上也是window调用的

window的属性

由上图可知,document/location/navigaitor/histoty等是作为window的属性存在,才能发挥其作用的。这些属性各有各自的一些属性和方法

按照iOS开发的角度来讲:

window可以理解为控制器

window.document是控制器的view,控制界面的显示,操作显示的控件,元素等

window的方法

window.open(url,target,param):打开一个新窗口

url 要打开的地址

target新窗口的位置 _blank _self _parent(父框架)

param的设置项:

  • name:新窗口的名称,可以为空
  • featurse:属性控制字符串,在此控制窗口的各种属性,属性之间以逗号隔开。
  • fullscreen= { yes/no/1/0 } 是否全屏,默认no
  • channelmode= { yes/no/1/0 } 是否显示频道栏,默认no
  • toolbar= { yes/no/1/0 } 是否显示工具条,默认no
  • location= { yes/no/1/0 } 是否显示地址栏,默认no
  • directories = { yes/no/1/0 } 是否显示转向按钮,默认no
  • status= { yes/no/1/0 } 是否显示窗口状态条,默认no
  • menubar= { yes/no/1/0 } 是否显示菜单,默认no
  • scrollbars= { yes/no/1/0 } 是否显示滚动条,默认yes
  • resizable= { yes/no/1/0 } 是否窗口可调整大小,默认no
  • width=number 窗口宽度(像素单位)
  • height=number 窗口高度(像素单位)
  • top=number 窗口离屏幕顶部距离(像素单位)
  • left=number 窗口离屏幕左边距离(像素单位)

返回值:

新窗口的句柄

win = window.open("01-window.html","_black","width=200,height=200,top=100,left=100");


window.close():关闭窗口

新窗口.moveTo(5,5) 新窗口.moveBy()     打开的新窗口在什么位置

新窗口.resizeTo() window.resizeBy()     打开的新窗口有多大


window.scrollto(x,y) 让浏览器窗口内容滚动到指定地点

定时器:

定时器也是window的方法

setInterval()循环定时器;周而复始的执行(循环执行)

var timerId = setInterval(code,interval);

clearInterval(timerId);

setTimeout() 炸弹定时器;用完以后立刻报废(只执行一次)

var timerId = setTimeout(code,interval);

clearTimeout(timerId);

注意:定时器,跟OC有个一样的情况,就是点击按钮两次,创建定时器两个,动画加速一倍。记得clear上一个

location:

window.location相当于浏览器地址栏

location对象的属性 href (最常用的,URL地址),如果给它赋值,就会跳转界面
hash 返回url中#后面的内容,包含#
host 主机名,包括端口
hostname 主机名
pathname url中的路径部分
protocol 协议 一般是http、https
search 查询字符串
location对象的方法 location.assign() 改变浏览器地址栏的地址,并记录到历史中。
设置location.href就会调用assign()。一般使用location.href 进行页面之间的跳转
location.replace() 替换浏览器地址栏的地址,不会记录到历史中
location.reload() 重新加载
navigation:

window.navigator 的一些属性可以获取客户端的一些信息

userAgent 用户的计算机系统

platform 浏览器支持的系统,win/mac/linux

history:

window.history 历史记录管理

后退

history.back()

history.go(-1) 0是刷新

前进

history.forward()

history.go(1)

特效--引言

特效可以理解为页面动画。

JavaScript中做特效,主要用到四个模块(都是DOM给元素节点增加的属性):

三大家族:Offset/Scroll/Client

事件event对象(事件被触动时,鼠标和键盘的一些状态,都是通过event的属性)


下面三个系列,都是DOM中,为元素节点留的API:一般盒子与document.body/document.documentElement都能调用

注意两点:

1. 后者调用的时候,有时候与前者表示的意义有所差别

2. 后者body/documentElement的选择,参照我们在DOM和BOM篇,获取节点部分的笔记,与DTD是否声明有关


浏览器可视区域与body的关系,如同盒子与盒子内容的关系


offset获取盒子本身参数,scroll获取盒子内容参数,client获取浏览器可视区域的一些参数
三大家族中,只有scrollTop/scrollLeft是可以赋值的,其他全部都是只读.

Offset模块

offset这个单词本身是--偏移,补偿,位移的意思。

DOM中有一套方便的获取元素尺寸的办法就是offset家族;

offsetWidth和offsetHight 以及offsetLeft和offsetTop以及offsetParent五个元素节点属性共同组成了offset家族。

offsetWidth和offsetHeight(算padding,算border)

这两个属性,所有的元素节点对象都有。调用这两个属性,获取元素节点/body/html节点的宽和高。

offsetParent

如果父系盒子中有定位的,获取距离该元素节点 层级最近的、有定位的父盒子(仅指:absolute/relative/fixed. static定位的越过不算)

如果父系盒子中到body都没有定位的,值为body节点


注意:fixed定位的盒子是没有offsetParent的,为null

offsetTop和offsetLeft

获取offsetParent节点,距离该元素节点top的距离。(document.body/documentElement也可以调用,不过一直是(0,0))

注意:

例外:如果父系盒子中到body都没有定位的,offsetParent是body,但是这里的值是获取的html页面顶部到该元素节点top的距离。

注意:

1. margin不算在offsetWidth/Height,是算在offsetTop/offsetLeft中的

2. 在可以滚动的盒子/document中,随着滚动,offsetTop/offsetLeft是固定不变的,不会随着滚动变化

offsetTop与style.top的区别

一、最大区别在于offsetLeft可以返回任何盒子(包括没有定位的)距离左侧的位置。而style.top不可以,它只是在获取CSS中,元素定位时,设置的值

二、offsetTop返回的是数字,而style.top返回的是字符串,除了数字外还带有单位:px。

三、offsetTop只读,不能赋值,而style.top可读写。(通常两者结合使用,前者用来获取,后者用来赋值)

注意:offsetLeft/offsetTop取值的时候,如果是小数,会做四舍五入的处理,用它做缓动动画的时候需要注意。style.left取的是精确值

Scroll模块

scroll这个单词本身是--卷页,卷曲的意思。学习scroll,可以参照iOS的scrollView的contentView

scrollWidth/scrollHeight(算padding,不算border)

盒子调用

取内容宽高,当盒子内容的宽高 < 盒子本身宽高的时候,最小就是盒子本身的宽高(IE67不一样,就是取内容宽高)

document.body/documentElement调用的时候

注意:如果body的高度 < 浏览器可视区域的宽高,取值浏览器可视区域的宽高(IE67不一样,就是取内容宽高)

scrollLeft/scrollTop(向上向左为正)

盒子调用

只有当盒子内容大小 > 盒子本身宽高的时候(overflow = auto/hidden都行),调用这个才有意义,指盒子内容被盒子卷去的上部/左侧的长度

document.body/document.documentElement调用

网页滚动时,被卷去的左侧和头部(浏览器无法显示的左/头部)(参考scrollView的偏移量)


window.pageXOffset/pageYOffset

火狐/谷歌/ie9+以上支持的,获取网页被浏览器卷去的


兼容写法:

var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;

或者

var aaa = document.documentElement.scrollTop + document.body.scrollTop;(没有为0)

Client模块

clientWidth和clientHeight(算padding,不算border)

盒子调用

指盒子本身的大小,区别于offsetWidth,不算border

document.body/documentElement调用

是指浏览器可视区域的大小(不算工具栏、控制台等)

ie9及其以上的版本

window.innerWidth/Height


兼容写法:

var aa = window.innerWidth/Height || document.body.clientWidth/Height || document.documentElement.clientWidth/Height


应用:

根据浏览器clientWidth/clientHeight,可以用来大致判断当前设备是移动版(宽640)/平板版本/PC版本(宽960),后面我们还要学window.screen.width/height,直接获取屏幕的像素点数,电脑一般:我们的电脑一般:横向1280个像素点,纵向960个像素点。

clientX和clientY

是Event的属性,事件被触发时,鼠标距离浏览器窗口左、上的距离

clientTop和Left

盒子/body上、左border

动画

让图片或者图画动起来,原理也就是通过计时器来改变offsetLeft/offsetTop的值

常见的动画有:闪动、匀速、缓动三种动画(本阶段主要讲这三个)

步长

计时器中,每一步走的长度,叫步长

动画的原理:盒子的位置 = 盒子本身所在的位置+步长。

操作对象

操作盒子的动画 -- 获取offsetLeft/offsetTop,然后赋值改变style.left/top

操作真个网页的滚动动画 -- 获取document.body.scrollTop/scrollLeft,然后改变window.scroll(x,y)

补充:

.ani {

-webkit-animation: blink .7s infinite;

-moz-animation: blink .7s infinite;

animation: blink .7s infinite;

}


让标签,0.7s 眨动一次

匀速动画

案例:轮播图

实现原理:

JS中的轮播实现原理,没有UIScrollView

1. 设置盒子大小为轮播图大小,然后设置overflow = hidden.

2. 在盒子里放一个ul,横向排列

3. 设置定时器,改变u标签l的offsetLeft

两个需要解决的问题:

1. 图片肯定是要复用的,不可能一直加载,那么在复用跳转的一刹那,怎么让人不突兀

解决方法:在最后加一张,与第一张一模一样的。相同图片之间无动画切换,是很难看出来的。

2. 上面这些逻辑,我们都是在定时器中写的,如果是app,用户拖拽切换,怎么办?

解决方法:网页中不会有手势拖拽,不用担心。app中我们可以搞三组图片,这样第一个问题可以解决,第二个问题,除非用户闲得慌,不撒手连续拖拽,四张图片的距离,否则都不会有问题。

缓动动画(代码见animate.js)

开始特快越走越慢,非常逼真,实现的动画效果更细腻。对于做页面效果来说,缓动动画更具实际开发意义。

原理:定时器中,改变步长,让步长越来越小

缓动动画的公式:盒子位置 = 盒子本身位置+(目标位置-盒子本身位置)/ 10;(说是10更符合我们的计算,逻辑,审美,人体工程学,呵呵)

bug1:

offsetTop/offsetLeft取值是四舍五入取值,一旦当步长小于0.5的时候,比如当前位置99.4,步长0.4,就会一直死循环下去,到不了100.

解决方法:

方法一:对步长进行:正数天花板向上大、负数地板向下取整,避免出现为小数的情况。(0.4天花板是1,-0.4天花板是0,所以负数应该地板取整取值)

方法二:直接用style.top/left取值呀,干嘛非要用offsetTop/offsetLeft,搞不明白,就为了省那一个单词的长度?


自己封装的缓动框架不足

很多属性我们的框架无法获取值和赋值。

border-radius: 1px 21px 41px 1px ;

在火狐、IE里面有时候,border-radius可能会赋值失败,

很多浏览器支持的是

div.style.borderTopLeftRadius = "50px";

div.style.borderBottomRightRadius = "50px";


opacity: 0.5;

值为小数,获取的时候要特殊处理。

兼容问题。IE678不识别opacity;

透明度,一般我们写的时候,写百分数的值,比如0.3,写30,不要以小数的形式传输和计算(算步长的时候,小数计算可能会有问题),因为JS里面有小数精度丢失的问题

background: rgba(0,0,0,.4);

z-index: 1; // zIndex这个写法,貌似也行

层级的提高是一次性直接提到最高,并不需要缓动

在缓动动画中,判断是不是这几个值,如果是拿出来单独获取值和赋值

案例:旋转木马

PC端区别于APP的一点,就是手指拖动,所以,这个如果iOS要做,我们只能用本身自带滑动效果的UIScrollView、UICollectionView来做。而这里:用几个盒子就行,一个盒子数组对应一个样式数组,一一对应,在我们左右转动的时候,改变样式数组的元素顺序,然后再遍历盒子数组赋值

核心还是缓动动画