JavaScript事件与字符串常用函数
一、JavaScript事件基础
1.事件的三种添加方法
1.1 添加到元素的事件属性上。
<button onclick="console.log(this.innerHTML)">Button1</button>
1.2 通过脚本添加到事件属性上。
<button>Button2</button>
<script>
const btn2 = document.querySelector('body button:nth-of-type(2)');
// 添加事件
btn2.onclick = () => {
console.log(this); // <button></button>
console.log(this.innerHTML); // Button2
}
</script>
这里有一点需要注意的是,onclick不能重复定义一个事件,因为后面的事件会覆盖前面的事件,类似于CSS样式覆盖这个道理。
如果想要移除一个事件,可以使用以下方法:
btn2.onclick = null;
1.3 通过事件监听器添加事件。
- 语法:
addEventListener(事件类型, 事件回调方法, 触发阶段)
<button>Button3</button>
<script>
const btn3 = document.querySelector('button');
btn3.addEventerListener('click', function () {
console.log(this.innerHTML, '第一次'); // Button3 第一次
});
btn3.addEventListener('click', function () {
console.log(this.innerHTML, "第2次"); // Button3 第二次
});
</script>
1.3.1事件移除
通过回调函数添加的事件是无法移除的,但是可以通过事件方法函数来移除。
let handle = () => console.log(btn3.innerHTML, "第3次");
// 添加点击事件
btn3.addEventListener('click', handle); // Button3 第三次
// 移除点击事件
btn3.removeEventListener('click', handle);
1.3.2事件派发
创建一个按钮,并拿到这个元素:
<button>Button4</button>
<script>
const btn4 = document.querySelector('button');
</script>
通过事件派发,结合定时器,我们可以做一个自动点击广告的小案例。
// 创建一个自定义事件
let ev = new Event('click');
let i = 0;
btn4.addEventerListener('click', function () {
console.log(`点击了广告,共赚:${i}元`);
i += 0.5;
});
setInterval(btn4.dispatchEvent(ev), 1000);
2.事件传递
- 捕获:从最外层元素逐级向内知道事件的绑定者;
- 目标:到达目标事件;
- 冒泡:从目标再由内向外逐级向上知道最外层元素。
如果需要理解捕获、目标,冒泡
需要先理解什么是事件的对象、事件的绑定者以及事件的触发者,现有如下案例:
以下是定义个一个ul列表的DOM结构:
<ul>
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
</ul>
给每一个li元素绑定一个点击事件:
const lis = document.querySelectorAll('.item');
lis.forEach(li => (li.onclick = ev => {
// 事件对象保存着当前事件的所有信息
console.log(ev);
// 事件类型
console.log(ev.type); // click
// 事件绑定者
console.log(ev.currentTarget);
// 事件触发者
console.log(ev.target);
// 在这种情况下,事件绑定者和触发者都是同一个
console.log(ev.currentTarget === ev.target);
// 事件的传递路径,假定:点击了item5,此时事件传递的路径就是从内向外逐级传递。
console.log(ev.path); // [li.item, ul, body, html, document, Window]
}));
注意:on + event事件是不支持捕获的,只支持冒泡:
// 不支持捕获,仅支持冒泡
li.onclick = function () {};
addEventListener的第三个参数为true
时,表示事件在捕获阶段发生,false
在冒泡阶段发生,也是默认事件。
- 捕获
// window
window.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, true);
// document
document.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, true);
// html
document.documentElement.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, true);
// body
document.body.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, true);
// ul
document.querySelector("ul").addEventListener('click', ev => {
console.log(ev.currentTarget);
}, true);
- 效果图:
- 冒泡
// ul
document.querySelector("ul").addEventListener('click', ev => {
console.log(ev.currentTarget);
}, false);
// body
document.body.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, false);
// html
document.documentElement.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, false);
// document
document.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, false);
// window
window.addEventListener('click', ev => {
console.log(ev.currentTarget);
}, false);
- 效果图:
从上述捕获和冒泡两个阶段可以看出来:JavaScript事件触发的三个阶段分别为:捕获阶段、目标阶段、冒泡阶段而这个阶段就是事件的传递机制。
3.事件代理
现在如果我不想给每个li元素都添加一个点击事件,只给它的父节点ul添加一个点击事件,那么我应该怎么操作呢?
此时,我们可以统一个li元素的父节点ul添加一个点击事件,然后通过ev.target获取到用户当前操作的元素即可,事件触发者一般是事件绑定者的子元素或后代元素。
document.querySelector('ul').addEventListener('click', ev => {
// 事件绑定者
console.log(ev.currentTarget);
// 事件触发者,一般情况下是事件绑定者的子集
console.log(ev.target);
});
- 效果图:
二、利用所学的知识做一个留言板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<style>
{
margin: 0;
padding: 0;
font-size: 10px;
box-sizing: border-box;
font-family: Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif;
}
ul, li {
list-style: none;
}
.box {
width: 50rem;
height: 10rem;
margin: 1rem auto;
}
h2 {
font-size: 3rem;
display: flex;
justify-content: center;
margin-bottom: 1rem;
}
#message {
display: flex;
flex-flow: column nowrap;
width: 100%;
}
#message textarea {
width: 100%;
min-height: 10rem;
padding: .6rem 1rem;
border: 1px solid #c9c9c9;
border-radius: 2px;
outline: none;
font-size: 1.4rem;
font-family: inherit;
}
#message .button {
width: 100%;
height: 5rem;
margin-top: 1rem;
}
#message .button .btn {
padding: 0 2rem;
height: 3.8rem;
border-radius: 3px;
border-width: 0;
font-size: 1.2rem;
outline: none;
cursor: pointer;
}
#message .button .btn:hover {
transition: all .3s;
opacity: .8;
}
#message .button .btn.btn-submit {
background-color: #3e7771;
color: #ffffff;
}
#message .button .btn.btn-rest {
margin-left: .5rem;
}
#message .content-wrap em.tips {
font-style: normal;
color: red;
margin-top: 1rem;
}
#list {
width: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto;
margin-top: 1rem;
}
#list li {
display: grid;
grid-template-columns: 4rem 1fr;
grid-template-rows: auto auto;
gap: .5rem;
margin-top: 1rem;
}
#list li.item .avatar {
width: 4rem;
height: 4rem;
}
#list li.item .avatar img {
width: 100%;
height: 100%;
border-radius: 50%;
}
#list li.item .comment {
display: grid;
grid-template-columns: 1fr;
row-gap: .5rem;
}
#list li.item .comment .title {
display: flex;
flex: rows nowrap;
align-items: center;
}
#list li.item .comment .title .nick > * {
font-size: 1.6rem;
color: #000000;
}
#list li.item .comment .title .time {
color: #8c92a4;
margin-left: .5rem;
font-size: 1.2rem;
color: #8c92a4;
font-size: 1.4rem;
}
#list li.item .comment .context{
color: #8c92a4;
font-size: 1.2rem;
color: #40485B;
font-size: 1.4rem;
margin: .5rem 0;
}
#list li.item .del {
margin: .5rem 0;
display: grid;
cursor: pointer;
border: none;
place-self: center end;
grid-area: 2 / 1 / 2 / 3;
padding: .5rem;
outline: none;
}
hr {
border-color: rgba(222, 222, 222, .5);
}
</style>
</head>
<body>
<div class="box">
<h2>留言板</h2>
<div id="message">
<div class="content-wrap">
<textarea class="content" name="message" value="ddd" placeholder="请输入内容"></textarea>
<em class="tips" style="display: none;">* 留言内容不能为空!</em>
</div>
<div class="button">
<button class="btn btn-submit">立即提交</button>
<button type="reset" class="btn btn-rest">重置</input>
</div>
</div>
<hr>
<ul id="list">
</ul>
</div>
<script>
// 获取元素
const msg = document.querySelector('.content');
// 提交按钮
const btn = document.querySelector('.btn-submit');
console.log(btn);
// 重置按钮
const resetBtn = document.querySelector('.btn-rest');
console.log(resetBtn);
// 评论列表
const ul = document.querySelector('#list');
btn.addEventListener('click', ev => {
// 获取文本框的内容:msg.value
let str = ` <li class="item" >
<div class="avatar">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAHCklEQVRoQ+2Zd1BUVxTGv106K82VJk1BEHAElGBBYxR1Eomxm6gJjo4tGnUsmZiIRkfDRMeWaOwmxthLNBg10dhFUBEZEASRLkVAWFjaUpbNnOvsm0VBGN9j3MG9f8Huffed3/nuPeWuqPvpaSq8Q0OkA27nausUbucCQ6ewTuF25gHdlm5ngr6Co1NYp3A784BuS7czQbUnaHXpYIcprkGwMJDgiTwX+55cYMYNtvNFTmURUsvz2sT3b21L97P2wnr/WbA1scKj0iyMu7YaS3tMRIjbMKTIc7A85tc2geYNPNZ5IMj41o4ChQybE0+xZ9TApObIy6FY5z8Tnzj1h1gkwkNZRptA8wb+ofd0THAZ1FpephrBNQVMi2hCPy7LwdfRuwRVmjfwSt8vMMZ5AAdsINaHoVgfKqigUNaiQdX4Bim9PB8Tr69h888NC0M3s86cE+gzib4xVvtNRbBjX6hUKpzIvIE1cQdb7dCWJvIGfvkFZ4euhYe5I55Vy5g694tTmrVBDVxQLcOymL24U5TE5hL0xoA5KFKU4mTmTbia2UMEEf7Kvt0ST4vfCwo8xM4PtMWlRuZcIHqdBaeHrIa3pQvkdZW4XZgIG2MrWBhKYGNsAUOxAYz0DBgojZed0iJZMxMEBZ7pHoz5XqOZoaezIhD64LdGrx3e2R/LfabAyrBDI5jWGK+VwDv6LUSQfS/UNdQjqugRZDUVjVgoQo91HgBrY8tXGJWqBtQo61CtrMFzRRnyq0sgqy3H47KnyKsqwe3CBFTWK1rjm9fOEUxhKiT2BC6Gs8Sm2RfSea5V1jN1qbiwNrZAoE0PVNXXICz+MP7MusUbqKUFBANWb2djPUMWnUkxGnQGCVBPJGaqT4/YwNm0yHscZriPYP/vTbmArUlnWrKX9/eCAe/qv4iVhaTWxsQTOJJ+lRk30qkfVvlOhZmBCa7mx2Lena2c0V95jsac7iOhL9LD0YyrWBt3iK3RpYMtuls4wVliC6mRGaRGFjDVN8KZ7AiseLCfF7QgwINsffCj/wwuOofcWsedt4VeYzHLIxhikRh/pF5i29bT0hk+Vq5wkdgi0MYblLvp3OuL9bio3BTVhZx7WBK98+0DU6HwaZfBzJB/cu9hafQuzqjNAXMR7NgHFfXVuFuUjCB7v9dCqR9UFy5ltVUoqZEjs6KApTp1k/Gm1LwV9u3ohi0Bc9HZVMpsoLNLEfX72N9RXleN4x+sQDdzB+RWPcfF3PusOSBFadBZp7/pfBcqSnGzIB4JskxkVjzjipCh9r3Y3Cv5sW/K2Og53sBU+45yCoRIBCgbGti2JHXS5Hk4lnkdC73GwNxAguvP4nAo/TKL4s8Vci7NHBj4Dfpae7GqalnMPkQWJjYKaiFuw5njyIHkEL6DF7Dm2c2qKMD25HDM9xrDoCinxsvS4S/1gFKlbDYKk8OoFqf8uzHhJA6nX4GdiRVCfT5nOZ3Up/y7J+U8dj8+x5eX308tlHt/6jOPRdUdyWeZUdQMhPnPgKK+BvamUgafV1WMxdE7EVeS9orBL0fqpNJsFrmdJNZsblltJX5JDsfBtP94w9ICvBSmBca7vI+ATt3xbcy+RgYt6zkJIa7DoCcWg6KrZiDTnKhZf1NgM9EzYqqyY1Gej3UPjyKiIEEQWEGAm7KEtjo1ETbGlkwhau/O59xt0ujeUndseG82HEw7cd9TirqUF4MNCcdZ17XKbyp8rVxxIO0SwrMjecHzVvjlt1Nrt63vAvS3eXEL8m9uNBbfezV3UiMxuWsQ/KXurBJTj6eVReysnsq6yX2mDmzZlYWYHbmFRfE3HYIDL/Yej2ndPnxRL1cVYWn0bu7sUjCiqDvCoQ/sTTs2mY8zKp5hbtTPHFRPq64sTtAOiC1JxeQbYW/Kyp4TFHhS1yFY0mMCzA1MWY6lQEbl5CjnQNA2dzOz53Kw2mrqhSnHelm4wNPCCfUNShxMv4z1D4+xKXRnFuo7BaZ6xlz5yYdYMGAqEFb6hrCUQsXH30+jWCDTTF1qQykgFSvkCH8ayaIvndPZHh9jnucoUPMhr6tiF33HMq5hU8CXrFKj1BQWd4TV03yGIMAEtabXNAZLMFGFSVhwdxtXT6sbC1I9qSwbZ7Ii2F2V5tA8+9RhUV7OrSqGg6mURe5UeS4+u/ED756YN7CmsgRADTulIM2LdJrjKLHGxdxopmZzQ9NxmnNom+9PvYhNiSf5iCvMGSYYyrlUYFC1FRZ/hFcJSNDf+UxmxQwpTTuGys2Fd7fzVlewoEXV1XT3j1hzIES9S4ZRX0wXenSXpb7N5C2v0FFaCIPaeg3eZ7itDRR6fR2w0B7VtvV0CmubIkLbo1NYaI9q23o6hbVNEaHt0SkstEe1bT2dwtqmiND26BQW2qPatt47p/D/fz1ommzIsNIAAAAASUVORK5CYII=" />
</div>
<div class="comment">
<div class="title">
<span class="nick"><b>残破的蛋蛋</b></span>
<div class="time">${formatDate(Date.now())}</div>
</div>
<div class="context">${msg.value}</div>
<hr>
</div>
<button class="del" onclick="del(this)">删除</button>
</li>
`;
if (msg.value.length === 0) {
console.log(1);
document.getElementsByClassName('tips')[0].style.display = 'block';
return false;
}
ul.insertAdjacentHTML('afterbegin', str);
msg.value = '';
});
// 删除评论
function del(element) {
confirm('确定要删除这条评论吗?') ? element.parentNode.outerHTML = null : false;
}
// 重置内容
resetBtn.onclick = function () {
msg.value = '';
}
// 获取时间
function formatDate(time) {
let date = new Date(time);
console.log(date);
let y = date.getFullYear();
console.log(y);
let m = date.getMonth();
m = date.getMonth()+1 < 10 ? `0${date.getMonth()+1}` : date.getMonth()+1
console.log(m);
let d = date.getDate();
console.log(d);
let h = date.getHours();
console.log(h);
let i = date.getMinutes();
console.log(i);
let s = date.getSeconds();
console.log(s);
return `${y}-${m}-${d} ${h}-${i}-${s}`;
}
</script>
</body>
</html>
- 效果图:
三、字符串常用的10个方法
// 1. concat() 拼接字符串
let str = "html".concat(" css ", "php !", 888);
console.log(str); // html css php !888
// 2. slice(start, end) 取子串
str = "html css php !";
let res = str.slice(0, 5);
console.log(res); // html
// 省略第二个参数,表示从0一直取到末尾
res = str.slice(0);
console.log(res); // html css php !
res = str.slice(5);
console.log(res); // html css php !
res = str.slice(-5);
console.log(res); // html css php !
res = str.slice(-5, -2);
console.log(res); // html css php !
// 3.substr(start, length)
res = str.substr(0, 6);
console.log(res);
res = str.substr(-5, 3);
console.log(res);
// 4.trim():删除两端空格
let pwd = " root888 ";
console.log(pwd.length); // 13
// 5.将字符串打成数组
res = str.split("");
console.log(res);
// 比如说从邮箱中解析出用户和邮箱地址
res = "admin@admin.cn".split("@");
console.log(res[0]); // admin
console.log(res[1]); // admin.cn
// 6.查找字符串中的字符串
str = "The full name of China is the People's Republic of China.";
// 使用indexof()方法返回字符串指定的文本首次出现的位置
console.log(str.indexOf('China')); // 17
// lastIndexOf()方法返回指定的字符串在文本中最后一次出现的位置
console.log(str.lastIndexOf('the')); // 26
// indexof()和lastIndexOf()如果在文中本找到指定的字符串,则返回-1
console.log(str.indexOf('hello')); // -1
console.log(str.lastIndexOf('hello')); // -1
// 7.search()方法返回指定文本在文中第一次出现的位置
str = "The full name of China is the People's Republic of China.";
console.log(str.search('China')); // 17
// 8.替换字符串
str = "Please visit microsoft and Microsoft!";
console.log(str.replace('Microsoft', '微软')); // Please visit microsoft and 微软!
// 默认的replace()只替换首次匹配的字符串,并且对大小写敏感
// 9.大小写转换
str = 'Hello World!';
// 字符串转大写
console.log(str.toUpperCase()); // HELLO WORLD!
console.log(str.toLocaleUpperCase()); // HELLO WORLD!
// 字符串转小写
console.log(str.toLowerCase()); // hello world!
console.log(str.toLocaleLowerCase()); // hello world!
// 10.charAt()方法返回字符串中指定下标的字符串
str = 'Hello World';
console.log(str[0]); // H