====DOM===========================================================================
=DAY-01=====================================
正课:
1. 什么是DOM
2. *DOM Tree
3. *查询: 4种
1. 什么是DOM: Document Object Model
什么是:
专门操作网页内容的统一的API标准——W3C
为什么:
早期的DOM时木有标准,存在严重的兼容性问题
DOM就是为了统一操作网页内容的API标准
用DOM操作网页内容,几乎100%兼容所有浏览器
何时:
只要操作网页内容,都用DOM
原生JS:只需要浏览器,不需要下载第三方软件,就可以操作
ECMAScript(核心语法)
+DOM(操作网页内容)
+BOM(操作浏览器窗口)
如何:
2. DOM Tree:
什么是:
在内存中,存储网页中所有内容的树型结构
为什么:
树型结构最好的展现层次关系结构,且可无限向下延伸。
何时:
当浏览器读到网页内容时,就会自动在内存中创建树形结构
只要存储不确定层级深度的上下级关系,都用树型结构
如何:
自动创建,自动维护
1. 当浏览器读取到HTML文档时,开始创建
2. 首先创建根节点document
document对象是整棵DOM树的树根
所有网页内容,都是document节点的后代节点
3. 依次读取网页中每个元素,属性,文本
网页中每项内容(元素,属性,文本)都是DOM树上的一个节点对象。
节点对象: 所有节点都是node类型的节点对象
三大属性:
1、nodeType: 节点类型
何时: 只要鉴别节点的类型时
值是一个整数,包括:
document 9
element 1
attribute 2
text 3
问题: 只判断是否为元素,无法细致区分元素的标签名
2、nodeName: 节点名称
何时: 只要进一步区分元素的名称时
包括:
document #document
element 全大写的标签名***12个记这一个就够了
attribute 属性名
text #text
3、nodeValue: 表示节点的值——了解
何时使用:几乎不用
document null
elem null
attr 属性值
text 文本内容
DOM: *查询,修改,添加,删除,事件绑定
所有DOM操作,都遵循4步
1、查找触发事件的元素
2、绑定事件处理函数
3、查找要修改的元素
4、修改其内容
3. 查找: 4种: ***
1.VIP 不需要查找就可直接获得元素:
document.documentElement -->html
document.head -->head
document.body -->body
document.forms[i(下标)/id/name] -->form
2. 按节点间关系查找:
什么是:
DOM树中任何节点都不是孤立的。
一个节点和父级,子级,兄弟之间都建立了联系
何时:
如果已经获得一个节点,找周围附近的有关系的节点时
如何: 2大类关系:
节点树: 包含所有网页内容(元素,文字)的完整树结构
1. 父子关系:
elem.parentNode 获得elem的父节点
返回值: 唯一的一个父节点对象
elem.childNodes 获得elem的所有*直接*子节点
返回值: 所有直接子节点组成的类数组对象
elem.firstChild 获得elem下的第一个子节点
elem.lastChild 获得elem下的最后一个子节点
2. 兄弟关系:
elem.previousSibling 获得elem的前一个兄弟节点
elem.nextSibling 获得elem的后一个兄弟节点
问题:
受看不见的空字符的干扰
一切文本都是节点对象,包括看不见的空字符,
也是节点对象(tab,空格,换行)
解决: 元素树
元素树: 仅包含元素节点的树结构
优: 不受看不见的空字符的干扰
1. 父子关系:
elem.parentElement 获得elem的父元素
.parentNode 父元素只会是元素
elem.children 获得elem的所有*直接*子元素
返回值: 所有直接子元素组成的类数组对象
elem.firstElementChild 获得elem下的第一个子元素
elem.lastElementChild 获得elem下的最后一个子元素
2. 兄弟关系:
elem.previousElementSibling 获得elem的前一个兄弟元素
elem.nextElementSibling 获得elem的后一个兄弟元素
元素树不是一颗新树,只是节点树的一个子级
问题: 1. IE9+
2. 遍历指定父节点下的所有后代节点: ——鄙视
问题: children和childNodes只能查找直接子节点,无法查找更深层次!
解决: 递归遍历:
如何: 2步:
1. 先定义函数,仅遍历直接子节点
2. 对每个直接子节点,调用和父元素完全相同的方法
算法: 深度优先遍历:
什么是:
每次同时碰到子元素和兄弟元素时,总是优先遍历子元素。
所有子元素遍历完,才返回遍历兄弟。
问题: children和childNodes返回动态集合
什么是: 不实际存储数据,每次访问集合,都重新查找DOM树.
优: 首次查找,不需要返回完整数据,效率高!
缺: 反复访问集合,导致反复查找DOM树,效率低!
错误: for(var i=0;i<children.length;i++)
解决: 遍历时,提前缓存length
正确: for(var i=0,len=children.length;i<len;i++)
问题: 递归效率低,避免使用
解决: 用循环代替:
节点迭代器: NodeIterator:
什么是:
可按深度优先遍历的顺序,依次遍历下一个节点的对象
如何: 2步:
1. 用父元素创建节点迭代器对象:
var iterator=document.createNodeIterator(
parent,NodeFilter.SHOW_ELEMENT(遍历元素节点),null,false
开始位置 .SHOW_ALL(遍历所有节点)
);
2. 循环调用Iterator迭代器的nextNode()方法:获取下一个节点对象
nextNode()2件事:
1. 返回当前节点,
2. 跳到下一个节点
如果没有后续节点,返回null
do{
var node=iterator.nextNode();
if(node)//if(node!=null)
console.log(node.nodeName);
else
break;
}while(true)
3. 按HTML查找: 4种:
1. 按id查找:
var elem=document.getElementById("id");
强调: 只能用document调用!
返回值:
返回一个元素(id重复时,返回第一个)
找不到时,返回null
2. 按标签名(tag name)查找:
var elems=parent.getElementsByTagName("标签名");
强调:
1. 可在任意父元素上调用!
2. 不仅找直接子元素,且查找所有后代中的元素
返回值:
返回包含多个元素的动态集合(类数组对象)
找不到,返回length为0的空集合
3. 按name属性查找:(表单常用这个)
var elems=document.getElementsByName("name");
强调: 只能用document调用
返回值:
返回包含多个元素的动态集合(类数组对象)
找不到,返回length为0的空集合
4. 按class属性查找:
var elems=parent.getElementsByClassName("class");
返回值:
返回包含多个元素的动态集合(类数组对象)
找不到,返回length为0的空集合
强调:
1. 可在任意父元素上调用!
2. 不仅找直接子元素,且在查找所有后代
3. 如果一个元素同时被多个class修饰时,只要其中一个class匹配,就可找到该元素
问题: 每次只能按一种条件查找,当查找条件复杂时,步骤就非常繁琐。
解决: 用选择器查找
4. 按照选择器查找:
为什么:
按HTML查找,每次只能按一个条件查找
如果查找条件复杂时,步骤会很繁琐
何时:
只要查找条件复杂时,都用选择器查找
1. 仅查找一个元素:
var elem=parent.querySelector("选择器");
返回值:一个元素对象,没找到,返回null
2. 查找多个元素:
var elems=parent.querySelectorAll("选择器");
返回值:
包含所有符合条件元素的非动态集合
如果找不到,返回length为0的空集合
非动态集合: 实际存储完整数据,即使反复访问集合,也不会反复查找DOM树
强调:
1. 可在任何父元素上调用
2. 不仅查找直接,切查找所有后续元素
3. 受制于浏览器的兼容性限制
鄙视:getElementsByTagName VS querySelectorAll
返回值:
html-->动态集合for(var len=xxx.length)
选择器查找-->非动态集合
首次查找:
前者块,后者慢
易用性:
总结:如果只要一个条件就可获得想要的
=DAY-02======================================================================
4. 修改: 3种:
1. 内容: 3种:
1. 获取或修改元素的HTML代码片段内容:(代码)
elem.innerHTML
2. 获取或修改元素的纯文本内容(网页显示的)
elem.textContent vs innerHTML:
1. 去掉内嵌标签
2. 将转移字符翻译为原文
说明:兼容性
3. 获取或修改表单元素的值
elem.value
2. 属性:
1. HTML标准属性: HTML中规定的值,值为字符串类型的
2种:
1. 核心DOM:
支持操作一切结构化文档(html和xml)的统一API
优点: 万能!几乎可以做任何事情
缺点:繁琐!
(属性节点都保存在elem的attributes集合中
var node=elem.attributes["属性名"];
var value=node.nodeValue;)-这句他没讲
获取: var value=elem.getAttribute("属性名")
修改: elem.setAttribute("属性名","值")
判断有没有: var bool=elem.hasAttribute("属性名") 有-true
移除: elem.removeAttribute("属性名")
2. HTML DOM:
专门操作HTML文档的简化版DOM API
特点: 简洁, 不是万能!
原理: HTML DOM将所有HTML标准属性,已经提前预定义在了元素对象上,默认值为""
如何:
获取: var value=elem.属性名
修改: elem.属性名=值
判断有没有: elem.属性名!=="" 有true
移除: elem.属性名=""
特例: class属性:obj.class类型名=> .className样式类名
核心DOM: 可直接使用class
HTML DOM: 必须换为.className => 就是HTML中的class
因为js的对象中已经提前有一个内部属性class,用来记录对象创建时的类型名
2. 状态属性: disabled selected checked
特点: 值是bool类型
不能用核心DOM操作,因为核心DOM只能操作字符串类型
只能用HTML DOM 打. 操作
都有对应的选择器: :check :
3. 自定义扩展属性:
什么是: 自定义的,不在HTML标准范围内的属性
为什么:
id的问题: 唯一!
class的问题: 不稳定,可能随时人为或被程序修改
何时:
1、只要标识多个元素,且不希望受个数和样式修改影响
2、代替id,elem,class选择器,用于选中触发事件的元素
3、保存自定义的业务数据
总结: 今后,只要给元素添加行为时,查找元素都用自定义扩展属性
如何:
1.html中定义:<ANY data-属性名="值"...
说明:data- 只是扩展属性的前缀标志,并不是属性名的一部分
选择器:[data-属性名=值]
2. 获取或设置: 2种:
HTML DOM无法操作自定义扩展属性,
因为自定义扩展属性,无法提前预定义在DOM元素上
1. 核心DOM
2. HTML5:
elem.dataset.属性名
说明:dataset会收集所有data-XX前缀的扩展属性
访问时,仅凭elem.dataset.XX就可以
3. 样式: 2种:
1. 内联样式:
用style设置的css属性,默认出现在内联样式中
特点: 优先级最高, 仅当前元素独有
修改:
1. 仅修改一个内联样式
elem.style.css属性名=值
强调: 所有css属性名要去横线变驼峰
比如: z-index => zIndex
font-size=> fontSize
background-position=>backgroundPosition
2. 批量替换内联样式:
elem.style.cssText="...";
获取:
错误: elem.style.css属性
style仅表示内联样式,elem.style只能获得内联延时,无法获得外部样式,丢样式
解决: 获得计算后的样式:
什么是: 最终应用到当前元素上的所有样式的合集
为什么: 一个元素的完整样式,可能来源自多个地方
何时: 只要获取样式,都要获得计算后的完整样式!
如何: 2步:
1. 获得计算后的完整style对象
var style=getComputedStyle(elem);
2. 获得style中的css属性值;
var value=style.css属性;
强调: 计算后的样式style是只读的,不能修改!
2. 修改样式表中的样式: ——了解
1. 获得样式表对象:sheet
var sheet=document.styleSheets[i];
2. 获得要修改的属性所在的cssRule(样式表对象中的一套规则:(一对儿{}中的内容)
var rule=sheet.cssRules[i];
说明: 如果是keyframes 继续获得
继续: var sub_rule=rule.cssRules[i]
3. 修改样式:
rule.style.css属性=值
问题: 一句话只能修改一个css属性值
解决: 今后都是用class来批量修改元素的样式
所有DOM操作,都遵循4步
1、查找触发事件的元素
2、绑定事件处理函数
3、查找要修改的元素
4、修改其内容
=DAY03========================================================
5. 添加和删除:
3步:
1. 创建空元素:
var elem=document.createElement("标签名");
ex:
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树
3种:
指定父元素末尾追加: parent.appendChild(a)
在当前子元素前插入: parent.insertBefore(a, child) 将a插入到child之前
替换现有子元素: parent.replaceChild(a, child) 用a替换child
DOM优化:
尽量减少操作DOM树的次数
为什么:
每次操作DOM树都会导致重新layout和paint
什么是layout?
网页的加载原理:
html -> DOM Tree
↓
Render Tree-> ***layout*** -> paint
↑ 计算每个元素的
css -> COM 绝对布局位置
只要修改DOM树, 包括: 修改样式,修改位置,添加删除元素
都会导致重新layout ——>效率低
解决:
1. 如果同时添加父元素和子元素时,
都要先在内存中将所有子元素,添加到父元素中,
最后,再将父元素,一次性添加到DOM树。
2. 如果父元素已经在树上,要同时添加多个平级子元素时:
先将多个子元素添加到文档片段中,再将文档片段一次性添加到DOM树中
文档片段:
什么是: 内存中,临时存储一棵dom子树片段的存储空间(虚拟父元素对象)
何时: 只要同时添加多个平级子元素时
如何: 3步:
1. 创建文档片段对象
var frag=document.createDocumentFragment();
2. 先将子元素添加到文档片段中
frag.appendChild(child)
3. 将文档片段一次性添加到DOM树指定父元素下
parent.appendChild(frag)
强调: frag将子元素送到dom树后,自动释放
删除:
parent.removeChild(child)
child.parentNode.removeChild(child);
2. HTML DOM常用对象:
什么是:
对常用的元素,提供了简化版的API
优: 简化
缺: 不是万能
Image: 创建: var img=new Image();
Select:
属性:
.value 当前选中项有value属性时,会返回option的value
如果选中项没有value属性,则用内容代替
.selectedIndex 快速获得当前选中项的下标位置
.options: 获得select下所有option元素对象的集合
.options.length 获得select下option个数
.length => .options.length
固定套路: 清空所有option
sel.innerHTML="";(包打天下)
sel.length=0; =>sel.options.length=0;清除所有option
方法: add(option) 代替 appendChild(option)
问题: .add不支持frag(文档片段)
.remove(i) 移除i位置的option
%、Option:***
创建: var opt=new Option(text,value);
属性: .index .text .value
%、table:管着行分组:
创建:
var thead=table.createTHead();
var tbody=table.createTBody();
var tfoot=table.createTFoot();
删除:
table.deleteTHead();
table.deleteTFoot();
获取:
tabel.tHead table.tFoot table.tBodies[i]
%、行分组:管着行:
创建: var tr=行分组.insertRow(i)
在i位置插入一个新行,原i为位置的行 向后挤压
固定套路:
1.在开头插入一行: 行分组.insertRow(0)
2. 在结尾追加一行: 行分组.insertRow()
删除: 行分组.deleteRow(i)删除i位置的行
强调: 主语是行分组时,i要求是在行分组内的相对下标位置
问题:行分组内的相对下标无法自动获取
解决:table.deleteRow(tr.rowIndex)
tr.rowIndex可自动获得当前tr相对于整个表格的下标位置
table.deleteRow(i) i刚好需要相对于整个表格的下标位置
获取: 行分组.rows 获得行分组内所有行的集合
%、行:管着格:
创建: var td=tr.insertCell(i)
固定套路: 末尾追加: tr.insertCell()
强调:只能创建td不能创建th
删除: tr.deleteCell(i)
获取: tr.cells
form:
获取: var form=document.forms[i/id/name];
属性: form.elements 获得表单中所有表单元素的集合
强调: 表单元素包括: input select textarea button
form.elements.length 获得表单中表单元素的个数
form.length==> form.elements.length
固定套路: 获得结尾的按钮:
var btn=form.elements[form.length-1]
方法: form.submit() //手动提交表单
表单元素:
获取: var elem= form.elements[i/id/name]
如果表单元素有name属性,则: form.name属性值
方法: elem.focus() 让当前表单获得焦点
elem.blur()让当前元素失去焦点
=====================================================
BOM: Browser Object Model
什么是:
专门操作浏览器窗口或软件的API
没有标准!
window: 2个角色:
1. 代替ES中的GLOBAL充当全局作用域对象
2. 封装保存所有内置,全局的API和对象(像alert 啊等)
包括:history,location,document,navigator,screen,event
(属性: 文档显示区大小: 浏览器窗口中专门显示网页的区域
/*window.*/innerWidth,
/*window.*/innerHeight 没讲)
功能: 打开和关闭窗口:
打开窗口: window.open("url","target")
4种:
1. 在当前窗口打开,可后退
HTML: <a href="url" target="_self">
js: open("url","_self ")
2. 在当前窗口打开,不可后退
js: location.replace("新url")
用新的url代替history中当前地址
3. 在新窗口打开,可打开多个
HTML: <a href="url" target="_blank">
js: open("url","_blank ")
4. 在新窗口打开,只能打开一个
HTML: <a href="url" target="自定义的窗口名">
js:open("url","自定义的窗口名")
原理: 其实,每个窗口都有一个唯一的name属性
浏览器规定,同一时刻,同名窗口只能打开一个
后打开的会覆盖先打开的
target属性就是在为新窗口指定name名称
预定义name:
_self 自动使用当前窗口自己的name打开新窗口
_blank 不指定窗口名, 每打开一个窗口,浏览器会自动随机生成内部窗口名
关闭窗口: /*window.*/close();
history: 保存当前窗口打开后,成功访问过的url的历史记录栈
不允许修改history内容!
只能三个操作: history.go(n);
前进 history.go(1)
后退 history.go(-1), history.go(-2),
刷新 history.go(0)
location:
什么是: 保存当前窗口正在打开的url地址的对象
属性:
.href: 获取或设置完整的url地址
.protocol: 协议
.host: 主机名+端口号
.hostname: 主机名
.port: 端口号
.pathname: 相对路径
.search: ?xxx=xxx&xx=xx查询字符串参数
.hash: 锚点地址
鄙视: 将search转化为对象形式:
方法:
1. 在当前窗口打开新连接,可后退:
location.assign("url") => location.href="url"=>location="url"
2. 在当前窗口打开,不可后退:
location.replace("新url")
3. 刷新:
1、普通刷新: 优先从缓存中获取资源,缓存没有或过期,才去服务器找新的。
f5
history.go(0)
location.reload()
2、强制刷新: 无论有没有缓存,都强制从服务器获取新资源!
location.reload(true)
4. navigator:
什么是: 封装浏览器配置信息的对象
何时: 只要读取浏览器配置信息时
如何:
1. 判断浏览器是否启用了cookie
什么是: 客户端本地持久存储一个数据小文件
为什么: 程序内存中的所有数据(变量、数组、对象)都是临时存储的
何时: 只要希望在客户端持久保存用户私密数据时
如何判断是否启用cookie:
var bool=navigator.cookieEnabled
设置: 设置->高级->隐私->内容设置->查看和禁用cookie
2. 判断是否安装插件:
什么是: 保存当前浏览器安装插件的集合
什么是插件:为浏览器添加新功能的小软件
如何判断插件是否安装:
navigator.plugins["插件名"]!==undefined
3. 判断当前浏览器名称和版本号——鄙视
navigator.userAgent: 保存浏览器名称,版本和内核信息的字符串
何时: 只要判断浏览器名称和版本时就用
5. ***定时器: 2种:
1. 周期性定时器:
什么是: 让程序每隔一端时间间隔,自动反复执行一项任务
何时: 只要让程序按照指定的时间间隔反复执行一项任务
——动画!
如何: 3步:
1. 定义任务函数: 变化一次的函数
function task(){...}
2. 将任务函数放入定时器中反复执行:
var timer=setInterval(task,ms)
启动定时器,让定时器每隔ms毫秒,自动反复执行task函数
其中: timer 指当前定时器唯一的序号
专门用于停止定时器之值
3. 停止定时器: clearInterval(timer)
2种: 1. 定时器自动停止:
在任务函数中,设定临界值
一旦达到临界值,就自动调用clearInterval
2. 手动停止定时器
2. 一次性定时器:
一次性: 让程序先等待一段时间,再延迟执行一项任务
执行后,自动停止
何时: 只让程序延迟执行一项任务,且不需要反复执行时
如何: 3步:
1. 任务函数:
2. 启动定时器: timer=setTimeout(任务函数,ms)
其中: ms指延迟的毫秒数
3. 停止定时器: clearTimeout(timer)
在执行前,停止等待,不再执行任务
3.定时器原理:
setTimeout 和 setInterval只是将任务函数,保存到定时器中,
必须等到主程序所有语句执行完,才能执行!
鄙视: 定时器中的任务函数,必须等到主程序所有语句执行完,才能执行!
1.var a=10;
function fun(){
a++;
}
setTimeout(fun,0);
setInterval
//fun无论等待多长时间都必须到最后才执行
console.log(a);//10
2.for(var i=0;i<3;i++){
setTimeout(()=>console.log(i),0);
}//3 3 3
6. ***event: ——DOM
什么是:
用户手动触发的或浏览器自动触发的 页面内容状态的改变。
事件处理函数:
当事件发生时,自动调用执行的函数
所有事件处理函数:
this->elem 当前触发事件的.前的元素
何时:
今后只要希望触发事件时,自动执行一项任务,就要提前绑定事件处理函数
绑定事件处理函数: 3种:
1. 在HTML中绑定事件处理函数: (组件开发中常用)
html:<ANY ... on事件名="js语句/js函数调用" ...>
js:function 函数(){...}
问题:
1. 不便于集中管理事件
2. 不便于灵活重用
总之: 不符合内容与行为分离的原则
2. 在js中,用赋值方式绑定:
elem.on事件名=function(){
this->elem 当前触发事件的.前的元素
}
问题:
是用=赋值的方式给事件属性赋值的,后赋值的处理函数会覆盖先赋值的
(赋值是替换原函数。每个事件只能绑定一个处理函数)
3. 在js中,为元素添加事件监听对象:
elem.addEventListener("事件名",handler)
优:
一个事件,可同时添加多个处理函数
可随时添加和移除
如何移除:移除处理函数时,必须找到原处理函数对象
elem.removeEventListener("事件名",原handler);
强调:
如果一个处理函数,可能被移除,
则绑定时,就必须用有名的函数。不能用匿名函数。
事件模型: 当事件触发后,发生的一系列行为过程——鄙视
DOM标准认为: 点在内层元素上,也等效于点在外层元素上了
3个阶段:
1. 捕获: 由外向内记录各级父元素上绑定的处理函数
捕获阶段只记录处理函数,不执行!
2. 目标触发:
目标元素: 最初实际触发事件的元素
优先触发内层目标元素上的事件处理函数
3. 冒泡: 由内向外,按捕获阶段顺序的反向,依次触发各级父元素上的事件处理函数
事件对象:e
什么是:
事件发生时,自动创建的记录事件信息的并提供修改事件默认行为的API对象
何时:
1、只要获得事件的信息
2、修改事件的默认行为
如何:
创建: 自动创建
获取: 事件对象e默认总是作为处理函数的第一个参数,自动传入。
API:
1、取消冒泡: e.stopPropagation();
2、利用冒泡:
优化: 尽量减少事件监听的个数
为什么: 浏览器触发事件处理函数,是用遍历方式查找处理函数并执行。
遍历的效率取决于遍历次数。
何时: 只要多个平级子元素,要绑定相同事件时
如何: 只要在父元素上绑定依次处理函数,所有子元素自动共用!
2大难题:
1. 获取目标元素:
错误: this->指向父元素
正确: e.target->始终保存着最初触发事件的目标元素
且不随冒泡而改变!
2.判断e.target是否是想要的:
手段:nodeName, 元素名, class属性, 内容...
阻止事件(默认行为):
什么是:
当事件处理函数过程中,可取消事件的触发
何时:
1、默认行为不是想要的,就要阻止
2、出错时,不想继续执行下去了
如何: e.preventDefault();
三个典型:
1. <a href="#xxx"
默认: 跳到锚点,在url结尾增加#xxx
2. 阻止表单自动提交!
自定义表单提交: 2种:
1. <input type=button js: form.submit()
2. <input type=submit
=>form.onsubmit(): e.preventDefault()
3. HTML5中做拖拽效果时
必须阻止浏览器默认的拖拽行为
=DAY04==============================================================
正课:
1. 定时器:
一次性:
2. *navigator:
3. ***event
1. 定时器:
一次性: 让程序先等待一段时间,再延迟执行一项任务
执行后,自动停止
何时: 只要让程序延迟执行一项任务,且不需要反复执行时
如何: 3步:
1. 任务函数:
2. 启动定时器: timer=setTimeout(任务函数,ms)
其中: ms指延迟的毫秒数
3. 停止定时器: clearTimeout(timer)
在执行前,停止等待,不再执行任务
鄙视: 定时器中的任务函数,必须等到主程序所有语句执行完,才能执行!
var a=10;
function fun(){
a++;
}
setTimeout(fun,0);
//fun无论等待多长时间都必须到最后才执行
console.log(a);//10
2. navigator:
什么是: 封装浏览器配置信息的对象
何时: 只要读取浏览器配置信息时
如何:
1. 判断是否启用cookie
什么是: 客户端持久存储用户私密信息的小文件
为什么: 内存中的数据都是临时的
何时: 只要在客户端持久保存数据时
如何判断是否启用cookie:
var bool=navigator.cookieEnabled
设置: 设置->高级->隐私->内容设置->查看和禁用cookie
2. 判断是否安装插件:
什么是: 为浏览器添加新功能的小软件
如何判断插件是否安装:
navigator.plugins["插件名"]!==undefined
3. 判断当前浏览器名称和版本号——鄙视
navigator.userAgent: 保存浏览器名称,版本,内核信息的字符串
何时: 只要判断浏览器名称和版本时
3. ***event: ——DOM
什么是: 用户手动触发的,或浏览器自动触发的页面状态的改变。
事件处理函数: 当事件发生时,自动执行的函数
绑定事件处理函数: 3种:
1. 在HTML中绑定事件处理函数:
<ANY ... on事件名="js语句" ...>
问题: 1. 不便于集中管理事件
2. 不便于灵活重用
总之: 不符合内容与行为分离的原则
2. 在js中,用赋值方式绑定:
ANY.on事件名=function(){
this->ANY 当前触发事件的.前的元素
}
问题: 赋值是替换原函数。每个事件只能绑定一个处理函数
3. 在js中,为元素添加事件监听对象:
ANY.addEventListener("事件名",handler)
优: 一个事件,可同时添加多个处理函数
可随时添加和移除
如何移除:
ANY.removeEventListener("事件名",原handler);
问题: 如果一个处理函数,可能被移除,则绑定时,就必须用有名的函数。不能用匿名函数。
事件模型: 当事件发生时,浏览器触发事件的过程——鄙视
DOM标准认为: 点在内层元素上,也等效于点在外层元素上了
3个阶段:
1. 捕获: 由外向内记录各级父元素绑定的处理函数
捕获阶段只记录处理函数,不执行
2. 目标触发:
目标元素: 最初实际触发事件的元素
优先触发目标元素上的处理函数
3. 冒泡: 由内向外,按捕获阶段顺序的反向,依次触发父元素上的处理函数
事件对象:e
什么是: 事件发生时,自动创建的记录事件信息的对象
何时: 只要获得事件的信息,或修改事件的默认行为
如何:
创建: 自动创建
获取: 事件对象e总是作为处理函数的第一个参数,自动传入。
API:
取消冒泡: e.stopPropagation();
利用冒泡:
优化: 减少事件监听的个数
为什么: 浏览器触发事件处理函数,是用遍历方式找打处理函数并执行。
何时: 只要多个平级子元素,要绑定相同事件时
如何: 只要在父元素上绑定依次处理函数,所有子元素自动共用!
2大难题:
1. 获取目标元素:
错误: this->父元素
正确: e.target->记录了最初触发事件的元素
且不随冒泡而改变!
2. 鉴别e.target是否是想要的:
元素名, class属性
阻止默认行为:
何时: 只要一个元素的事件中,带有默认行为,且默认行为不是想要的,就要阻止
如何: e.preventDefault();
三个典型:
1. <a href="#xxx"
默认: 跳到锚点,在url结尾增加#xxx
2. 阻止表单自动提交!
自定义表单提交: 2种:
1. <input type=button js: form.submit()
2. <input type=submit
=>form.onsubmit(): e.preventDefault()
3. HTML5中做拖拽效果时
必须阻止浏览器默认的拖拽行为
=================================================================
正课:
1. ***event
鼠标坐标
页面滚动
项目:
详情页: 放大镜效果
首页楼层滚动:
1. ***event
鼠标坐标: 3对儿:
1、相对于屏幕左上角:
e.screenX, e.screenY;
2、相对于文档显示区左上角:
e.clientX, e.clientY
3、相对于当前元素左上角:
e.offsetX, e.offsetY
如何选择: 和主角的活动范围保持一致!
页面滚动:
事件: window.onscroll
属性:滚动距离: scrollTop=
1、document.body.scrollTop
2、document.documentElement.scrollTop
自定义控制滚动:
1、写死了的位置
window.scrollTo(x方向的位置(通常为0),y方向的位置)
2、滴加
window.scrollBy(x方向的位置(通常为0),y方向的位置)
====JQUERY===========================================================================
==============================
正课:
1. 修改:
用class批量修改样式
2. 添加,删除,替换,克隆
3. 事件绑定
1. 修改:
用class批量修改样式:
1. 为元素追加一个class: $(...).addClass("class名")
2. 为元素移除一个class: $(...).removeClass("class名")
3. 判断是否包含一个class: $(...).hasClass("class名")
4. 为元素切换一个class: $(...).toggleClass("class名")
if($(...).hasClass("class名"))
$(...).removeClass("class名")
else
$(...).addClass("class名")
补: .index()
2种:
1. var i=$("selector").index(jq对象/DOM对象)
查找右边的jq对象或DOM对象,在左边的结果集合中的下标位置
2. 如果在同一个父元素下找某个子元素的位置
var i=$("child").index();
2. 添加,删除,替换,克隆:
添加: 2步:
1. 用$()创建一个新元素: var $新元素=$("html片段")
2. 将新元素添加到dom树:
$("parent").append($新元素)
.prepend($新元素)
$("child").before($新元素)
.after($新元素)
可以更简化: $("parent").append/prepend("html片段")
$("child").before/after("HTML片段")
删除: $(...).remove();
补: .is("selector") 判断当前元素是否符合selector的条件
替换: $("selector").replaceWith(jq对象|DOM对象)
克隆: var $clone_elem=$(...).clone();
强调: 默认浅克隆: 仅克隆样式和属性, 不可隆行为
深克隆: 即克隆样式和属性,又克隆行为
$(...).clone(true)
3. 事件绑定:
鄙视: jQuery中共有几种事件绑定方式,区别:
DOM: .addEventListener("事件名",handler)
.removeEventListener(...)
jq:
1. $("target").bind/unbind("事件名",handler)
同addEventListener()
.unbind三种重载:
.unbind("事件名",handler) 移除当前元素上,指定事件上的名为handler的处理函数。
.unbind("事件名") 移除当前元素上,指定事件上的所有处理函数
.unbind() 移除当前元素上,所有事件的监听
2. $("target").one("事件名",handle) 同bind
区别: 只触发一次,触发后,自动解绑
3. .live/die("事件名",handle)——已废弃
原理: 将所有事件集中绑定在顶级document上
4. $("parent").delegate("selector","事件名",handler)
原理: 简化利用冒泡:
1. 获得目标元素: this->e.target
2. 筛选目标元素: 第一个参数: "selector"
只有满足"selector"要求的元素,才能触发事件
鄙视: .bind vs .delegate: 3点
1. .bind直接帮在目标元素上
.delegate 帮在父元素上
2. 监听个数: .bind 监听个数多——每个目标元素都添加
.delegate 监听个数少——只给父元素添加一个
3. 新增子元素自动获得事件处理函数:
.bind 只能对现有元素添加事件监听
新增元素无法自动获得监听
.delegate 只要父元素下的元素,无论现有,还是新增,都能自动获得父元素上统一的事件监听
5. .on/off:
1. 代替bind: .on("事件名",handler) 同bind
2. 代替delegate: .on("事件名","selector",handler)同delegate
6. .事件名:
强调: 仅对常用的事件提供了终极简化
js 和css并行执行
transition没显示
放到window.onload=function(){页面内容加载完成后在执行的}中
4、页面加载后执行: 2种:
1. DOMContentLoaded: DOM内容加载完,就可提前执行
DOM内容仅包括: html和js
提前触发
何时: 只要不依赖于css和图片的所有操作都可在DOM内容加载后,提前绑定触发
比如: 事件绑定
jq: $(document).ready(()=>{//就等于DOMContentLoaded
//DOM内容加载后,就可提前执行的操作
//比如: 事件绑定
})
简化: $().ready(()=>{
更简化: $(()=>{...})
其实: 写在body结尾的script中的代码默认就是DOM内容加载后自动执行
2. window.onload 在所有页面内容加载完成后自动触发
window.onload=function(){...}
问题:使用赋值的方式,多个的话,后面的会覆盖前面的
$(window).load(function(){})
包括: html,css,js,图片
何时: 如果必须依赖css或图片的操作
鄙视:jQuery中$的原理:
查找,创建新元素,封装(DOM封装为jQuery对象那个),DOM加载后自动执行
是jQuery类型的工厂函数,用于创建jQuery类型的子对象
有四种重载:
1、选择器作为参数:现有选择器查找DOM元素,在封装进jQuery中
jQuery对象其实就是一个类数组对象
为了加快(speed up)查找速度,
如果只给 #id 则自动优先调用 getElementById
tag TagName
.class Classname
其余复杂选择器都调用querySelectorAll
2、DOM对象作为参数:将DOM元素封装为jQuery对象
DOM不是jQuery类型的子对象,无法直接使用jQuery简化版本的API
需要先封装,在使用
3、html代码片段作为参数:创建新的DOM元素对象
4、回调函数作为参数:自动在DOM内容加载后,提前出该函数,
是一种事件绑定
鼠标事件:
1、mouseover mouseout
进出子元素,会频繁触发父元素的处理函数
2、mouseenter mouseleave
进出子元素,不再频繁触发父元素的处理函数------效率高
简写: 如果同时绑定鼠标进入和移出事件时,可简写为hover
$().hover(
fun(){...}, //给mouseenter进,不触发父元素
fun(){...} //给mouseleave出,不触发父元素
)
更简化:
如果两个处理函数,可用toggle统一为一个处理函数
则只需要传一个参数即可
模拟触发:
虽然没有触发事件,但是依然可用程序模拟执行元素的事件处理函数
如何: $(...).trigger("事件名")
其实可以更简单: $(...).事件名()
4_trigger.html
总结: jQuery简化了DOM五大操作:
查找, 修改, 添加, 删除, 事件绑定
=====================================================
正课:
1. 动画:
2. 类数组对象:
3. 插件:
css不是CPU解析的,是GPU(显卡)解析的,GPU做绘图效率更高
1. 动画:
简单动画: 3种固定动画效果
1. 显示隐藏: .show() .hide() .toggle() 记这个吧
默认:
不带参数,默认用display实现瞬间显示隐藏,不支持动画效果
带时间(ms)参数, 才有动画效果
总结: 通常都是用不带参数的方法,代替display,简化代码
2. 上滑下滑: .slideUp(ms) .slideDown(ms) .slideToggle(ms)
3. 淡入淡出: .fadeIn(ms) .fadeOut(ms) .fadeToggle(ms);
问题:
1. 用js定时器实现动画效果,效率不如css的transition
2. 效果是在jQuery库中写死的,不便于维护
万能动画: 可自定义动画要修改的css属性
$(...).animate({
css属性: 目标值,
css属性: 目标值,
... : ...
},ms,callback)
问题:
仅支持单个数值的css属性值
不支持颜色 不支持C3变换
优点:
可随意停止
$(...).动画API(ms,callback)
jQuery动画API的最后一个参数是一个回调函数:
在动画播放后自动执行。callback专门用于在动画播放后执行善后处理。
回调函数中: this->正在播放动画的DOM元素
强调: 想用this,就不能用箭头函数
并发和排队:
排队: 对同一个元素调用的多个动画API,是排队执行。
原理: 动画API并不是启动动画。仅是将动画加入一个队列中顺序执行。
并发: 在一个animate函数内,修改的多个css属性,是同时变化。
2. 类数组对象操作: 4个:
1. [i] => .get(i) 返回的是DOM元素
2. .length => .size()
3. .forEach =>
.each(function(i当前位置,elem当前DOM元素){ this->当前DOM元素 })
鄙视:$.each(obj,fun) vs $(...).each(fun)
1.存储位置:
$.each() 直接存储在构造函数上
$(...).each 存储在jQuery类型的原型对象中
2.调用方法
$.each() obj可以是任何类数组对象
$(...).each 必须是jQuery对象
4. .indexOf => $(全部).index($要查找的元素)
如果在同一个父元素内查找直接子元素 $(要查找的元素).index()
3.定义jQuery全局函数
jQuery.fn.自定义函数=function(){
// this ->将来调用该函数的jquery类型子对象
//不用$封装 已经是jQuery对象了
}
插件: 基于jQuery开发的独立的小功能,效果
为什么: 复用功能和效果,极大节约代码量
何时: 只要发现多个项目中,都用到相同的功能和效果
如何: 3种:
1. jQuery UI: jQuery官方推出的插件
官网: jqueryui.com
快速入门: jqueryui.com
手册: 官网
如何使用:
下载js和css以及图片:
强调: jquery-ui.css 必须和images文件夹同目录
引入:
jquery-ui.css
jquery-3.2.1.js
jquery-ui.js
自定义脚本
包括: 交互, 效果, 部件
2. 第三方插件:
3. *****自定义插件:
=======================
正课:
1. 插件:
官方插件: jQuery UI
***封装自定义插件:
第三方插件:
2. jQuery的Ajax封装
*****跨域请求
什么是插件:具有完整样式和功能的小功能(函数)
为什么:开发中,很多效果/功能都是重复使用的
何时:只要项目中有反复使用的功能/样式,都要先封装为组件,再反复使用组件
包括:3中
1.官方 2.第三方 3.自定义
1. 插件:
官方插件: jQuery UI
基于jQuery API实现的可复用的小功能库
如何:
下载
包括:文件夹images jquery-ui.css jquery-ui.js
其中,images要和jquery-ui.css同一目录下
.autocomplete();
HTML: <input ... />
JS: $(文本框).autocomplete({
source:客户端数组|"远程.php路径"
})
PHP: 2种:
1. 返回只有一个键的关联数组, 只要键名为label,客户端autocomplete可自动识别
2. 返回包含多个键的关联数组: 2步:
1. 再次调用:
.autocomplete("instance")._renderItem=function($ul,item){
//$ul: 自动获得当前下拉列表的ul元素
//item: 获得结果结合中,当前正在加载的元素对象
//操作: 3件事:
//1. 创建一个li>div:
//从item中获取键的值,拼接到div中
//2. 将新的li追加到$ul中
//3. 返回新的li的对象
}
2. 在autocomplete中定义select处理函数:
在单击每个列表项时自动触发:
select:function(e,obj){
//obj.item是当前li对应的原集合中的对象
//常用操作: 2个
//1. 将item中的主要内容,显示在文本框中
//2. 用当前选中项作为参数,跳转到新的url
return false;//必须
}
2. 日期选择: datepicker
HTML: <input />
CSS:
JS: $(文本框).datepicker()
3. 对话款: 表单提交
HTML:
<div id="xxx" title="标题"
<form>
...
//不用写提交和重置按钮
</form>
</div>
css:
JS: $(div).dialog(); //仅将div及其内容,变为对话框的样式
总结:
问题: jquery ui采用侵入的方式,自动加载样式和行为
优: 极大的减少了开发人员的代码量
缺: 侵入的class和行为都是写死的,不便于维护
解决: bootstrap vs jquery ui
bootstrap不采用侵入的方式,隐式添加任何代码
而是仅提供样式类库
由开发人员,自主的选择应用何种class
自定义插件:
何时: 只要在项目中发现频繁重用的功能,都要封装为自定义插件
如何提取:
前提: 必须使用HTML,css,js实现了插件的完整样式和功能
Step1: 将当前功能的css,提取到一个专门的css文件中
强调: css中尽量少的使用id,元素选择器
尽量一切都用class去实现!
Step2: 将当前功能的js行为,提取到一个专门的js文件中
在插件的js文件中查找自定义扩展属性的元素
强调: 将来插件都是通过查找自定义扩展属性来为元素添加行为的
今后,只要出发事件的元素,都要标记自定义扩展属性
如何使用:
1. 按插件要求,编写HTML内容结构
2. 引入插件的css, 在HTML中对应元素上,手动添加class
第三方插件:
1. jquery validate
$(form).validate({
rule:{
name1:"规则1",
name2:{
规则1:值1,
规则1:值2,
}
},
messages:{
消息
}
})
2. jQuery的Ajax封装:
$.ajax({
url:"xxx.php",
type:"get|post",
data:"参数数据"|{变量:值,...}| $(form).serialize(),
//jquery-1.11.3.js
//success:data=>{...}
})//jquery-3.2.1.js
.then(data=>{...})
补充: jquery表单操作:
$(form).serialize()
=====================================
正课:
1. 插件:
官方插件: jQuery UI
***封装自定义插件:
第三方插件:
2. jQuery的Ajax封装
*****跨域请求
1. 插件:
官方插件: jQuery UI
.autocomplete();
HTML: <input ... />
JS: $(文本框).autocomplete({
source:客户端数组|"远程.php路径"
})
PHP: 2种:
1. 返回只有一个键的关联数组, 只要键名为label,客户端autocomplete可自动识别
2. 返回包含多个键的关联数组: 2步:
1. 再次调用:
.autocomplete("instance")._renderItem=function($ul,item){
//$ul: 自动获得当前下拉列表的ul元素
//item: 获得结果结合中,当前正在加载的元素对象
//操作: 3件事:
//1. 创建一个li>div:
//从item中获取键的值,拼接到div中
//2. 将新的li追加到$ul中
//3. 返回新的li的对象
}
2. 在autocomplete中定义select处理函数:
在单击每个列表项时自动触发:
select:function(e,obj){
//obj.item是当前li对应的原集合中的对象
//常用操作: 2个
//1. 将item中的主要内容,显示在文本框中
//2. 用当前选中项作为参数,跳转到新的url
return false;//必须
}
2. 日期选择: datepicker
HTML: <input />
CSS:
JS: $(文本框).datepicker()
3. 对话款: 表单提交
HTML:
<div id="xxx" title="标题"
<form>
...
//不用写提交和重置按钮
</form>
</div>
css:
JS: $(div).dialog(); //仅将div及其内容,变为对话框的样式
总结:
问题: jquery ui采用侵入的方式,自动加载样式和行为
优: 极大的减少了开发人员的代码量
缺: 侵入的class和行为都是写死的,不便于维护
解决: bootstrap vs jquery ui
bootstrap不采用侵入的方式,隐式添加任何代码
而是仅提供样式类库
由开发人员,自主的选择应用何种class
自定义插件:
何时: 只要在项目中发现频繁重用的功能,都要封装为自定义插件
如何提取:
前提: 必须使用HTML,css,js实现了插件的完整样式和功能
Step1: 将当前功能的css,提取到一个专门的css文件中
强调: css中尽量少的使用id,元素选择器
尽量一切都用class去实现!
Step2: 将当前功能的js行为,提取到一个专门的js文件中
在插件的js文件中查找自定义扩展属性的元素
强调: 将来插件都是通过查找自定义扩展属性来为元素添加行为的
今后,只要出发事件的元素,都要标记自定义扩展属性
如何使用:
1. 按插件要求,编写HTML内容结构
2. 引入插件的css, 在HTML中对应元素上,手动添加class
第三方插件:
1. jquery validate
2. jQuery的Ajax封装:
$.ajax({
url:"xxx.php",
type:"get|post",
data:"参数数据"|{变量:值,...}| $(form).serialize(),
//jquery-1.11.3.js
//success:data=>{...}
})//jquery-3.2.1.js
.then(data=>{...})
补充: jquery表单操作:
$(form).serialize()