js急速入门之四(事件/事件派发/事件传递/事件代理/常用表单事件/字符串常用方法/留言板)
事件添加
- 添加到元素的事件属性上
- 通过脚本添加到事件属性上
- 通过事件监听器添加事件
<!-- 1. 添加到元素的事件属性上 -->
<!-- <button onclick="js代码">button1</button> -->
<button onclick="console.log(this.innerHTML);">在元素上添加事件</button>
<!-- 2. 通过脚本添加到事件属性上 -->
<button>通过脚本在事件属性上添加</button>
<script>
const btn2 = document.querySelector("body button:nth-of-type(2)");
//添加事件
btn2.onclick = function () {
console.log(this.innerHTML);
};
btn2.onclick = function () {
this.style.background='skyblue';
}
// 移除事件
// btn2.onclick = null;
</script>
<!-- 3. 通过事件监听器添加事件 -->
<button>通过事件监听器添加</button>
<script>
// addEventListener(事件类型,事件回调方法,触发阶段)
const btn3 = document.querySelector("button:nth-of-type(3)");
btn3.addEventListener("click",function (){
console.log(this.innerHTML);
});
//直接使用onclick 事件会覆盖,使用addEventListener就不会覆盖,可以添加多个相同行为事件
btn3.addEventListener("click",function (){
this.style.background='yellow';
});
//3.1 移除事件,通过回调添加的事件是无法移除的,可以移除独立函数
//事件方法函数
const handle =()=>console.log(btn3.innerHTML,"第3次");
btn3.addEventListener("click",handle);
btn3.removeEventListener("click",handle);
</script>
<button>点击广告</button>
<script>
//3.2 事件派发
const btn4 = document.querySelector("body button:nth-of-type(4)");
//自定义事件
const ev = new Event("click");
btn4.addEventListener("click",function(){
console.log("点击了我");
});
btn4.dispatchEvent(ev);
//使用间歇式定时器
setInterval("btn4.dispatchEvent(ev)",1000);
</script>
事件传递
- 捕获:从最外层元素逐级向内直到事件的绑定着
- 目标:到达事件目标
- 冒泡:从目标再由内向外逐级向上直到最外层元素
on+event:不支持捕获,只有冒泡addEventListener()
第三个参数是true表示事件在捕获阶段触发,false是冒泡(默认)
window.addEventListener(
"click",//事件类型:行为
(ev) => console.log(ev.currentTarget),//做什么
true//true表示事件在捕获阶段触发,false是冒泡(默认),不写就表示冒泡
);
事件冒泡与事件代理
事件代理:也叫“事件委托”
冒泡最主要的应用就是事件委托
合理的应用冒泡可以减少遍历,将事件委托给父元素
有些时候需要阻止冒泡:ev.stopPropagation();
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
</ul>
<script>
//事件代理:也叫“事件委托”
//冒泡最主要的应用就是事件委托
const lis = document.querySelectorAll("li");
//遍历每个li,并逐个添加点击事件
// lis.forEach(
// (li) =>
// (li.onclick = (ev) => {
// console.log(ev.currentTarget);
// })
// );
document.querySelector("ul").addEventListener("click", (ev) => {
//事件的绑定者
console.log(ev.currentTarget);
//事件的触发者,通常是 事件绑定者的子元素
console.log(ev.target.innerHTML);
});
</script>
常用表单事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>常用表单事件</title>
<style>
#login {
width: 20em;
border: 1px solid #888;
box-sizing: border-box;
padding: 1em 2em 1em;
margin: 2em auto;
background-color: lightcyan;
display: grid;
grid-template-columns: 3em 1fr;
gap: 1em 0;
}
#login .title {
grid-area: auto / span 2;
place-self: center;
}
#login button {
grid-area: auto / 2 / auto;
}
</style>
</head>
<body>
<!-- form.id === form.name -->
<!-- 推荐使用id,不用name 表示form 方便css -->
<form id="login" action="" method="POST">
<label class="title">用户登录</label>
<label for="email">邮箱:</label>
<input type="email" name="email" />
<label for="password">密码:</label>
<input type="password" name="password" />
<button name="submit">登录</button>
</form>
<script>
//获取表单
// const login = document.forms[0];
// const login = document.forms["login"];
// const login = document.forms.item(0);
// const login = document.forms.item("login");
// const login = document.querySelector("#login");
//推荐使用namedItem 适用于ID和name
const login = document.forms.namedItem("login");
//submit()提交事件
login.onsubmit = () => alert("submit...");
// 一般使用ajax提交;如果是自定义表单的提交行为,应该禁用掉默认的提交
login.onsubmit = (ev) => ev.preventDefault();
//或者使用form元素的 onsubmit="return false"属性来禁用默认提交行为
//推荐使用preventDefault方法,保证HTML代码整洁和代码分离机制
login.submit.onclick = (ev) => {
//禁用默认提交行为
ev.preventDefault();
//阻止事件冒泡
ev.stopPropagation();
// 事件绑定者
// console.log(ev.currentTarget);
// 表单中的每一个子元素都有一个form属性,指向它所属的表单
// console.log(ev.currentTarget.form);
// isEmpty(login);
isEmpty(ev.currentTarget.form);
};
document.body.addEventListener("click", (ev) =>
console.log(ev.currentTarget)
);
//与表单相关的几个事件
// focus:获取焦点事件
// blur: 失去焦点事件
// input: 只要值发生变化时连续触发,不等失去焦点
// change: 值发生改变且失去焦点是触发<input><select><textarea>
// select: 选中文本时触发,<input><textarea>
// invalid: 提交时表单元素值不满足验证条件时触发
// reset: 将表单值全部重置到默认值(并非清空)
// submit: 提交表单时触发,注意触发对象是<form>,提交的是表单不是按钮
// keydown: 按下键盘时:键盘键按下时
// keyup: 松开键盘时:键盘键弹起时
// keypress: 按过键盘时,按下有值键时(除Ctrl/Alt/Shift/Meta),先触发keydown
// 按下一直不放的触发顺序:keydown,keypress,重复这两个事件,直到keyup
// load,error:
// 非空验证
function isEmpty(form) {
// console.log(form.email.value.length);
console.log(form.password);
if (form.email.value.length === 0) {
alert("邮箱不能为空");
form.email.focus();
return false;
} else if (form.password.value.length === 0){
alert("密码不能为空");
form.password.focus();
return false;
} else {
alert("假设验证通过");
}
}
</script>
</body>
</html>
留言板
使用了字体图标,通过判断触发者的 className
来找到需要处理的上级父元素
<div class="messageBoard">
<h3>留言板</h3>
<label><input type="text" name="message" /></label>
<div class="messageBoardCenter">
<ol id="list"></ol>
</div>
</div>
<script>
//获取dom元素
const input = document.querySelector("input");
const list = document.querySelector("#list");
input.onkeydown = (ev) => {
if (ev.key === "Enter") {
if (ev.currentTarget.value.length === 0) {
alert("内容不能为空");
} else {
//将留言内容添加到列表中
//创建留言
let str = `<li>${ev.currentTarget.value}    <a href="#" class="iconfont delete" title="删除"></a></li>`;
list.insertAdjacentHTML("afterbegin", str);
input.value = null;
}
}
};
list.addEventListener("click", (ev) => {
if (ev.target.className === "iconfont delete") {
// console.log(ev.target.parentElement);
// list.removeChild(ev.target.parentElement);
confirm("是否删除?")
? list.removeChild(ev.target.parentElement)
: false;
}
});
</script>
效果图
字符串常用方法
// 1. concat() 字符串拼接。大量字符拼接操作时用处较大
let str = "html".concat(" css ", " php !");
console.log(str);
// 2. slice(start, end) 取子串
str = 'hello php.cn';
let res = str.slice(0, 5);
console.log(res);
//第二个参数为0表示结尾不限,后面全部取出
console.log(str.slice(0));
//支持负数:
console.log(str.slice(-2));
//正方向从0开始,反方向从-1 开始
console.log(str.slice(-5,-1));
// 3. substr(start,length); 省略第二参数表示剩下全部取得
res = str.substr(0, 5);
console.log(res);
res = str.substr(-6, 3);
console.log(res);
// 4. trim():删除首尾空格
let psw = ` 999 `;
psw = ' 9999 ';
psw = " 99999 "
console.log(psw.trim().length);
// 5. 将字符串打散变成数组
res = str.split("");
console.log(res);
// 比如说从邮箱中解析出用户和邮箱地址
res = 'admin@php.cn'.split("@");
console.log(res);
console.log(res[0]);
console.log(res[1]);
// String.prototype.includes()
// 判断一个字符串里是否包含其他字符串。
// String.prototype.endsWith()
// 判断一个字符串的是否以给定字符串结尾,结果返回布尔值。
// String.prototype.indexOf()
// 从字符串对象中返回首个被发现的给定值的索引值,如果没有找到则返回-1。
// String.prototype.lastIndexOf()
// 从字符串对象中返回最后一个被发现的给定值的索引值,如果没有找到则返回-1。
总结:字符串常用方法需要准确记忆。
特别是 substr(),split(),indexOf(),toLowerCase(),toUpperCase(),toString()