Correcting teacher:PHPz
Correction status:qualified
Teacher's comments:
<script>
// 正常都在主线程里执行 代码的"书写顺序"与"执行顺序" 一致
console.log(1);
console.log(2);
console.log(3);
console.log("--------");
// 现在给console.log(2) 加一个定时任务
console.log(1);
// 定时任务: setTimeout(函数,等待时间)
// 要等待三秒后才执行,这三秒理论上说,是什么也做不了,代码到这里就"阻塞"
setTimeout(() => console.log(2), 3000);
// 这个时候 js引擎将 setTimeout(() => console.log(2), 3000); 脱离"主线程",放到了"任务队列"的地方
console.log(3);
// 当主线程上已没有任务的时候,由"事件循环"将这个任务重新放回到主线程中执行
// 定时任务就是一个异步任务,只要是异步任务,就不在主线程执行,到任务队列中,等"事件循环"来找它
// 执行机制
// 1. 同步任务: 主线程
// 2. 异步任务: 任务队列, 由"事件循环"来调度
// 哪些是异步任务?
// 1. 定时任务, 2. 事件, 3, IO操作(input,output), 4. http请求
// 怎么实现异步? 回调函数
</script>
<form action="">
<input type="text" onkeydown="console.log(this.value);" />
<!-- 为什么慢半拍? -->
<!-- 因为dom渲染是同步任务,keydown事件是异步任务,所以总是获取的上一个数据 -->
<!-- 解决方案很粗暴,就是异步事件等等,等同步的dom渲染完了再执行 -->
<input type="text" onkeydown="setTimeout(()=>console.log(this.value),0);" />
<!-- <input type="text" oninput="console.log(this.value);" /> -->
</form>
<body style="display: grid; gap: 0.5em">
<!-- 1. 事件属性 -->
<button onclick="alert('hello')">事件属性</button>
<!-- 2. 元素对象 -->
<button>元素对象</button>
<script>
const btn2 = document.querySelector("button:nth-of-type(2)");
btn2.onclick = () => console.log(111);
btn2.onclick = _ => console.log(222);
btn2.onclick = $ => console.log(333); // 会进行覆盖 只会执行这一个
// 移除
// btn2.onclick = null;
</script>
<!-- 3. 事件监听器 -->
<button>事件监听器</button>
<script>
const btn3 = document.querySelector("button:nth-of-type(3)");
// btn3.addEventListener(事件类型, 事件回调,是否冒泡false/捕获true)
let i = 0;
btn3.addEventListener("click", () => { i += 0.5;console.log(i)});
btn3.addEventListener("click", () => { console.log(i)});
btn3.addEventListener("click", () => { console.log(i)}); // 会全部执行
// 删除 比较麻烦 只能用 removeEventListener 进行移除 并且添加的匿名函数无法移除
let show = () => console.log(444);
btn3.addEventListener("click", show);
// 删除
btn3.removeEventListener("click", show);
</script>
<!-- 4. 事件派发 -->
<button>事件派发</button>
<script>
const btn4 = document.querySelector("button:nth-of-type(4)");
// let i = 0;
btn4.addEventListener("click", () => {
i += 0.5;
console.log("恭喜你, 又赚了: " + i + " 元");
});
// 4.1创建一个自定义事件
const myclick = new Event("click");
// 4.2派发 触发自定义事件
// btn4.dispatchEvent(myclick);
// btn4.dispatchEvent(myclick);
// setTimeout: 定时器,用于执行一次性的定时任务
// setInterval: 定时器, 用于执行间歇性的定时任务
// setInterval(() => btn4.dispatchEvent(myclick), 3000);
</script>
在一个对象上触发某类事件,如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序, 那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活)
事件冒泡允许多个操作被集中处理, 把事件处理器添加到一个父级元素上,避免把事件处理器添加到多个子级元素上,
事件冒泡机制有时候是不需要的,需要阻止掉,通过 event.stopPropagation() 来阻止。
事件委托:就是利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作,事件委托首先可以极大减少事件绑定次数,提高性能;其次可以让新加入的子元素也可以拥有相同的操作。 事件委托的关系是将子元素的事件委托到父元素上。
<!-- event: 事件对象 -->
<button onclick="show(event)">click</button>
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
</ul>
<script>
function show(ev) {
// ev: 事件对象
// console.log(ev);
// ev中有二个特别重要的属性
// 1. 事件绑定者(主体) currentTarget
// console.log(ev.currentTarget);
// 2.事件触发者(目标) target
// console.log(ev.target);
// console.log(ev.target === ev.currentTarget); //返回 true
}
const lis = document.querySelectorAll("li");
// 循环给每一个li添加点击事件
// lis[0].onclick = function(){alert(111)}
lis.forEach(function (li) {
li.onclick = function (ev) {
console.log(ev.target);
};
});
// lis.forEach(li => (li.onclick = ev => console.log(ev.currentTarget)));
// onclick这种通过 事件属性 的添加的事件,是冒泡事件
// 冒泡: 子元素的同名事件,会沿着dom树向上逐级触发上级元素的同名事件
// 获取 html === document.documentElement
// 事件委托:
document.querySelector("ul").onclick = (ev) => {
// 1.事件绑定者
// console.log(ev.currentTarget);
// 2. 事件触发者
// console.log(ev.target);
// console.log(ev.target.textContent);
// console.log(ev.target === ev.currentTarget); //返回false
};
</script>
<!-- 阻止默认行为 :event.preventDefault() 阻止冒泡事件 : event.stopPropagation()
上述两个操作可以合并为:return false; -->
<form action="" method="post" id="login" onsubmit="return false">
<label class="title">用户登录</label>
<label for="email">邮箱:</label>
<input type="email" id="email" name="email" value="" autofocus />
<label for="password">密码:</label>
<input type="password" id="password" name="password" />
<button name="submit">登录</button>
</form>
<script>
// form
const login = document.forms.login;
// submit: 提交事件 这里直接提交会报错 表单有一个默认的提交行为 推荐用 禁用默认行为 onsubmit="return false"
// login.onsubmit = () => console.log("提交了");
// 这个也可以 禁用表单的提交行为
// 阻止默认行为 event.preventDefault()
// login.onsubmit = ev => ev.preventDefault();
// 为什么要禁用原生的提交行为?因为我想在提交进行验证和处理
login.submit.onclick = ev => {
// 阻止冒泡事件 : event.stopPropagation()
ev.stopPropagation();
// 每个表单元素都有一个form属性,与所属的表单绑定
console.log(ev.currentTarget.form);
// 非空验证
isEmpty(ev.currentTarget.form);
};
function isEmpty(form) {
if (form.email.value.length === 0) {
alert("邮箱不能为空");
form.email.focus();
return false;
} else if (form.password.value.trim().length === 0) {
alert("密码不能为空");
form.email.focus();
return false;
} else {
alert("验证通过");
}
}
</script>