DOM事件分为3个级别:DOM 0级事件处理、DOM 2级事件处理和DOM 3级事件处理
给元素的事件行为绑定方法,在当前元素事件行为的冒泡阶段执行
element.on+事件类型 = js code
<div id="demo">点击</div>
var div = document.getELementById("demo")
div.onclick = function() {
console.log("元素被点击了")
}
从某种角度上来说,给元素的事件行为其实是给这个DOM对象的属性进行赋值,所以DOM 0级事件是不能绑定多个方法的,因为后面再去绑定会覆盖前面已经绑定过的,同理,如果要是需要取消这个事件,只能通过给这个属性赋空值的手段来达到目的
DOM 2级事件在DOM 0级事件基础上进行了优化,允许绑定多个处理函数,也可任意移除某个处理函数
<button id="btn">点击</button>
var btn = document.getELementById("btn")
btn.addEventListener("click", function() {
console.log("点击了")
}, false)
addEventListener方法参数的具体介绍:MDN
可以通过removeEventListener
解绑事件
注:对于IE8以下的版本不支持addEventListener
和removeEventListener
,需要用attachEvent
和detachEvent
来实现
// 只支持冒泡型事件,所以只需传两个参数
btn.attachEvent('onclick', fn); // 绑定事件
btn.detachEvent('onclick', fn); // 解绑事件
DOM 3级事件在DOM 2级事件的基础上新增了更多的事件类型,比如
DOM 3级事件还支持自定义事件
事件代理就是利用事件冒泡,只制定一个事件处理程序,就可以管理某一类型的所有事件
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
let Lis = document.getElementsByTagName("li")
for(let i = 0; i < Lis.length; i++) {
Lis[i].onclick = function() {
alert(Lis[i].innerText)
}
}
这种方式对内存消耗是很大的,如果我们只给ul绑定一个函数,当点击li时,会根据冒泡机制向上传递,触发ul的事件,我们通过获取事件源就知道是哪个元素被点击了,这样对内存的消耗就变低了
<ul id="el">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
var ul = document.getElementById("el")
ul.onclick = function (e) {
if (e.target.tagName === 'LI') {
console.log(e.target.innerText)
}
}
调用这个方法,默认事件行为将不再触发
比如阻止点击a标签的页面跳转行为
<a id="a" href="http://www.baidu.com">链接</a>
a.onclick = function (e) {
console.log("a标签被点击了")
e.preventDefault()
}
可以阻止事件冒泡到父元素
<div id="parent">
<div id="child"></div>
</div>
<script>
parent.addEventListener('click', function () {
console.log("parent")
}, false)
child.addEventListener("click", function (e) {
console.log("child")
e.stopPropagation()
}, false)
</script>
既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发
<div id="parent">
<div id="child"></div>
</div>
<script>
parent.addEventListener('click', function () {
console.log("parent")
}, false)
child.addEventListener("click", function (e) {
console.log("child")
e.stopImmediatePropagation()
}, false)
child.addEventListener("click", function() {
console.log("第二个click事件被触发")
})
</script>
event.targe
t指向引起触发事件的元素,而event.currentTarget
则是事件绑定的元素。
定时器(setInterval()):按照指定的周期(以毫秒计)来调用函数或计算表达式。方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭
计时器(setTimeout()) :在指定的毫秒数后调用函数或计算表达式。
可以通过clearInterval
和clearTimeout
来清除
正则表达式是可以用于匹配字符串和字符组合的文本模式
var reg = /abc/
var str = "aerabcdr ab c"
console.log(reg.test(str))
var reg = new RegExp("abc")
var str = "aerabcdr ab c"
console.log(reg.test(str))
标志 | 描述 |
---|---|
g | 全局搜索 |
i | 不区分大小写搜索 |
m | 多行搜索 |
var reg = /a/g
var reg = /a/i
var reg = /a/m
1.test()
规则:正则表达式搜索字符串指定的值,从而去匹配字符串。如果匹配成功就返回 true
,如果匹配失败就返回 false
。
用法:正则.test(字符串)
2. exec()
规则:该函数通过对指定你的字符串进行一次匹配检测,获取字符串中的第一个与正则表达式的内容,并且将匹配的内容和子匹配的结果存放在返回数组中
用法:正则.exec(字符串)
var reg=/hello/;
console.log(reg.exec('hellojs'));
console.log(reg.exec('javascript'));
3. match()
规则:正则去匹配字符串,如果匹配成功,就返回匹配成功的数组,如果匹配不成,就返回 null
用法:字符串.match(正则)
var str = "12379asdf34sdf2df"
var reg = /f/g
console.log(str.match(reg))
4. replace()
规则:正则去匹配字符串,匹配成功的字符串去替换成新的字符串。函数的第一个参数,是匹配成功的字符;第二个参数:可以是字符串,也可以是一个回调函数。
用法:字符串.replace(正则,新的字符串)
var str = "13adf45"
var reg = /adf/g
str = str.replace(reg, '*')
console.log(str)
5. search()
规则:正则去匹配字符串,如果匹配成功,就返回匹配成功的位置,如果匹配失败就返回 -1
用法:字符串.search(正则)
var str = "abaddade"
var reg1 = /b/
var reg2 = /e/
console.log(str.search(reg1)
console.log(str.search(reg2)
在前面我们已经知道了怎么创建正则表达式和基本的使用方法,但是这并没有体现正则表达式的魅力,我们可以使用String.indexOf()
来达到同样的目的。这里我就要说到精确匹配和模糊匹配,在刚刚的例子种就是一种精确匹配,那么什么是模糊匹配呢?先抛出一个问题,我们怎么去判断字符串中是否有数字,是否有字母等等。先来认识以下元字符
正则表达式由两种基本字符类型组成
类:指符合某些特征的对象集合
在正则表达式中,我们有时候需要匹配的不是某个特定字符而是符合一系列特征的字符串,我就可以用[]
来构建一个简单的类
// 这种匹配就不是 abc 这三个字符,而是abc中任意一个字符
var reg = /[abc]/g
var str = '23a34b31bcddf'
var result = str.replace(reg, '*')
console.log(result)
使用元字符^
创建反向类/负向类
反向类的意思是不属于类的内容
// 匹配不是a或b或c的内容
var reg = /[^abc]/g
var str = 'ad3fb123ab'
var result = str.replace(reg, '*')
console.log(result)
如果我要用字符类匹配所有字母,按照前面的方式那么我们需要26个字母,这样是很麻烦的。因此正则表达式提供了范围类,我们可以用[a-z]
来实现我们的需求,他表示从a到z的任意字符(闭区间)
var reg = /[0-9]/g
var str = "fasdf1234sadf3fsf"
var result = str.replace(reg, "*")
console.log(result)
字符 | 描述 |
---|---|
\d | 匹配一个数字字符 |
\D | 匹配一个非数字字符 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等 |
\S | 匹配任何非空白字符 |
\w | 匹配字母、数字、下划线 |
\W | 匹配非字母、数字、下划线 |
. | 匹配除换行符(\n、\r)之外的任何单个字符 |
字符 | 描述 |
---|---|
^ | 匹配输入字符串的开始位置,如果开启了多行匹配,也会匹配\n和\r后的位置 |
$ | 匹配输入字符串的结束位置,如果开启了多行匹配,也会匹配\n和\r前的位置 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置 |
\B | 匹配非单词边界 |
假如我们想匹配学号,如果用前面的知识我们需要写10个\d
,这显然也是很麻烦的。因此正则表达引入了量词的概念。
字符 | 描述 |
---|---|
? | 出现零次或一次(最多出现一次) |
+ | 出现一次或者多次(至少出现一次) |
* | 出现零次或者多次(任意次) |
{n} | 出现n次 |
{n,m} | 出现n到m次 |
{n,m} | 至少出现n次 |
var reg = /\d{4}[/-]\d{2}[/-]\d{2}/g;
var text = '2020-07-04,2020/07/04,2020~02/25,2020/7/4';
var result = text.replace(reg,'匹配正确日期格式');
console.log(result);
正则表达式默认是贪婪模式,即每次匹配都尽可能的匹配多的字符,直到匹配失败为止
贪婪模式:
var reg = /\d{3,6}/g;
var text = '12345678';
var result = text.replace(reg,'*');
console.log(result);
我们可以发现正则表达式匹配了前6个字符,而不是3个、4个、5个,这就是贪婪模式,它会尽可能多的匹配
但是我们想让他尽可能少的匹配呢?这就是非贪婪模式
我们只需要在量词后加上?
即可
var reg = /\d{3,6}?/g;
var text = '12345678';
var result = text.replace(reg,'*');
console.log(result);
假如我们需要匹配abc
连续出现三次的情况呢?我们就需要用到分组
var reg = /(abc){3}/g;
var text = 'abcabcabcadasd1';
var result = text.replace(reg,'*');
console.log(result);
假如我们要匹配abc
或def
时,我们可能会想到前面的字符类,但是字符类时针对单个字符的,这里是多个字符,我们可以使用|
// 匹配abc或def
var reg = /abc|def/g
var str = "abcdef"
var result = str.replace(reg, "*")
console.log(result)
// 匹配abcedf或abecdf
var reg = /ab(ce|ec)df/g
var str = "abcedfabecdf"
var result = str.replace(reg, "*")
console.log(result)
假如我们有这样一个需求,将2020-07-04
替换成04-07-2020
,你会怎么做呢?这时候我们就需要使用正则表达式的反向引用了,表达式在匹配时,表达式引擎会将小括号 “( )” 包含的表达式所匹配到的字符串记录(分组捕获)下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。我们可以通过$1
、$2
、$3
等等获取括号中的内容
var reg = /(\d{4})-(\d{2})-(\d{2})/g
var str = '2020-07-04'
var result = str.replace(reg, "$1-$2-$3")
在上面的反向引用中,假如我们不想保存某个捕获怎么办?我们只需要在分组内加上?:
即可
var reg = /(\d{4})-(?:\d{2})-(\d{2})/g
var str = '2020-07-04'
var result = str.replace(reg, "$1-$2")
前瞻是指在正则表达式匹配到规则的时候,向前检查是否符合断言,后顾和前瞻相反
符号 | 描述 |
---|---|
(?=pattern) | 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串 |
(?!pattern) | 正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串 |
(?<=pattern) | 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反 |
(? | 反向否定预查,与正向否定预查类似,只是方向相反 |