DOM&BOM.1

第一章

1.什么是DOM

DOM: Document Object Model(文档对象模型)

是JavaScript的方法,仅当与特殊文档对象配合使用时(如选择器),才能发挥作用

什么是: 专门操作网页内容的API标准

        W3C指定的标准,所有浏览器厂商遵照实现

何时: 今后只要操作网页内容,就必须用DOM提供的API

为什么: 为了统一操作网页内容的API

        用DOM标准操作网页内容几乎100%兼容

分为: 核心 DOM 和 HTML DOM

核心DOM: 万能,但繁琐

HTML DOM: 对核心DOM中部分常用API的简化,专门操作HTML文档的API

           不是万能,但简洁

总结: 实际开发中不必区分核心DOM和HTML DOM,优先使用简单的API,如果实现不了,用复杂的补充

DOM树:

什么是: 网页中的一切内容在内存中都是以树形结构存储在一起的,每项内容(元素,属性,文本)都是树上的一个节点对象

为什么: 树形结构是保存不确定层级深度的上下级包含关系最好的结构

根节点:树结构都有唯一的一个根节点:document节点,所有网页内容,都是document的子节点

节点对象: 网页中的每一项内容都是一个节点对象,节点对象封装了节点可用的属性和功能

如何:三大属性(返回的值):

.nodeType: 节点类型

什么是: 定义了节点的类型

何时: 区分节点的类型时

为什么: 不同类型的节点可用的属性和可执行的操作不同

值是整数:4个: document: 9   根节点

              element:   1    元素节点,如<html>、<body>、<p>

              attribute: 2    属性节点,元素的属性,如a标签的链接属性

              text:      3    文本节点,标签中的纯文本

document.createTextNode("..."): 创建文本节点(无标签),括号内为文本值

问题: nodeType无法进一步区分具体的元素名

解决:nodeName

.nodeName: 节点名(元素的标签名)

什么是: 保存节点名称的属性

何时: 进一步区分具体的元素名

为什么: 不同的元素拥有的属性和可执行的操作都不一样

包括: document:  #document

      element:   元素的标签名(全大写)

      attribute: 属性名

      text:      #text(文本节点)

其实, nodeName可代替nodeType来鉴别节点类型

.nodeValue: 节点值(了解)

什么是: 保存节点的值(几乎不用)

包括: document:  null

      element:   null

      attribute: 属性值

      text:      文本内容

_______________________________________________________________________________________________

DOM 操作流程:(增删改查+事件处理)

查找触发事件的元素 → 绑定事件处理函数 → 查找要修改的元素 → /添加/删除/修改:内容/属性/样式

_______________________________________________________________________________________________

2.查找:4种:

1. 不需要查找可直接获得的元素:

   document.documentElement: html

  document.head:            head

  document.body:            body

2. 按节点间关系查找:

何时: 如果已经获得一个元素,要找周围元素时

包括: 2大类关系:

节点树: 包含所有节点的完整树结构

父子:elem.parentNode: 获得一个节点的父节点

      elem.childNodes:   获得父节点下的所有直接子节点

      elem.firstChild:   获得父节点下的第一个直接子节点

      elem.lastChild:    获得节点下的最后一个直接子节点

兄弟: elem.nextSibling:     获得一个节点相邻的下一个兄弟节点

      elem.previousSibling: 获得一个节点相邻的前一个兄弟节点

问题: 受看不见的空字符文本节点的干扰,可用元素树解决

元素树: 仅包含元素节点的树结构(父子关系中与CSS有差异)

何时: 只要仅关心元素,不关心其它类型的节点时

父子: elem.parentElement:        获得一个节点的父元素

     elem.children:           获得父元素(elem)下的所有直接子元素

     elem.firstElementChild:获得父元素(elem)下的第一个直接子元素

     elem.lastElementChild:获得父元素(elem)下的最后一个直接子元素

兄弟:elem.nextElementSibling:   获得一个元素相邻的下一个兄弟元素

      elem.previousElementSibling:获得一个元素相邻的前一个兄弟元素

说明: 元素树不是一棵新树,仅是节点树的一个子集

优: 不受空文本的干扰

缺: IE8不兼容

比较:childNodes和children返回的不是数组,而是类数组对象

  类数组对象: 长的像数组的对象

  VS 数组: 相同: 1.下标;2.  .length;3.用for循环遍历

           不同: 类型不同,API不通用

非动态/动态集合可以直接在选择器后面加数字下标使用: elem.children[i]

其实,childNodes和children都返回动态集合

动态集合: 不实际存储数据,每次访问集合,都重新查找DOM树

  问题: 反复访问集合,会导致反复查找DOM树

  遍历动态集合: 错误: for(var i=0;i<children.length;i++){...}

                正确:for(var i=0,len=children.length;i<len;i++){...}(按值传递)

用节点间关系,遍历查找一个父元素下所有后代节点

1. 递归遍历: 2步:

  ① 定义函数仅遍历直接子节点

  ② 对每个碰到的子节点,调用和父节点完全相同的函数

算法:深度优先: 每当同时有子元素和兄弟元素时,总是先遍历子元素。子元素遍历完,才返回遍历兄弟元素

问题: 递归的执行效率极低,可用循环代替

arguments.callee: 专门指代当前正在调用的函数自己

何时: 只要递归,在函数内调用自己,必须加arguments.callee()代替

为什么: 避免修改外层函数名后,还要重复修改内部调用的函数名

强调: 因为递归算法效率极低,所以ES6或新版浏览器中已经禁止使用arguments.callee,意味着不再推荐使用递归算法

caller    返回一个对函数的引用,该函数调用了当前函数

functionName.caller:  functionName对象是所执行函数的名称

callee    返回正被执行的Function对象,也就是所指定的Function对象的正文

[function.]arguments.callee:  可选项function参数是当前正在执行的Function对象的名称

2. 用循环代替递归:

节点迭代器对象(NodeIterator): 专门按照深度优先遍历的顺序依次访问每个子元素的对象

                                内置"深度优先"算法

如何用节点迭代器对象:2步:

1. 创建节点迭代器对象:

var iterator=document.createNodeIterator(         //传递四个参数

  parent,NodeFilter.SHOW_ALL,null,false        //NodeFilter.SHOW_ALL: 遍历所有节点

                     SHOW_ELEMENT                 //NodeFilter.SHOW_ELEMENT: 只遍历元素节点

);

2. 用循环反复调用NodeIterator的nextNode()函数,直到返回null退出:

do{

  var node=iterator.nextNode();        //返回当前节点(同时会首先返回parent元素)

  if(node!=null){

    console.log(node.nodeType!=3?node.nodeName:node.nodeValue);    //输出node,跳到下一个节点

  }else break;                         //如果返回null,就退出循环

}while(true);

3.按HTML查找:4种:

 ① 按id查找一个元素:var elem=document.getElementById("id值");

    强调:1.必须用document调用;2.只返回一个元素

 ② 按标签名查找多个元素: var elems=parent.getElementsByTagName("标签名");

    强调:1. 可在任意父元素上调用(标签名为*时,可查找所有后代元素)

         2. 不但找直接子元素,而且查找所有(符合条件的)后代元素

         3.返回多个元素组成的动态集合

 ③ 按name属性查找(了解): var elems=document.getElementsByName("name的值");

    何时: 查找拥有name属性的表单元素时

    强调:1. 只能用document调用

         2. 返回动态集合

 ④ 按class属性查找: var elems=parent.getElementsByClassName("class的值");

    强调:1. 可在任意父元素上调用(IE8以下不支持)

         2. 不但找直接子元素,而且找所有(符合条件的)后代元素

         3.返回动态集合

         4.只要包含指定的类名,就选择该元素,不必完全匹配

问题: 每次只能按一种条件查找,如果条件复杂,代码会很繁琐

解决: 当查找条件复杂时,要用选择器查找

4.按选择器查找: Selector API:2个:

① 只找一个元素:

 var elem=parent.querySelector("selector");

② 找多个元素:

 var elems=parent.querySelectorAll("selector");

强调:1. 可在任意父元素上调用

     2. 不仅查找直接子元素,且查找所有(符合条件的)后代元素

     3.返回非动态集合

        非动态集合: 实际存储数据,即使反复访问,也不会导致反复查找DOM树(遍历时不用缓存length)

     4. 受制于当前浏览器的兼容性要求(IE8以下不支持)

this关键字:自动获得 当前触发事件的元素对象(在函数中时,用于回调函数或有实参的函数)

if('querySelector' in document){    //检查此函数是否存在

  document.querySelector("#id");

}else{

  document.getElementById("id");

}

var elems = parent.querySelectorAll("selector");

elems是NodeList对象,无法使用一些属于数组的函数,可将elems转换为数组,就能使用这些函数

方法① var arrayElements = [].slice.call(elems);

方法② var arrayElements = Array.from(elems);

_______________________________________________________________________________________________

笔试:

按HTML查找 VS 按Selector API 选择器查找

 ① 返回值: 按HTML查找,返回动态集合

            按Selector API 选择器查找,返回非动态集合

 ② 效率: 首次查找HTML效率高

          Selector API 查找稍慢

 ③ 易用性: HTML查找更繁琐

            Selector API 查找更简洁

总结:1. 如果已经获得一个元素,找周围元素用节点间关系查找

     2. 如果通过一个条件就可找到想要的元素,用HTML查找

     3. 如果查找条件复杂时,用Selector API 选择器查找

总结返回值:

    1. 凡是返回一个元素的API,如果没找到,都返回null

    2. 凡是返回多个元素的API,如果没找到,都返回空元素的集合

_______________________________________________________________________________________________

过渡动画: 不要用display

① js中: 用支持过渡的css属性修改样式:width、height、opacity...

② css中: 起始样式;过渡的新属性;transition:all .5s linear...

凡是带transition的元素,无论以任何手段修改样式属性值,都自带过渡效果

测速比较:

console.time("getChildren1");    //开始:time() 和 结束:timeEnd()里的参数必须相同才能计算时间

getChildren1(document.body);

console.timeEnd("getChildren1");

console.time("getChildren2");

getChildren2(document.body);

console.timeEnd("getChildren2");

第二章*****************************************************************************************

修改内容:

.innerHTML: 获取或设置元素 开始标签到结束标签之间的HTML代码片段(设置会清除旧元素)

            单标签无返回值,没有标签的文本节点返回undefined

            不包括本身的标签,但包括子标签及其属性(转义字符和正文会相互转化)

.textContent:获取或设置元素 开始标签到结束标签之间的纯文本内容,单标签无返回值

             不包括任何标签、转义字符

                ① 去掉了内嵌的标签

                ② 将所有转义字符翻译为正文(而不是标签)

                强调: IE8不兼容,用.innerText代替

.value: 专门获得或设置 表单元素的输入内容

  注意: var a=input.value;变量string(原始类型),a="";无法改变input的输入内容

_______________________________________________________________________________________________

修改属性:

标准属性: 2种方式访问:

1. 核心DOM: 4个API: 所有属性节点都保存在元素的attributes集合中 ———繁琐

  获取指定属性值:   elem.getAttribute("属性名")             →attribute.nodeValue 属性的值

  修改指定属性值:   elem.setAttribute("属性名","属性值")

  是否包含指定属性: elem.hasAttribute("属性名")

  移除指定属性:     elem.removeAttribute("属性名")

elem.getAttributeNode("属性名");  →text.nodeValue 返回属性的节点内容,表示指定的属性和值

                              .value:  返回属性的值

指元素的第几个属性(从0开始):  elem.attributes[i];

elem.getAttributeNode(elem.attributes[i]);  →elem2.nodeValue? 返回null

2. HTML DOM: 所有标准属性都被提前封装在了元素对象中,可直接用.访问 ———简洁,首选

 获取属性值: elem.属性名

 修改属性值: elem.属性名="属性值"

 是否包含:   elem.属性名!=""        /*是否为空字符串*/

 移除属性:   elem.属性名=""         /*设置为空字符串*/

注意: div没有标准属性width/height,所以要用style.css属性名

特殊: class属性: class是JS语言的保留字,所以DOM中的class属性被迫改名为className

状态属性: .selected    .checked    .disabled    属性为boolean类型,无值

          不能用核心DOM访问,只能用HTML DOM访问,访问的结果都是boolean类型

比如: checked 属性设置或返回checkbox是否应被选中:elem.checked = true / false

注意: preventDefault 即使是在checked属性被切换的情况下也会阻止浏览器改变输入选择框的选择

自定义扩展属性: 如: data-toggle="dropdown"    //大写字母会自动转为小写

1. 核心DOM: ———繁琐

   自定义扩展属性不能用HTML DOM访问

2.HTML5语法: ———简洁

定义自定义属性:  data-属性名="值"

获取/修改属性值: elem.dataset.属性名="属性值"     /*与HTML DOM类似*/

elem.classList 属性返回元素的类名,该属性用于在元素中添加,移除及切换 CSS 类

elem.classList 属性只读,但可用.add("class1","class2")和.remove("myStyle")方法 添加/删除 类名

                 可添加/删除多个,若已存在则不会添加,删除不存在的类名也不会报错

                 但不要加空格

elem.classList 返回元素的类名组成的数组

elem.classList.length 属性返回类列表中类的数量(只读)

elem.classList.toggle(class1, true/false) 在元素中切换类名(移除返回false,添加返回true)

      第二个参数可选,设置元素是否强制添加或移除类名,不管该类名是否存在(false移除,true添加)

_______________________________________________________________________________________________

修改样式: 2种:

单独修改一个css属性

1. 内联: 写在元素的style属性中的样式

获取或设置内联样式: elem.style.css属性名="值"

注意:都要先找到元素,在使用elem.style.属性="值"来修改属性值,要分成两条语句

强调: ①css属性名都要去横线变驼峰:

         比如: background-color->backgroundColor

               list-style-type->listStyleType

      ② 所有css属性名的值都是字符串(需要带单位)

         计算前都要先去单位,转数字再计算

问题: 实际开发中可能几乎不包含内联样式,用elem.style可能无法获得任何样式

解决: 凡是读取样式,都要读取计算后的样式: getComputedStyle(elem)

ComputedStyle:计算后的样式: 最终应用到元素上的所有样式的综合,并将相对单位计算为绝对单位

如何:① var style=getComputedStyle(elem) //获得计算后的所有css属性

             //无法直接获得img的原尺寸宽高,要等图片加载完成(.onload)后才可以获得

     ② style.css属性名                      //从style中获得想要的css属性

简写为:getComputedStyle(elem).display       //获取,不建议修改

强调: 计算后的css属性都是只读,不允许修改,而应使用elem.style.css属性名,进行修改

因为计算后的css属性可能原来是共用的,一旦修改,牵一发而动全身

elem.style.cssText    批量修改元素的style属性

elem.style.cssText += elem.style.cssText + '; 样式';    //避免之前的属性被覆盖,在前面加分号避免浏览器会自动去除最后一个属性的分号

2. 内部/外部样式表: ———危险

3步:1. 找样式表对象: var sheet=document.stylesheets[i]

    2. 找cssRule对象: var cssRule=sheet.cssRules[i]

       如果是keyframes,就需要继续找下级cssRule

    3. 修改cssRule的style下的css属性值: cssRule.style.css属性=值

问题: 一次只能修改一个css属性

解决: 批量修改一个元素的多个class属性

2步: ① 先在css中将多个属性定义为一个class

     ② 在js中修改元素的className为指定的class

_______________________________________________________________________________________________

2.添加/删除/替换:

添加: 3步:

1.创建空元素: var elem=document.createElement("标签名")

   比如: var a=document.createElement("a"),相当于 <a></a>

2.设置关键属性:

   比如:a.href="http://tmooc.cn"; a.innerHTML="go to tmooc";

       相当于 <a href="http://tmooc.cn "> go to tmooc </a>

3. 将新元素添加到 DOM 树指定父元素下:

   一个新元素,必须追加到 DOM 树下指定的父元素下,才能显示出来

   3种:末尾追加:parent.appendChild(elem)    //最常用

                   //把页面上现有元素追加到另一个parent中,原先的元素会移动到那个parent中

       中间插入:parent.insertBefore(elem,child)    /*将新elem 插在旧child前面*/

       替换:     parent.replaceChild(elem,child)

_______________________________________________________________________________________________

优化: 尽量减少操作 DOM 树(即添加、修改、删除元素)

原理: 页面加载过程:  html -> DOM Tree

                               ↓

                             Render Tree ->layout-> paint(绘制)

                               ↑      计算每个元素的绝对位置

                     css -> CSSRules

为什么: 每修改一次DOM树,都会反复触发layout,降低页面响应速度

解决: 2种:

1.如果同时添加父元素和子元素时, 就要先在内存中将子元素添加到父元素中,最后再将拼好的父元素整体一次性添加到DOM树

2. 如果父元素已经在页面上,要同时添加多个平级子元素,就要用文档片段

文档片段: 内存中临时保存多个子节点的虚拟父节点

何时: 要添加多个平级子元素

如何:3步:

  ① 创建文档片段: var frag=document.createDocumentFragment();

  ② 将子元素临时追加到frag中: frag.appendChild(elem);(在这之前先创建子元素,并设置关键元素)

                                                      //比如: 可以先设置left/top、canvas先画好

  ③ 将frag整体追加到 DOM 树: parent.appendChild(frag);

说明: frag不会成为实际页面元素,将子元素添加到DOM树后,frag自动释放,不占用页面空间

删除:parent.removeChild(child);

第三章*****************************************************************************************

1.HTML DOM常用对象:

Image: 指代页面上一个img元素

创建:    var img=new Image();

指定属性:img.src="banner_01.jpg";

追加:    parent.appendChild(img);

图片加载完成再进行操作:

方法① img.onload = function(){ ... }

方法② img.onreadystatechange = function(){ if(this.readyState == "complete"){ ... }

Select: 指代页面上一个<select>元素

属性:sel.selectedIndex   获得当前选中项的下标位置

     sel.value           获得当前sel的值(value),如果选中项没有value,则用内容(innerHTML)代替

                             <select>元素的值就是当前选中项的值

     sel.options          获得当前sel下所有option元素的集合

     sel.options.length   选项的个数 <=> sel.length

     sel.options.length=0 清除所有选项 <=> sel.length=0

     sel.options[sel.selectedIndex].text 获取选中项的文本

方法:① sel.add(option)     向sel末尾追加一个option

        强调: 不支持文档片段(frag)(用frag时不用.add)

     ② sel.remove(i)   移除i位置的选项

事件:sel.onchange  当选中项发生改变时触发此事件函数

Option: 指代页面上一个option元素

创建/设置属性:var opt=new Option(text,value)     /*内容和值一起创建*/

属性:opt.text代替opt.innerHTML

_______________________________________________________________________________________________

Table:指代一个table元素: 管着行分组: 创建,删除,获取

创建行分组: var thead=table.createTHead();

            var tbody=table.createTBody();

            var tfoot=table.createTFoot();

删除行分组: table.deleteTHead();

            table.deleteTFoot();

获取行分组: table.tHead

            table.tBodies[i]

            table.tFoot

行分组:tHead tBody tFoot: 管着行tr

创建行: var tr=行分组.insertRow(i);

        说明: 如果i位置有行,则原位置的行向后顺移

固定套路: 1.末尾追加新行: 行分组.insertRow();

          2.开头插入新行: 行分组.insertRow(0);

删除行: 行分组.deleteRow(i)     /*删除当前行分组中下标为i的行*/

获取所有行: 行分组.rows

行:管着格:

创建格: var td=tr.insertCell(i)

    固定套路:末尾追加: tr.insertCell()

    强调: insertCell只能创建td

删除格: tr.deleteCell(i)

获取格: tr.cells

删除行:2种:

1. 行分组.deleteRow(i)

   i是行在行分组内的相对下标位置, 无法直接获得

2. table.deleteRow(i)

   i是行在整个table中的绝对下标位置,可直接获得: tr.rowIndex    表示tr在整个表格中的位置

固定套路:删除行: table.deleteRow(tr.rowIndex)

_______________________________________________________________________________________________

三大对话框: 弹出的是窗口(对话框,css/js改变的是body),无法改变标题、样式等

alert(): 警告框

prompt(str1,str2): 输入框

  str1: 输入框的提示信息

  str2: 文本框的默认值,默认为空

  返回值: 点击确定返回文本框中的内容,点击取消返回null

confirm(): 确认框(有确认和取消操作的对话框)

  何时:只要执行危险的操作前(提交更新、删除)都要先确认再执行操作

  如何:var bool=confirm("提示消息");

        如果点确定,就返回true,执行操作

        否则,就返回false,不执行操作

Form: 代表页面上一个form元素

获取:var form=document.forms[i/'id']   获取页面上的第i个form元素或为此id的form元素

属性: form.elements         获得表单中的所有表单元素: input select button textarea

      form.elements.length  获得表单中表单元素的个数 <=> form.length

方法:form.submit();      用程序手动提交表单(定义一个变量,提交前修改其值,防止重复提交)

何时: 只要希望通过自定义的验证去决定是否提交表单: 2种

1. <input type="button"/>(代替input->submit: 自动提交,不验证)在<input type="button"/>的单击事件中自己手动调用form.submit();

2.<input type="submit"/> 用 e.preventDefault() 阻止表单默认提交

事件: form.onsubmit=function(){ }

获取表单中的表单元素:var elem=form.elements[i/id/name]

简写:如果表单元素有name属性:   form.name

     如果表单元素没有name属性: form.elements[form.length-2]    获得倒数第2个按钮(元素)

方法:elem.focus();  让elem获得焦点

     elem.blur();   让elem失去焦点

_______________________________________________________________________________________________

2.什么是BOM:Browser Object Model(浏览器对象模型)

BOM: 专门操作浏览器窗口/软件的API(没有标准,浏览器不同)

window:2个角色:

  1. 代替ES、NodeJS中的Global充当全局作用域对象

  2. 封装所有浏览器内置的/DOM/BOM 的API

window的功能: 打开和关闭窗口,弹出对话框...

包括: history:   保存当前窗口打开后,成功访问过的url的历史记录栈,控制前进后退

      location:  保存浏览器正在打开的url的地址

      document:  封装页面内容和 DOM API的根对象

      navigator: 保存浏览器的配置信息

      screen:    保存显示设备的信息

      event:     定义事件对象

_______________________________________________________________________________________________

3.打开和关闭窗口:

打开一个新窗口: window.open("url","name")

所有在window下,都可省略window.

name: 内存中每个窗口都有一个唯一的name属性

浏览器规定: 同一个name属性的窗口只能打开1个

            后打开的同名窗口会覆盖先打开的

预定义name: _self: 用当前窗口的name打开新窗口

                   结果: 新窗口替换当前窗口

            _blank: 不指定name属性,用空name打开新窗口,让浏览器随机分配name

                    结果: 每个窗口的name都不一样,就可打开多个

第三个参数可指定窗口样式:

  如: var newWindow = window.open("url","_blank",'top=100,left=100,width=300,height=300');

      top/left: 窗口顶部距离屏幕顶部/左端的像素数(指定宽高时有效)

      width/height: 窗口的宽/高,单位像素

  可使用newWindow.close()关闭打开的窗口

打开和关闭窗口: 4种:

1. 在当前窗口打开,可后退:

   HTML: <a href="url" target="_self"></a>

   js: open("url","_self")

2. 在当前窗口打开,不可后退:

   当前窗口每打开一个新url,都会将新url保存在history中

   如果新url是追加进history中,则可后退;如果新url将当前url替换掉,则无法后退到此页面(其它正常)

   HTML: 无法实现

  js:location.replace("url")

3. 在新窗口打开,可打开多个:

   HTML: <a href="url" target="_blank"></a>

   js: open("url","_blank")

4. 在新窗口打开,只能打开一个:

   HTML: <a href="url" target="自定义name"></a>

  js: open("url","自定义name")

close():  关闭页面

窗口大小: 文档显示区的大小:

宽: window.innerWidth        高: window.innerHeight

body的宽、高(最短,不包括border、滚动条):  document.body.clientWidth/clientHeight;

屏幕可用工作区宽度(实际宽度):  window.screen.availHeight/Width;

_______________________________________________________________________________________________

4.定时器:2种:

周期性定时器:(尽量不要嵌套定时器)

若想要使等待的时间不断变化,只能在回调函数中,先清除定时器,再启动定时器(不要用var)

var reqParam = {

  arr: [0, 10000, 60000, 180000, 420000],  //请求间隔(0表示倒计时结束立即请求一次)

  max: [1, 10, 10, 10, 10],                //每种间隔最大请求次数

  index: 0,                                //请求数组的当前下标

  count: 0,                                //当前请求次数

  timer: null,                             //初始化请求次数定时器

  countTimer: null,                        //初始化倒计时定时器

  ajaxType: 'jsonp',                       //发起ajax请求的方式(可在单独页面中定义)

  jsonp: 'jsonp_callback',                 //jsonp跨域函数名

  countdown: true,                         //是否倒计时

  desc: '等待开奖',                        //不显示分、秒时的字段

  jumpIssue: true                          //是否允许跳期(在render中使用)

};

var req= function(url1, url2){    //计算请求次数的函数

 reqParam.count++;

  if(reqParam.count >= reqParam.max[reqParam.index]){  //请求次数到达限定次数,此间隔结束

    clearInterval(reqParam.timer);

   requestData(url1, url2);       //清理定时器之后,立即请求一次(本轮的最后一次)

    console.log("请求数组的当前下标:"+reqParam.index+"\n"+

    "当前请求次数:"+reqParam.count+"\n"+"当前间隔时间:"+reqParam.arr[reqParam.index]);

    reqParam.index++;

    if(!reqParam.arr[reqParam.index]) return;  //reqParam.arr中的请求完毕后,不再进行请求

   reqParam.count = 0;

   reqParam.timer= setInterval(function(){  //清除周期性定时器后,需要重新调用

     req(url1, url2);                        //回调自己,进行请求

    }, reqParam.arr[reqParam.index]);

  }else{

   requestData(url1, url2);        //只在此处和阶段循环结束时请求数据

    console.log("请求数组的当前下标:"+reqParam.index+"\n"+

    "当前请求次数:"+reqParam.count+"\n"+"当前间隔时间:"+reqParam.arr[reqParam.index]);

  }

}

function requestData(url1, url2){    //url1: 获取多期,url2: 获取一期

  $.ajax({

    url: url1,

    data: window.param,        //传入相应请求参数

    dataType: reqParam.ajaxType,

    jsonp: reqParam.jsonp,

    success: function(res){

      if(typeof res !== 'object'){

        res = $.parseJSON(res);

      }

      var countTimes = res.data.issueTime.recentDrawTime;    //倒计时

      if(countTimes < 0 && window.param.num === 1)

        return false;              //后续请求时,请求到的倒计时小于0,相当于没请求成功

     clearInterval(reqParam.timer);     //请求成功后,需要第一时间清除定时器

      reqParam.index = 0;

      reqParam.count = 0;

      varrand= 1000;                    //用于随机数

      if(typeof render === 'function'){   //渲染数据(并在其中防止数据重复)

       render(res.data);

      }

     reqParam.countTimer= setInterval(function(){

        countTimes--;                    //每秒减1进行倒计时

      if(countTimes > 0){

if(reqParam.countdown){

          var minute = parseInt(countTimes / 60);

          var seconds = parseInt(countTimes % 60);

          minute = minute >= 10 ? minute : '0' + minute;

          seconds = seconds >= 10 ? seconds : '0' + seconds;

          $('#timing').text(minute+':'+seconds);

        }

      }elseif(countTimes <= 0){

          clearInterval(reqParam.countTimer);          //倒计时结束,清除定时器

          $('#timing').text(reqParam.desc);

         rand*= parseInt(Math.random()*(10 + 1));     //随机0-10秒

         rand+= res.data.issueTime.queryTime*1000;    //倒计时完毕后的查询时间

          setTimeout(function(){

            console.log('随机和查询共:'+rand/1000+'秒');

            if(window.param.num){

              window.param.num = 1;   //当url1和url2相同时,修改window.param里的参数即可

            }

           req(url2, url2);           //请求一次成功后,将url1替换为url2

          }, rand)

       }

     }, 1000)

    }

  })

}

$(function(){

 requestData(url1, url2);    //第一次请求数据不用定时器,所有js加载完毕后开始请求

})

什么是: 让程序每隔一段时间间隔反复执行一项任务(可在定时器中改变某个变量)

何时: 只要让程序每隔一段时间间隔反复执行一项任务

如何: 3件事:

1.任务函数: function task(){...}

   定义了定时器每次要执行的任务,可用if判断临界值,执行操作(如停止定时器)

     停止当前定时器要把函数放在定时器内,不能单独定义

2.启动定时器: var timer=setInterval(task,间隔(ms))    //不要多次声明(var),可以直接用(=)

   强调:task是回调,不用加(),要传参数时可以把要执行的函数放在回调函数内

   其中: timer是定时器在内存中唯一标识的一个整数序号(从1开始)

   何时: 只要一个定时器可能被停止,都要在启动时先保存序号(var timer=...)

3.停止定时器: clearInterval(timer)

   其中: timer是要停止的定时器序号

   问题: 停止定时器不会自动清空timer变量中的序号,有可能影响下次启动

   解决: 建议先停止定时器时,再手动清空timer(timer=null)

2种方式:① 手动停止: 用户通过操作来停止定时器(用timer!=null判断启动/停止)

        ② 自动停止: 在任务函数内反复判断临界值

                     只要达到临界值,就自动停止定时器

一次性定时器:

什么是: 让程序先等待一段时间,再自动执行一次任务,执行一次后自动停止

何时: 只要让程序先等待一段时间,再自动执行一次任务

如何: 3件事: 1. 任务函数:   function task(){...}

             2. 启动定时器:var timer=setTimeout(task,等待ms)

             3. 停止定时器:clearTimeout(timer);

                           用于在任务执行前,取消等待,不再执行

window.onload: 当页面中所有内容(html,css,js)都加载完,才自动触发onload事件

原理: 定时器中的回调函数(task)只能在主程序所有语句执行完才能开始执行

笔试:

var a=10;

setTimeout(function(){console.log(a);},0);  //先算a++,再输出11

a++;

注意:js中所有的异步回调函数(如定时器、ajax)都在正常代码(非异步代码)执行完之后才执行

原因: JavaScript是单线程执行的

注意:① 定时器有一个最小执行时间,IE8及以下最小15.6ms,其它最少4ms

     ② 定时器中的this默认指向window,可使用bind()改变回调函数中的this

     ③ 定时器的第3、4...个参数表示第一个参数(回调函数)传入的参数

     ④ 微信内置浏览器中,等待时间为0时,定时器可能会失效,建议改为10ms

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容