跳到主要内容

17-JavaScript-事件

运用 element 修改 DOM 元素

主要作用于对 html 标签元素进行增删改查,加入条件判断可完成事件的触发

方法返回指定属性节点
element.getAttribute()返回指定元素的属性值
element.getAttributeNode()返回指定属性节点
element.hasAttributes()如果元素有任何属性返回 true,否则返回 false。
element.hasAttribute()如果元素中存在指定的属性返回 true,否则返回 false。
element.removeAttribute()从元素中删除指定的属性
element.removeAttributeNode()删除指定属性节点并返回移除后的节点。
element.setAttribute()新增或者改变指定属性并指定值。
element.setAttributeNode()设置或者改变指定属性节点。

三种方法操作元素中的内容

let oDiv = document.querySelector('div')
console.log(oDiv.innerHTML)
console.log(oDiv.innerText)
console.log(oDiv.textContent)

Node.textContent

HTMLElement.innerText

  • 只展示给人看的内容元素。
  • 受 CSS 样式的影响,不会返回隐藏元素的文本,它会触发回流( reflow )去确保是最新的计算样式。(回流在计算上可能会非常昂贵,因此应尽可能避免。)
  • textContent 不同的是, 在 Internet Explorer (小于和等于 11 的版本) 中对 innerText 进行修改, 不仅会移除当前元素的子节点,而且还会永久性地破坏所有后代文本节点。在之后不可能再次将节点再次插入到任何其他元素或同一元素中。

Element.innerHTML

  • 主要返回 HTML。通常,为了在元素中检索或写入文本,一般使用 innerHTML
  • 但是textContent 通常具有更好的性能,因为文本不会被解析为 HTML。
  • 使用 textContent 可以防止 XSS 攻击

三者区别

innerHTML获取的内容包含标签, innerText/textContent 获取的内容不包含标签 innerHTML / textContent获取的内容不会去除两端的空格, innerText 获取的内容会去除两端的空格

注意:

  • 无论通过 innerHTML/innerText/textContent 设置内容, 新的内容都会覆盖原有的内容
  • 通过 innerHTML 设置数据, 数据中包含标签, 会转换成标签之后再添加
  • 通过innerText/textContent设置数据, 数据中包含标签, 不会转换成标签, 会当做一个字符串直接置

兼容性元素操作

let oDiv = document.querySelector('div')

setText(oDiv, 'www.it666.com')
function setText(obj, text) {
if ('textContent' in obj) {
obj.textContent = text
} else {
obj.innerText = text
}
}

DOM 事件触发

接口参考:GlobalEventHandlers

GlobalEventHandlers 描述了一系列 web worker 的事件接口 HTMLElement, Document, Window, 或 WorkerGlobalScope。这里面的每一个接口都可以添加更多的事件句柄。

表格来源于:w3school

事件句柄(Event Handlers)此事件发生在何时...鼠标 / 键盘描述
onabort图像的加载被中断。altKey返回当事件被触发时,"ALT" 是否被按下。
onblur元素失去焦点。button返回当事件被触发时,哪个鼠标按钮被点击。
onchange域的内容被改变。ctrlKey返回当事件被触发时,"CTRL" 键是否被按下。
onclick当用户点击某个对象时调用的事件句柄。metaKey返回当事件被触发时,"meta" 键是否被按下。
ondblclick当用户双击某个对象时调用的事件句柄。relatedTarget返回与事件的目标节点相关的节点。
onerror在加载文档或图像时发生错误。shiftKey返回当事件被触发时,"SHIFT" 键是否被按下。
onfocus元素获得焦点。
onkeydown某个键盘按键被按下。
onkeypress某个键盘按键被按下并松开。
事件句柄(Event Handlers)此事件发生在何时...鼠标 / 键盘描述
offsetX返回当事件被触发时,相对于当前元素自身的位置,如:元素左上角 x0offsetY返回当事件被触发时,相对于当前元素自身的位置,如:元素左上角 y0
clientX返回当事件被触发时,鼠标指针距离可视区域的水平坐标。clientY返回当事件被触发时,鼠标指针距离可视区域的垂直坐标。
pageX返回当事件被触发时,距离整个网页的水平坐标。pageY返回当事件被触发时,距离整个网页的垂直坐标。
screenX返回当事件被触发时,鼠标指针距离显示器的水平坐标。screenY返回当事件被触发时,鼠标指针距离显示器的垂直坐标。

==获取移动设备页面宽高度==

document.documentElement.clientWidth
document.documentElement.clientHeight

事件监听规律

重点:onclick(点击)、onmouse&&&(鼠标移动)、input.oninput(表单监听)

  1. 寻找需要操作的元素,进行赋值
  2. 函数或方法:添加监听事件

transparent:透明颜色

表单事件监听

  1. .onfocus input 获取焦点
  2. .onblur input 失去焦点
  3. .onchange input 内容改变
    • 注意 onchange 事件只有表单失去焦点的时候, 才能拿到修改之后的数据
    • 在 IE9 以下,使用onpropertychange
<input type="text">

let oInput = document.querySelector("input");
oInput.oninput = function () { // .onfocus .onblur
console.log(this.value);
}

函数闭包与循环索引

  1. 闭包是一种特殊的函数。
  2. 当一个内部函数引用了外部函数的数据(变量/函数)时, 那么内部的函数就是闭包
  3. 只要满足"是函数嵌套"、"内部函数引用外部函数数据"
  4. 只要闭包还在使用外部函数的数据, 那么外部的数据就一直不会被释放,也就是说可以延长外部函数数据的生命周期

闭包注意点:当后续不需要使用闭包时候, 一定要手动将闭包设置为 null, 否则会出现内存泄漏

let list = [] //  var list = [];
for (let i = 0; i < 3; i++) {
// 0 1 2 3 // for(var i = 0; i < 3; i++){
let fn = function test() {
// var fn = function test() {
console.log(i) // 3 // console.log(i);
} // }
list.push(fn) // list.push(fn);
} // }
list[0]() // 0 // list[0](); // 3
list[1]() // 1 // list[1](); // 3
list[2]() // 2 // list[2](); // 3

注意:通过 var 定义为全局变量,let 定义的为局部变量

  • 默认情况下是顺序结构, 代码会从上之下的执行, 前面的没执行完后面的不能执行
  • 默认情况下通过 var 定义的变量, 只要不是定义在函数中都是全局变量

通过()包裹的函数会立即执行

for (var i = 0; i < 3; i++) {
;(function test(index) {
console.log(index)
})(i)
}

函数排它思想

清除其它非选中元素的样式,只设置当前选中元素样式

//              let 方法 ↓                                       var 方法 ↓
for (let i = 0; i < oItems.length; i++) {
// for(var i = 0; i < oItems.length; i++) {
let item = oItems[i] // var item = oItems[i];
item.onclick = function () {
// (function (index) {
let preItem = oItems[previousIndex] // item.onclick = function () {
preItem.className = '' // var preItem = oItems[previousIndex];
this.className = 'current' // preItem.className = "";
previousIndex = i // this.className = "current";
} // previousIndex = index;
} // }
// })(i);
// }
class Tab {
constructor() {
this.oTabItems = document.querySelectorAll('.tab-item')
this.oTabContents = document.querySelectorAll('.tab-content')
this.oTabContents[0].style.display = 'block'
this.previousIndex = 0
}
addClickEvent() {
for (let i = 0; i < this.oTabItems.length; i++) {
let tabItem = this.oTabItems[i]
tabItem.onclick = () => {
this._change(i)
}
}
}
addMoveEvent() {
for (let i = 0; i < this.oTabItems.length; i++) {
let tabItem = this.oTabItems[i]
tabItem.onmousemove = () => {
this._change(i)
}
}
}
/*
如果在方法名称前面加上_ 标识为一个私有的方法,不要调用。实际上可以调用,只是方便工作而已
封装在一个类里面,通过标识运用不同的方法时,该方法需要运用到共有的方法
*/
_change(i) {
// 1.排它
let preTabItem = this.oTabItems[this.previousIndex]
preTabItem.className = preTabItem.className.replace('selected', '')
let preTabContent = this.oTabContents[this.previousIndex]
preTabContent.style.display = 'none'
// 2.设置当前的样式
let curTabItem = this.oTabItems[i]
curTabItem.className = curTabItem.className + ' selected'
let curTabContent = this.oTabContents[i]
curTabContent.style.display = 'block'
// 3.保存当前的索引
this.previousIndex = i
}
}
let tab = new Tab()
tab.addClickEvent()
// tab.addMoveEvent();

时间格式化

默认打印:Fri May 29 2020 14:00:30 GMT+0800 (中国标准时间)

将时间自定义,更符合中国用户的使用习惯

let date = new Date()
let res = formartDate(date)
console.log(res)
// console.log(date);
// 2019-4-19 18:17:06
function formartDate(date) {
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
}

添加事件三种方法

通过 onxxx 的方式来添加

注意点: 由于是给属性赋值, 所以后赋值的会覆盖先赋值

oBtn.onclick = function () {
alert('666')
}
oBtn.onclick = function () {
alert('777')
}

通过 addEventListener 方法添加

注意点:

  1. 事件名称不需要添加 on
  2. 后添加的不会覆盖先添加的
  3. 只支持最新的浏览器 IE9
oBtn.addEventListener('click', function () {
alert('666')
})
oBtn.addEventListener('click', function () {
alert('777')
})

旧版本兼容做法

function addEvent(ele, name, fn) {
if (ele.attachEvent) {
ele.attachEvent('on' + name, fn) // 只支持低版本的浏览器
} else {
ele.addEventListener(name, fn)
}
}

事件执行三个阶段

捕捉与冒泡及回调函数

共有两种模型:Netscape 和 Microsoft 是不同的实现方式。

事件捕获

当你使用事件捕获时,父级元素先触发,子级元素后触发,即 div 先触发,p 后触发。

事件冒泡

当你使用事件冒泡时,子级元素先触发,父级元素后触发,即 p 先触发,div 后触发。

  • Netscape 中,div 先触发,叫做事件捕获。
  • Microsoft 中,p 先触发,叫做事件冒泡。

两种事件处理顺序刚好相反。IE 只支持事件冒泡

设置事件捕获或冒泡

oFDiv.addEventListener(
'click',
function () {
console.log('father')
},
false
)

通过addEventListener方法, 这个方法接收三个参数

  • 第一个参数: 事件的名称
  • 第二个参数: 回调函数
  • 第三个参数: false 冒泡 / true 捕获

阻止事件冒泡

var oFDiv = document.getElementById('father')
var oSDiv = document.getElementById('son')
oFDiv.onclick = function () {
console.log('father')
}
oSDiv.onclick = function (event) {
event = event || window.event
// 注意点: stopPropagation方法只支持高级浏览器
// event.stopPropagation();
// event.cancelBubble = true; // 低级浏览器
if (event.cancelBubble) {
event.cancelBubble = true
} else {
event.stopPropagation()
}
console.log('son')
}

移入移出事件

触发事件描述
onmouseover移入到子元素,父元素的移入事件会被触发
onmouseenter移入到子元素,父元素的移入事件不会被触发
onmouseout移出到子元素,父元素的移入事件会被触发
onmouseleave移出到子元素,父元素的移入事件不会被触发

正则表达式

RegExp 对象

  • 正则表达式是描述字符模式的对象。
  • 正则表达式用于对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。

修饰符

修饰符用于执行区分大小写和全局匹配:

修饰符描述
i执行对大小写不敏感的匹配。
g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m执行多行匹配。

方括号

方括号用于查找某个范围内的字符:

表达式描述
[abc\\]查找方括号之间的任何字符。
[^abc\\]查找任何不在方括号之间的字符。
[0-9]查找任何从 0 至 9 的数字。
[a-z]查找任何从小写 a 到小写 z 的字符。
[A-Z]查找任何从大写 A 到大写 Z 的字符。
[A-z]查找任何从大写 A 到小写 z 的字符。
[adgk]查找给定集合内的任何字符。
[^adgk]查找给定集合外的任何字符。
(redbluegreen)查找任何指定的选项。

元字符

元字符(Metacharacter)是拥有特殊含义的字符:

元字符描述
.查找单个字符,除了换行和行结束符。
\w查找单词字符。
\W查找非单词字符。
\d查找数字。
\D查找非数字字符。
\s查找空白字符。
\S查找非空白字符。
\b匹配单词边界。
\B匹配非单词边界。
\0查找 NULL 字符。
\n查找换行符。
\f查找换页符。
\r查找回车符。
\t查找制表符。
\v查找垂直制表符。
\xxx查找以八进制数 xxx 规定的字符。
\xdd查找以十六进制数 dd 规定的字符。
\uxxxx查找以十六进制数 xxxx 规定的 Unicode 字符。

量词

量词描述
n+匹配任何包含至少一个 n 的字符串。例如,/a+/ 匹配 "candy" 中的 "a","caaaaaaandy" 中所有的 "a"。
n*匹配任何包含零个或多个 n 的字符串。例如,/bo*/ 匹配 "A ghost booooed" 中的 "boooo","A bird warbled" 中的 "b",但是不匹配 "A goat grunted"。
n?匹配任何包含零个或一个 n 的字符串。例如,/e?le?/ 匹配 "angel" 中的 "el","angle" 中的 "le"。
n{X}匹配包含 X 个 n 的序列的字符串。例如,/a2/ 不匹配 "candy," 中的 "a",但是匹配 "caandy," 中的两个 "a",且匹配 "caaandy." 中的前两个 "a"。
n{X,}X 是一个正整数。前面的模式 n 连续出现至少 X 次时匹配。例如,/a{2,}/ 不匹配 "candy" 中的 "a",但是匹配 "caandy" 和 "caaaaaaandy." 中所有的 "a"。
n{X,Y}X 和 Y 为正整数。前面的模式 n 连续出现至少 X 次,至多 Y 次时匹配。例如,/a3/ 不匹配 "cndy",匹配 "candy," 中的 "a","caandy," 中的两个 "a",匹配 "caaaaaaandy" 中的前面三个 "a"。注意,当匹配 "caaaaaaandy" 时,即使原始字符串拥有更多的 "a",匹配项也是 "aaa"。
n$匹配任何结尾为 n 的字符串。
^n匹配任何开头为 n 的字符串。
?=n匹配任何其后紧接指定字符串 n 的字符串。
?!n匹配任何其后没有紧接指定字符串 n 的字符串。

RegExp 对象方法

方法描述
compile在 1.5 版本中已废弃。 编译正则表达式。
exec检索字符串中指定的值。返回找到的值,并确定其位置。
test检索字符串中指定的值。返回 true 或 false。
toString返回正则表达式的字符串。

正则表达式 String 对象方法

方法描述FFIE
search检索与正则表达式相匹配的值。14
match找到一个或多个正则表达式的匹配。14
replace替换与正则表达式匹配的子串。14
split把字符串分割为字符串数组。14

RegExp 对象属性

属性描述
constructor返回一个函数,该函数是一个创建 RegExp 对象的原型。
global判断是否设置了 "g" 修饰符
ignoreCase判断是否设置了 "i" 修饰符
lastIndex用于规定下次匹配的起始位置
multiline判断是否设置了 "m" 修饰符
source返回正则表达式的匹配模式

应用案例

常用正则表达式合集案例
验证数字^[0-9]*$
验证 n 位的数字^\d{n}$
验证至少 n 位数字^\d{n,}$
验证 m-n 位的数字^\d{m,n}$
验证零和非零开头的数字`^(0[1-9][0-9]*)$`
验证有两位小数的正实数^[0-9]+(.[0-9]{2})?$
验证有 1-3 位小数的正实数^[0-9]+(.[0-9]{1,3})?$
验证非零的正整数^\+?[1-9][0-9]*$
验证非零的负整数^\-[1-9][0-9]*$
验证非负整数(正整数 + 0)^\d+$
验证非正整数(负整数 + 0)`^((-\d+)(0+))$`
验证长度为 3 的字符:^.{3}$
验证由 26 个英文字母组成的字符串^[A-Za-z]+$
验证由 26 个大写英文字母组成的字符串^[A-Z]+$
验证由 26 个小写英文字母组成的字符串^[a-z]+$
验证由数字和 26 个英文字母组成的字符串^[A-Za-z0-9]+$
验证由数字、26 个英文字母或者下划线组成的字符串^\w+$
验证用户密码^[a-zA-Z]\w{5,17}$ 正确格式为:以字母开头,长度在 6-18 之间,只能包含字符、数字和下划线。
验证是否含有^%&',;=?$\" 等字符:[^%&',;=?$\x22]+
验证汉字^[\u4e00-\u9fa5],{0,}$
验证 Email 地址^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
验证 InternetURLhttp://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$
验证电话号码`^(\d3,4\d4-)?\d8$--正确格式为:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。验证身份证号(15 位或 18 位数字)`^\d15\d18$`
验证一年的 12 个月`^(0?[1-9]1[0-2])$`正确格式为:“01”-“09”和“1”“12”验证一个月的 31 天`^((0?[1-9])((12)[0-9])3031)$`正确格式为:01、09 和 1、31。
整数^-?\d+$非负浮点数(正浮点数 + 0)^\d+(.\d+)?$
正浮点数`^(([0-9]+.[0-9][1-9][0-9])([0-9][1-9][0-9].[0-9]+)([0-9][1-9][0-9]))$`非正浮点数(负浮点数 + 0)`^((-\d+(.\d+)?)(0+(.0+)?))$`
负浮点数`^(-(([0-9]+.[0-9][1-9][0-9])([0-9][1-9][0-9].[0-9]+)([0-9][1-9][0-9])))$`浮点数^(-?\d+)(.\d+)?$