表单事件
- 常用事件
- submit: 提交
- focus: 焦点
- blur: 失去焦点
- change: 值改变,且失去焦点时
- input: 值一旦改变就触发, 不等失去焦点
- 禁用表单默认提交行为的 3 种方法
form.onsubmit = 'return false'form.button.type = 'button'event.preventDefault()
form.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>表单事件</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<form action="check.php" id="login" method="post">
<fieldset>
<legend class="title">请登录</legend>
<div>
<input type="email" name="email" value="admin@php.cn" autofocus />
<input type="password" name="password" value="123456" />
<button>登录</button>
</div>
</fieldset>
</form>
<script>
// const login = document.querySelector('#login')
const login = document.forms.login;
// 1.提交事件: submit, onsubmit
login.onsubmit = function () {
alert("提交成功");
// 通常在提交之前要做数据验证, 再提交,一般会禁用"默认提交行为"
// 有二种方式
// 方式1: 返回 false
// return false
// 方式2: 用事件对象的方法来禁用默认行为
// event.preventDefault()
};
// 除了操作表单元素<form>的submit之外,还可以修改<button>的type类型来实现禁用行为
const btn = document.querySelector("#login button");
btn.type = "button";
// 修改了button.type属性,将submit -> button , 这个按钮就只是视觉效果,没有提交行为
/**
* submit事件
* 默认提交时自动触发,禁用方式有二个
* 1. 事件方法: 返回false或禁用默认行为ev.preventDefault()
* 2. 修改提交按钮类型: submit -> button
*/
// =========================================
/**
* 其它表单事件
* focus: 获取焦点时
* blur: 失去焦点
* change: 值改变,且失去焦点时
* input: 值改变即触发,不等失去焦点
* select: 选择文本时触发,用适用于<input type=text>或<textarea>
*/
// change
login.email.onchange = function () {
console.log(this.value);
};
// input
login.email.oninput = function () {
console.log(this.value);
};
// blur
login.password.onblur = function () {
if (this.value.length < 6) console.warn("密码不能少于6位");
};
</script>
<!-- 禁用a标签的跳转行为 -->
<a href="https://www.php.cn" id="jump">php.cn</a>
<script>
document.querySelector("#jump").onclick = function () {
event.preventDefault();
};
</script>
</body>
</html>
style.css:
#login {
width: 20em;
margin: 30px auto;
}
#login fieldset {
padding: 1em 2em;
border: none;
border-radius: 0.5em;
box-shadow: 0 0 3px #666;
background: linear-gradient(to left top, lightcyan, white);
}
#login fieldset:hover {
box-shadow: 0 0 8px #666;
transition: 0.3s;
cursor: pointer;
}
#login fieldset .title {
text-align: center;
padding: 0 0.6em;
font-size: 1.3em;
background-color: #fff;
}
#login fieldset div {
display: grid;
gap: 1em;
}
#login input {
height: 2em;
border: none;
background: transparent;
border-bottom: 1px solid #aaa;
outline: none;
outline: none;
}
#login button {
height: 3em;
border: none;
cursor: pointer;
background-color: seagreen;
border-radius: 0.5em;
color: white;
}
#login button:hover {
opacity: 0.8;
transition: 0.3s;
}
实战留言板

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>留言板(toDoList)</title>
</head>
<body>
<!-- 输入框: 用户按下回车键就提交留言 -->
<input
type="text"
placeholder="请留言"
onkeydown="addMessage(this)"
autofocus
/>
<!-- 留言区 -->
<ul class="list"></ul>
<script>
function addMessage(ele) {
// 1. 判断用户是否按下了回车?错误优先的原则
if (event.key !== "Enter") return false;
// 2. 判断用户的留言是否为空?
if (ele.value.length === 0) {
alert("留言不能为空");
return false;
}
// 3. 添加留言
const list = document.querySelector(".list");
// 创建一条留言
let htmlStr = `
<li>
<span>${ele.value}</span>
<!-- this.parentNode 返回父节点的li -->
<button onclick="del(this.parentNode)">删除</button>
</li>
`;
// 最新留言应该永远显示在第一条,在<ul>的第一个子元素的位置上
list.insertAdjacentHTML("afterbegin", htmlStr);
// 4. 清空留言
ele.value = "";
}
// 删除
function del(ele) {
if (confirm("是否删除?")) ele.remove();
// outerHTML: 当前的元素的html字符串描述
// if (confirm('是否删除?')) ele.outerHTML = null
}
</script>
</body>
</html>
模块的使用
- 模块成员导出
/**
* 模块的知识
* 1. 一个js文件,就是一个模块
* 2. 一个js文件是不是模块,由调用环境决定
* 3. 全局,函数,块,现在又多了一个作用域: 模块作用域
* 4. 模块内的成员,默认全是私有的(局部的),外部不可见(类似函数内的成员)
* 5. export : 模块成员导出
* 6. import: 模块成员的导入
*/
// 模块成员
let uname = '安欣'
let greet = function (uname) {
return 'Hello, ' + uname
}
// 1. 逐个导出
export let uname = '安欣'
export let greet = function (uname) {
return 'Hello, ' + uname
}
// 2. 批量导出
// 声明部分
let username = '高启强'
let greeting = function (uname) {
return 'Hello, ' + uname
}
// 导出部分
export { uname, greet }
// 2. 批量别名导出
// 声明部分
// let username = '高启强'
// let greeting = function (uname) {
// return 'Hello, ' + uname
// }
let uname = '高启强'
let greet = function (uname) {
return 'Hello, ' + uname
}
// 导出部分
// export { uname, greet }
// as 别名导出
export { username as uname, greeting as greet }
// 3. 打包导出
// 适用于一个对象或数组的导出
export class User {
constructor(uname) {
this.uname = uname
}
greet() {
return '欢迎您, ' + this.uname
}
}
// 4. 默认导出(匿名导出)
export default class {
constructor(uname) {
this.uname = uname
}
greet() {
return '欢迎您, ' + this.uname
}
}
- 模块使用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>模块的使用</title>
</head>
<body>
<!-- 如果想使用模块,必须设置script.type = "module" -->
<script type="module">
// import 匿名对象 from 模块的路径
// {} : 匿名对象
// let uname
// import { uname as username, greet } from './module.js'
// console.log(username)
// console.log(greet(username))
// import { User } from './module.js'
// 默认导出, 能不能 {} 接收?
// 不行, 因为匿名对象中的属性必须要有名字
// 此时, 必须使用一个命名常量来接收
// import User from './module.js'
import Demo from "./module.js";
// console.log(User)
const user = new Demo("龙哥");
console.log(user.greet());
</script>
</body>
</html>
实战经典选项卡

index.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>模块实战: 选项卡</title>
</head>
<style>
/* 隐藏类 */
.hidden {
display: none;
}
/* 显示类 */
.active {
display: block;
}
/* 激活类 */
.type > *.active,
.content > *.active {
background-color: lightblue;
}
</style>
<body>
<div class="box">
<!-- 1. 栏目组 -->
<div class="type" style="display: flex"></div>
<!-- 2. 内容组 -->
<div class="content"></div>
</div>
<script type="module">
// import { cates, details, createTab, setBtnStatus, setContentStatus } from './tabs.js'
// tabs: 就是一个对象,把导入的成员做为它的属性,全部挂载到它的上面
// tabs: 相当于"命名空间"
import * as tabs from "./tabs.js";
console.log(tabs);
console.log(tabs.cates);
console.log(tabs.details);
// console.log(createTab)
// 获取栏目元素
const type = document.querySelector(".type");
// 获取新闻列表元素
const content = document.querySelector(".content");
// 页面加载时就把内容渲染出来
window.onload = tabs.createTab(type, content);
// 利用"事件代理",将每个按钮的点击,全部委托给父级div.type来实现
type.onclick = (ev) => {
// 1. 设置栏目高亮
tabs.setBtnStatus(ev);
// 2. 激活与当前栏目对应的新闻列表
tabs.setContentStatus(ev, ev.target);
};
</script>
</body>
</html>
tabs.js:
// 选项卡模块
// 1. 栏目
const cates = [
{ cid: 1, cname: "中国新闻" },
{ cid: 2, cname: "国际新闻" },
{ cid: 3, cname: "安徽新闻" },
];
// 2. 内容
// 内容的key 必须与 栏目的id绑定
const details = [
{
key: 1,
cid: 1,
content: [
{
title: "蔡英文窜美,美官员警告中国不要过度反应,外交部回应",
url: "https://news.ifeng.com/c/8OYFjT9c3KM",
},
{
title: "马英九:从来没有一次像今天受到这么大的冲击",
url: "https://news.ifeng.com/c/8OYI5PZyyRs",
},
{
title: "美媒:王毅与沙利文进行电话交谈",
url: "https://news.ifeng.com/c/8OXw5JWvnRM",
},
],
},
{
key: 2,
cid: 2,
content: [
{
title: "美核航母抵韩,半岛局势会失控吗?",
url: "https://news.ifeng.com/c/8OYApVnV1mN",
},
{
title:
"西班牙法律允许强占住房:有华人3年没回西班牙,房子被吉普赛人占了",
url: "https://news.ifeng.com/c/8OXfZLPso8P",
},
{
title: "拜登首次就普京拟在白俄部署核武器表态",
url: "https://news.ifeng.com/c/8OXdmTTNQD6",
},
],
},
{
key: 3,
cid: 3,
content: [
{
title: "省级党政代表团密集赴皖考察!安徽究竟有何看点?",
url: "https://ah.ifeng.com/c/8OXtD8eq0pA",
},
{
title: "合肥、蚌埠、亳州、安庆、宣城最新人事任免!",
url: "https://ah.ifeng.com/c/8OXnxW9z3K5",
},
{
title: "下月起合肥坐高铁到香港!最快只需7时26分",
url: "https://ah.ifeng.com/c/8OXheuq5n55",
},
],
},
];
// 3. 创建栏目和内容
function createTab(type, content) {
// 1. 生成栏目
for (let i = 0; i < cates.length; i++) {
const btn = document.createElement("button");
btn.textContent = cates[i].cname;
// 第一个按钮应该是高亮显示
// 为每个按钮添加一个自定义属性: data-index
// data-key = cates[i].cid
btn.dataset.key = cates[i].cid;
if (i === 0) {
btn.classList.add("active");
}
type.append(btn);
}
// 2. 生成内容
for (let i = 0; i < details.length; i++) {
// 创建<ul>
const ul = document.createElement("ul");
// 为每个<ul>添加自定义属性data-key
ul.dataset.key = details[i].cid;
// 全部内容加载时,默认全隐藏,只要显示第一组新闻列表即可
ul.classList.add(i === 0 ? "active" : "hidden");
// 循环: 将与列表对应的数据全部渲染出来
for (let j = 0; j < details[i].content.length; j++) {
// <li><a href="....">xxxxx</a></li>
const li = document.createElement("li");
const a = document.createElement("a");
a.textContent = details[i].content[j].title;
a.href = details[i].content[j].url;
li.append(a);
ul.append(li);
content.append(ul);
}
}
}
// 4. 自动设置栏目高亮
function setBtnStatus(ev) {
// 1. 去掉所有按钮的激活样式
// console.log(...ev.currentTarget.children);
[...ev.currentTarget.children].forEach((btn) =>
btn.classList.remove("active")
);
// 2. 将当前用户正在点击的按钮添加active
ev.target.classList.add("active");
}
// 5. 设置与栏目对应的内容的激活状态
/**
* 参数
* 1. 事件对象,event
* 2. 当前正在被点击的按钮(选项)
*/
function setContentStatus(ev, currentBtn) {
// 所有的新闻列表<ul>
const lists = document.querySelectorAll(".content > ul");
console.log(lists);
// 1. 将激活的列表全部隐藏 active -> hidden
lists.forEach((list) => list.classList.replace("active", "hidden"));
// 2. 找到与栏目ID相同(对应的)新闻列表<ul>
const currList = [...lists].find(
(list) => list.dataset.key === currentBtn.dataset.key
);
console.log(currList);
// 3. 设置当前列表为激活active
currList.classList.replace("hidden", "active");
}
export { cates, details, createTab, setBtnStatus, setContentStatus };
本文地址:https://www.mainblog.cn/331.html
版权声明:本文为原创文章,版权归 阁主 所有,欢迎分享本文,转载请保留出处!
免责申明:有些内容源于网络,没能联系到作者。如侵犯到你的权益请告知,我们会尽快删除相关内容。
版权声明:本文为原创文章,版权归 阁主 所有,欢迎分享本文,转载请保留出处!
免责申明:有些内容源于网络,没能联系到作者。如侵犯到你的权益请告知,我们会尽快删除相关内容。
黔ICP备19006353号-2
贵公网安备 52052102000042号