JavaScript 对象模型、事件与表单验证实战

83 阅读27分钟

JavaScript常用对象

JavaScript 提供了很多对象供使用者来使用。这些对象总共分类三类

  • 基本对象 image.png

  • BOM 对象 image.png

  • DOM对象

    DOM 中的对象就比较多了,下图只是截取部分

    image.png

这小节我们先学习基本对象,而我们先学习 Array 数组对象和 String 字符串对象。

Array对象

JavaScript Array对象用于定义数组

创建方式

(1) 构造函数方式 new Array()

  • 单数字参数:创建指定长度的空数组。

      let 变量名 = new Array(空数组长度);  //只能填单个数字
      eg:let arr1 = new Array(3); // 创建长度为3的空数组:[empty × 3]
    
  • 多参数:创建包含传入元素的数组。

    let 变量名 = new Array(元素列表);
    eg:let arr2 = new Array(1, 2, 3); // [1, 2, 3]
    

(2) 字面量方式 [](推荐) 更简洁直观,直接初始化元素:

let 变量名 = [元素列表];
eg:let arr = [1, 2, 3]; // [1, 2, 3]

注意:Java中的数组静态初始化使用的是{}定义,而 JavaScript 中使用的是 [] 定义

元素访问

JavaScript 使用方括号 [] 和索引访问数组元素,语法与 Java 一致:

数组名[索引] = 值;    // 修改元素
let value = 数组名[索引]; // 读取元素

示例代码

// 定义数组(字面量方式)
let arr = [1, 2, 3];

// 修改第一个元素
arr[0] = 10;

// 读取元素
console.log(arr[0]); // 输出 10
console.log(arr);    // 输出 [10, 2, 3]

JavaScript 数组与 Java 数组的核心区别

特性JavaScriptJava
类型限制数组元素可以是任意类型(动态类型)数组元素类型固定,声明时确定
长度动态性长度可变,可随时扩展或收缩长度固定,初始化后不可变
内存分配稀疏数组允许存在“空洞”(如 [1,,3]连续内存分配,无空洞
索引越界允许越界赋值,自动扩展数组长度越界访问会抛出 ArrayIndexOutOfBoundsException

特性详解

(1) 动态类型与混合类型元素

  • 动态类型:在声明时无需指定固定类型,类型在运行时动态确定
  • 混合类型:数组参数可包含不同类型的元素,无需统一数据结构
let mixedArr = [1, "hello", true, { name: "John" }, [4, 5]];
// 包含数字、字符串、布尔值、对象、子数组

(2) 动态长度

  • 自动扩展:索引越界时自动扩容,未赋值的索引位置为“空洞”(值为empty,即输出为 undefined)。

    let arr = [10, 20, 30];
    arr[5] = 50; // 扩容至长度6,索引3、4为 empty
    console.log(arr); // [10, 20, 30, empty × 2, 50]
    alert(arr3[4]);  //undefined
    
  • 手动调整长度:通过 length 属性直接修改数组长度。

    arr.length = 2; // 截断数组,仅保留前两个元素
    console.log(arr); // [10, 20]
    

(3) 稀疏数组
允许存在未被赋值的索引:

let sparseArr = [1, , 3]; // 索引1为 empty
console.log(sparseArr[1]); // 输出 undefined

(4) 单个数字参数
若参数为单个数字,会创建空数组而非包含该数字的数组:

let arr = new Array(3); // [empty × 3],而非 [3]

(2) 越界访问
读取越界元素返回 undefined

let arr = [10, 20];
console.log(arr[3]); // undefined

属性

Array 对象提供了很多属性,如下图是官方文档截取的

image.png

而我们只讲解 length 属性,该数组可以用于动态的获取数组的长度,与修改数组长度。而有这个属性,我们就可以遍历数组了

var arr = [1,2,3];
for (let i = 0; i < arr.length; i++) {
    alert(arr[i]);
}

数组与对象的关系

  • JavaScript 数组本质是特殊对象,索引实际是字符串键:
    console.log(typeof arr); // "object"
    console.log(Object.keys(arr)); // ["0", "1", "2"]
    

常用方法

Array 对象同样也提供了很多方法,如下图是官方文档截取的

image.png

而我们只演示 push 函数和 splice 函数。

  • push 函数:给数组添加元素,也就是在数组的末尾添加元素

    参数表示要添加的元素

    // push:添加方法
    var arr5 = [1,2,3];
    arr5.push(10);
    alert(arr5);  //数组的元素是 {1,2,3,10}
    
  • splice 函数:删除元素

    参数1:索引。表示从哪个索引位置删除
    参数2:个数。表示删除几个元素

    // splice:删除元素
    var arr5 = [1,2,3];
    arr5.splice(0,1); //从 0 索引位置开始删除,删除一个元素 
    alert(arr5); // {2,3}
    

String 对象

创建方式

(1) 使用 new 关键字:通过构造函数显式创建 String 对象。

var str = new String("Hello World");

(2) 直接赋值(推荐)(JavaScript 会自动转换为 String 对象)

var str = "Hello World"; 

属性:length

  • 作用:获取字符串的长度(字符数量)。
  • 特点:动态反映当前字符串的长度(字符串不可变,长度固定)。
  • 示例
    var str = "JavaScript";
    console.log(str.length); // 输出:10
    

常用方法

  1. charAt(index)
  • 作用:返回字符串中指定索引位置的字符。
  • 参数index(从 0 开始)。
  • 返回值:对应位置的字符,若索引越界则返回空字符串。
  • 示例
    var str = "Hello";
    console.log(str.charAt(1)); // 输出:"e"
    
  1. indexOf(searchStr)
  • 作用:查找子字符串在字符串中首次出现的索引位置。
  • 参数searchStr(要查找的子字符串)。
  • 返回值:首次出现的索引,未找到返回 -1
  • 示例
    var str = "Hello World";
    console.log(str.indexOf("World")); // 输出:6
    
  1. trim()
  • 作用:去除字符串两端的空白字符(空格、换行、制表符等)。
  • 返回值:新字符串,原字符串不变(字符串不可变)。
  • 应用场景:处理用户输入(如登录表单去除多余空格)。
  • 示例
    var input = "   user@example.com   ";
    var trimmed = input.trim();
    console.log(trimmed); // 输出:"user@example.com"
    console.log("1" + input.trim() + "1"); // 输出:"1user@example.com1"
    

注意事项

  1. 字符串不可变性:所有字符串方法返回新字符串,不会修改原字符串。
  2. 直接赋值 vs new String
    • 直接赋值的字符串是原始类型,但在必要时会自动包装为 String 对象。
    • 使用 new String 会显式创建对象,可能影响类型判断(typeof 返回 "object")。
  3. 浏览器兼容性trim() 方法虽未在早期规范中,但所有现代浏览器均支持。

自定义对象

创建方式

var 对象名 = {
    属性名1: 属性值1,
    属性名2: 属性值2,
    // ... 更多属性,
    方法名: function(参数列表) { 
        // 方法体 
    },
    // ... 更多方法
};

对象组成与理解

  1. 属性:存储数据的键值对

    • 格式:属性名: 属性值
    • 示例:name: "zhangsan"
  2. 方法:对象的行为(函数)

    • 格式:方法名: function() { ... }
    • 示例:eat: function() { alert("干饭~"); }
  3. 类比理解

    现实对象JavaScript 对象
    手机对象
    颜色属性color: "黑色"
    拍照功能takePhoto: function(){}

通过这种自定义对象的方式,可以方便地将现实世界的事物抽象为代码中的数据结构。

访问对象成员

  1. 访问属性

    对象名.属性名
    eg:alert(person.name); // 输出:zhangsan
    
  2. 调用方法

    对象名.方法名()
    eg:person.eat(); // 执行方法,输出:干饭~
    

完整示例

// 1. 定义对象
var person = {
    name: "zhangsan",  // 字符串属性
    age: 23,           // 数字属性
    eat: function() {   // 方法
        alert("干饭~");
    }
};

// 2. 访问属性
alert(person.name);  // 输出:zhangsan
alert(person.age);   // 输出:23

// 3. 调用方法
person.eat();        // 弹出提示框显示"干饭~"

注意事项

  1. 对象使用{}包裹,内部成员用逗号分隔
  2. 最后一个属性/方法后不要加逗号(否则可能引发错误)
  3. 方法定义必须使用function关键字
  4. 方法调用必须带括号(),即使没有参数
  5. 属性名可以加引号("name"),但通常省略

BOM

BOM 概述

  • BOM(Browser Object Model):浏览器对象模型,JavaScript 将浏览器的各个组成部分封装为对象,开发者可通过操作这些对象控制浏览器行为。

  • BOM中包含对象

    • Window(窗口对象)
    • History(历史记录对象)
    • Location(地址栏对象)
    • Navigator(浏览器信息对象,少用)
    • Screen(屏幕对象,少用)

下图是 BOM 中的各个对象和浏览器的各个组成部分的对应关系 image.png

BOM 中的 Navigator 对象和 Screen 对象基本不会使用,所以暂且只对 WindowHistoryLocation 对象进行讲解。

Window对象

Window对象是JavaScript对浏览器窗口的封装,作为BOM(Browser Object Model)的核心对象,它是所有浏览器对象的顶层对象。

特点

  1. 全局对象:在浏览器环境中,Window对象是全局对象
  2. 隐式调用:所有全局变量和函数都自动成为Window对象的属性和方法
  3. 无需创建:可直接使用window引用,window.前缀可省略

获取Window对象

该对象不需要创建,可直接使用,其中 window. 可以省略。比如我们之前使用的 alert() 函数,其实就是 window 对象的函数,在调用时可以写成如下两种

// 显式调用
window.alert("显式调用");

// 隐式调用(推荐)
alert("隐式调用");

Window对象属性

属性说明对应对象
location当前窗口的URL信息Location
history浏览历史记录History
navigator浏览器相关信息Navigator
screen屏幕信息Screen
document当前文档对象(DOM核心)Document

使用示例:

console.log(window.location.href); // 获取当前URL
console.log(location.href);        // 等效写法

Window对象函数

对话框函数confirm()

confirm("文本内容") 会弹出一个对话框,显示指定的文本内容,并提供确定、取消按钮供用户选择。

  • 返回值
    点击 "确定" → 返回 true
    点击 "取消" 或关闭对话框 → 返回 false

  • 完整语法

    let result = confirm("确认删除?");
    console.log(isDelete); // 点击确定返回true,取消返回false
    if (result) {
      // 用户点击了"确定"执行
    } else {
      // 用户点击了"取消"或关闭对话框执行
    }
    
  • 实际效果 image.png

  • 注意事项

    • 对话框是 模态的,会阻塞代码执行,直到用户响应。
    • 不同浏览器的对话框样式可能略有差异,但功能一致。

应用:如下图每一条数据后都有 删除 按钮,当用户点击 删除 按钮,有可能是用户的误操作,所以对于删除操作需要让用户进行再次确认,此时就需要用到 confirm() 函数。 image.png

定时器函数setTimeout()

setTimeout(function,毫秒值) : 在一定的时间间隔后执行一个function,只执行一次
setInterval(function,毫秒值) :在一定的时间间隔后执行一个function,循环执行

setTimeout() - 延迟执行(单次)

setTimeout(() => {
  alert("已等待3秒,即将显示");
}, 3000);

setInterval() - 间隔执行(循环)

let timer = setInterval(() => {
  console.log("每秒输出一次");
}, 1000);

清除定时器

clearTimeout(timerID);  // 清除setTimeout
clearInterval(timerID); // 清除setInterval

综合案例:灯泡开关切换

需求:实现灯泡自动切换(1秒间隔)

<!DOCTYPE html> <!-- HTML5文档类型声明,告知浏览器使用HTML5标准解析 -->
<html> <!-- 文档根元素,包含整个网页内容 -->
<head>
    <title>灯泡切换</title> <!-- 定义浏览器标签页标题 -->
</head>
<body>
    <!-- 交互按钮组 -->
    <button onclick="on()">开灯</button> <!-- 绑定点击事件调用on()函数 -->
    <img id="myImage" src="off.gif"> <!-- 初始显示关闭状态的灯泡图片 -->
    <button onclick="off()">关灯</button> <!-- 绑定点击事件调用off()函数 -->

    <script>
        // 灯泡控制函数
        function on() {
            /* 通过DOM API获取图片元素并切换光源 */
            document.getElementById('myImage').src = 'on.gif'; // 修改img元素的src属性实现图片切换
        }
        
        function off() {
            document.getElementById('myImage').src = 'off.gif'; // 原理同上
        }

        // 自动切换逻辑
        let state = 0; // 状态变量,0表示关灯状态,1表示开灯状态
        setInterval(() => { // 创建周期为1000ms的定时器[[15]
            state % 2 === 0 ? on() : off(); // 根据状态奇偶性切换灯泡
            state++; // 状态自增实现状态轮转
        }, 1000); // 每隔1000ms触发回调函数
    </script>
</body>
</html>

代码解析

  1. 定义on()off()函数控制灯泡图片切换
  2. 使用state变量记录当前状态(偶数=开灯,奇数=关灯)
  3. setInterval每1000ms执行一次状态切换
  4. 通过条件运算符决定调用哪个函数

注意事项

  1. 避免滥用对话框方法,会影响用户体验
  2. 定时器返回值是数字ID,用于清除定时器
  3. 在严格模式("use strict")下,this在全局作用域不再指向window
  4. 现代浏览器多标签页环境下,每个标签页有独立的window对象

History 对象

History 对象 是 JavaScript 中用于操作浏览器会话历史(即用户访问过的页面记录)的接口,允许开发者以编程方式控制页面的前进和后退行为。

获取 History 对象
通过 window.history 获取,其中 window. 可以省略:

const history = window.history; 
// 或直接使用 history
console.log(history); // 输出 History 对象

History 对象的常用方法
以下是两个核心方法,与浏览器工具栏的前进/后退按钮功能一致:
back()

  • 作用:导航到会话历史中的上一页(等同于用户点击浏览器的后退按钮)。
  • 示例
    history.back(); // 返回上一页
    

forward()

  • 作用:导航到会话历史中的下一页(等同于用户点击浏览器的前进按钮)。
  • 示例
    history.forward(); // 前进到下一页
    

注意事项

  1. 历史记录依赖

    • back()forward() 的可用性取决于当前页面的会话历史。
    • 如果当前页面是会话历史的第一页,back() 将无效;同理,若为最后一页,forward() 无效。
  2. 用户交互限制

    • 现代浏览器通常要求这些方法的调用必须由用户触发(如点击事件),以防止脚本滥用。
    • 示例:通过按钮触发后退操作
      <button onclick="history.back()">后退</button>   
      
  3. 扩展方法 go()(补充说明):

    • history.go(n):跳转到历史记录中相对于当前页的第 n 个页面。
      history.go(-1); // 等效于 back()
      history.go(1);  // 等效于 forward()
      

Location 对象详解

核心概念

image.png

Location 对象是 JavaScript 对浏览器地址栏的封装,属于 Window 对象的一部分。开发者可通过该对象获取当前 URL 信息、修改 URL 实现页面跳转或刷新操作。

获取 Location 对象

window.location;  // 标准写法(window可省略)
location;         // 简写形式(实际指向window.location)

所有操作均通过 location 对象完成,无需显式创建。

核心属性(按功能分类)

属性作用描述示例 URL[www.example.com:8080/order]
href完整 URL(最常用,用于页面跳转)"[http://www.example.com:8080/order](http://www.example.com:8080/order)?id=1#intro"
protocol协议(含:"http:"
host主机名 + 端口"[www.example.com:8080](https://www.example.com:8080)"
hostname主机名(不含端口)"[www.example.com](https://www.example.com)"
port端口号"8080"
pathnameURL 路径(域名后的部分)"/order"
search查询参数(以?开头)"?id=1"
hash锚点(以#开头)"#intro"
origin协议 + 主机名 + 端口(只读)"[http://www.example.com:8080](http://www.example.com:8080)"

注:修改任意属性(如location.hash="#top")会立即更新地址栏并触发页面动作。

常用属性href代码演示:

alert("要跳转了");
location.href = "https://www.baidu.com";

在浏览器首先会弹框显示 要跳转了 ,当我们点击了 确定 就会跳转到 百度 的首页。

核心方法

方法作用href 的区别
assign(url)跳转到新页面(可后退)等效于直接设置 href,但语义更明确
replace(url)替换当前页面(不可后退)不写入历史记录,无法通过浏览器返回按钮回到原页面
reload()重新加载当前页面
(参数 true 强制从服务器加载,跳过缓存)
无跳转,仅刷新

典型场景对比:

// 方式1:允许后退
location.assign("https://baidu.com"); 

// 方式2:禁止后退(适用于登录后清除历史)
location.replace("https://baidu.com"); 

// 方式3:刷新当前页(优先使用缓存)
location.reload();  
// 强制刷新(类似 Ctrl+F5)
location.reload(true); 

经典案例:3秒后自动跳转

需求实现:

document.write("3秒后跳转到百度...");
setTimeout(() => {
  location.href = "https://www.baidu.com";
}, 3000);

DOM

DOM 概述

DOM(文档对象模型) 是浏览器将 HTML/XML 文档解析为树状结构的编程接口,所有元素(如标签、属性、文本)被封装为对象,形成可编程访问的节点层级。

  • 核心对象
    • Document:整个文档的入口,如 document 对象。
    • Element:HTML 标签元素(如 <div>)。
    • Attribute:元素的属性(如 class="box")。
    • Text:标签内的文本内容。
    • Comment:HTML 注释。

树状结构示例

image.png

DOM 的作用

通过 JavaScript 动态操作网页:

  • 修改内容:如更新文本、插入新元素。
  • 改变样式:调整元素的 CSS 属性(颜色、尺寸等)。
  • 事件响应:绑定点击、鼠标悬停等交互行为。
  • 增删元素:动态添加或移除页面元素。

DOM 标准划分(W3C 规范)

DOM 是 W3C(万维网联盟)定义的访问 HTML 和 XML 文档的标准。该标准被分为 3 个不同的部分:

  1. 核心 DOM
    • 通用结构化文档模型,适用于 HTML 和 XML。
    • 定义基础对象(Document、Element 等)和方法。
  2. XML DOM
    • 针对 XML 文档的扩展,提供专用接口。
  3. HTML DOM
    • 针对 HTML 文档的扩展,提供专用接口。

    • 在核心 DOM 基础上,为每个 HTML 标签封装特定对象。

    • 例如:
      <img> 标签在浏览器加载到内存中时会被封装成 Image 对象,同时该对象也是 Element 对象。
      <input type='button'> 标签在浏览器加载到内存中时会被封装成 Button 对象,同时该对象也是Element 对象。

核心对象详解

Document 对象&获取 Element 对象

功能:整个文档的根节点,提供全局操作方法。

HTML 中的 Element 对象可以通过 Document 对象获取,而 Document 对象是通过 window 对象获取。

  • getElementById() :根据id属性值获取,返回单个Element对象
  • getElementsByTagName() :根据标签名称获取,返回Element对象数组
  • getElementsByName() :根据name属性值获取,返回Element对象数组
  • getElementsByClassName() :根据class属性值获取,参数为字符串形式的一个或多个类名(用空格分隔,例box active),返回Element对象数组
  • querySelector():按 CSS 选择器获取,参数为符合 CSS 选择器语法的字符串,仅返回第一个Element对象。(支持所有CSS选择器,如.box.active[data-id]div > p

使用示例

  1. 根据 id 属性值获取 img 元素对象,返回单个对象

    var img = document.getElementById("light");  //获取id属性值为light 的img元素对象并返回
    alert(img);
    

    结果如下:image.png

  2. 根据标签名称获取所有的 div 元素对象(根据name属性值或class属性值获取同理)

    var divs = document.getElementsByTagName("div");// 返回一个数组,数组中存储的是 div 元素对象
    // alert(divs.length);  //输出 数组的长度
    //遍历数组
    for (let i = 0; i < divs.length; i++) {
        alert(divs[i]);
    }
    

创建元素

const newDiv = document.createElement('div'); // 创建新元素
document.body.appendChild(newDiv); // 添加到页面

文档操作

document.title = '新标题'; // 修改页面标题
document.write('<p>动态内容</p>'); // 写入内容(慎用)

Element 对象及其使用

  • 对应关系:每个 HTML 标签(如 <div>)都是 Element 的对象。
  • 常用属性和方法
    • 属性操作

      element.id = 'newId'; // 修改 ID
      element.setAttribute('data-info', 'value'); // 添加自定义属性
      
    • 内容修改

      element.innerHTML = '<strong>加粗文本</strong>'; // 解析 HTML
      element.textContent = '纯文本内容'; // 仅处理文本
      
    • 类名操作

      element.classList.add('active'); // 添加类
      element.classList.remove('old-class'); // 移除类
      

HTML 中的 Element 元素对象有很多,不可能全部记住,以后是根据具体的需求查阅文档使用。

需求

  1. 点亮灯泡
    此案例由于需要改变 img 标签 的图片,所以我们查询文档,下图是查看文档的流程:
image.png

代码实现:

//1,根据 id='light' 获取 img 元素对象
var img = document.getElementById("light");
//2,修改 img 对象的 src 属性来改变图片
img.src = "../imgs/on.gif";
  1. 使所有的复选框呈现被选中的状态
    此案例我们需要看 复选框 元素对象有什么属性或者函数是来操作 复选框的选中状态。下图是文档的查看
image.png
//1,获取所有的 复选框 元素对象
var hobbys = document.getElementsByName("hobby");
//2,遍历数组,通过将 复选框 元素对象的 checked 属性值设置为 true 来改变复选框的选中状态
for (let i = 0; i < hobbys.length; i++) {
    hobbys[i].checked = true;
}

Attribute 、Text 和 Comment 对象

  • Attribute 对象

    功能:表示元素的属性(如 classhref)。
    操作方式:通常通过 Element 的方法间接操作:

    element.getAttribute('class'); // 获取属性值
    element.removeAttribute('disabled'); // 删除属性
    
  • Text 对象
    功能:表示元素内的文本节点。
    示例:

    const textNode = document.createTextNode('新文本');
    element.appendChild(textNode); // 添加文本到元素
    
  • Comment 对象
    表示 HTML 注释(<!-- 注释 -->),较少直接操作。

事件监听

事件是HTML元素上发生的特定交互动作,如点击按钮、鼠标移动到元素之上 、 按下键盘按键、页面加载完成等。事件是用户与网页交互的桥梁,也是动态网页的基础。

事件监听指通过JavaScript代码监测特定事件的发生,并执行相应的逻辑(如修改页面内容、验证输入等)。例如:点击按钮切换图片、输入框失去焦点时校验格式等。

事件绑定的三种方式

1. HTML标签内联事件属性绑定

原理:直接在HTML标签中通过on+事件名属性绑定函数。例如,onclick属性对应点击事件,属性值为要执行的函数名或代码段。

代码示例

  • 绑定函数名
<input type="button" value="点击" onclick="handleClick()">
function handleClick() {
    alert("按钮被点击!");
}
  • 直接写代码
<input type="button" value="点击" onclick="alert('按钮被点击!')">

2. DOM元素属性绑定

原理:通过JavaScript获取DOM元素后,为其事件属性(如onclick)赋值一个函数。

代码示例

<input type="button" value="点击" id="myButton">
const button = document.getElementById("myButton");
button.onclick = function() {
    alert("按钮被点击!");
};
//或者
document.getElementById("btn").onclick = function (){
alert("按钮被点击!")};
  • 同一事件属性只能绑定一个函数,后绑定的会覆盖之前的。

两种方式的对比

特性HTML内联绑定DOM属性绑定
代码分离差(HTML与JS混杂)优(JS单独管理逻辑)
维护性低(修改需查找多个位置)高(逻辑集中处理)
绑定数量限制只能绑定一个函数只能绑定一个函数
适用场景简单测试或快速原型实际项目开发

3. 更现代的绑定方式(addEventListener

原理:使用addEventListener方法动态绑定事件,支持多个监听器及事件传播控制。

代码示例

button.addEventListener("click", function() {
    alert("第一个监听器");
});
button.addEventListener("click", function() {
    alert("第二个监听器"); // 不会覆盖前一个
});

优势

  • 支持同一事件绑定多个函数。
  • 可控制事件在捕获或冒泡阶段触发。
  • 更易移除特定监听器(通过removeEventListener)。

最佳实践建议

  1. 避免内联绑定:实际开发中优先使用DOM属性或addEventListener,提升代码可维护性。
  2. 事件委托:动态生成的元素可通过父元素统一监听事件,减少重复绑定(如表格行点击)。
  3. 分离关注点:将事件处理逻辑封装为独立函数,增强代码可读性。

常见事件属性

事件属性是HTML元素的特殊属性,用于在用户操作(点击、输入、移动鼠标等)或浏览器状态变化时触发JavaScript代码,实现动态交互功能。每个事件属性对应一种行为场景,例如onclick对应鼠标点击,onfocus对应元素获得焦点。

常用事件属性分类与说明

以下为开发者最常用的核心事件属性,按交互场景分类:

分类事件属性触发条件
鼠标事件onclick鼠标光标单击元素时触发
onmouseover鼠标光标移动到元素上时触发
onmouseout鼠标光标移出元素时触发
表单事件onfocus元素获得焦点时触发
onblur元素失去焦点时触发
onsubmit表单提交时触发(需绑定到<form>标签)
窗口/页面事件onload页面或图片加载完成时触发
键盘事件onkeydown按下键盘任意键时触发
  • onfocusonblur只能绑定以下元素
    表单输入类的元素:<input>、<select>、<textarea>、<button>
    添加 tabindex 属性后的 非表单元素,如:

    <div tabindex="0" onfocus="console.log('div获得焦点')">点击我</div>
    

    例外:
    元信息元素(<base>、<script>、<meta>)、隐藏或不可见元素(如<input type="hidden">、<div style="display: none">),即使设置 tabindex,浏览器也不会支持焦点事件

  • 焦点得失的核心事件
    获得焦点onfocus):

    • 触发时机:通过 Tab 键、鼠标点击、代码调用 element.focus() 使元素成为当前焦点。
    • 示例:焦点移动到输入框时,输入框边框高亮。

    失去焦点onblur):

    • 触发时机:用户按下 Tab 切走焦点、点击其他区域、代码调用 element.blur()

    • 示例:输入框失去焦点时自动验证输入内容。‘’

    注:按键盘 Tab 键时,焦点会按顺序在页面中所有“可聚焦元素”之间移动。

  • 表单事件与鼠标事件相互独立,可以同时出现

核心事件属性详解

onfocus 与 onblur

  • 本质:二者是互补事件,用于处理元素的焦点状态。
  • 示例
    <input type="text" onfocus="this.style.backgroundColor='yellow'" 
           onblur="this.value = this.value.toUpperCase(); this.style.backgroundColor='white'">
    

根据JavaScript的事件处理机制,当事件处理函数直接以内联方式绑定到> HTML元素时(如onfocusonblur等属性),this默认指向触发事件的DOM元素本身
例外: 若内联代码调用全局函数,如onclick="handleClick()",则函数内部的this默认指向window(非严格模式)或undefined(严格模式)。此时需显式传递this作为参数; 内联事件中嵌套的严格模式函数会丢失this(如function() { "use strict"; ... }

onsubmit

  • 核心机制:通过事件处理函数返回值控制表单是否提交。
    • 返回true:允许表单提交。
    • 返回false:阻止提交(用于验证失败时)。
  • 代码示例
    <form onsubmit="return validateForm()">
      <input type="text" name="username" required>
      <input type="submit" value="提交">
    </form>
    <script>
      document.getElementById("register").onsubmit = function () { 
          // 获取用户名输入框的值 
          var username = this.elements["username"].value; 
          // 如果用户名输入框为空 
          if (username === "") { 
              alert("用户名不能为空!"); 
              // 返回 false 阻止表单提交 
              return false; 
          } 
          // 验证通过,返回 true 提交表单 
          return true; 
      };
    </script>
    

DOM属性赋值方式绑定事件中的this(如上onsubmit) 通过element.onsubmit = function() {}赋值时,事件处理函数成为元素的“方法”,因此this遵循“方法调用规则”,指向所属对象(即元素本身)

扩展事件属性
事件属性说明
onchange表单元素值改变时触发(如下拉框选择)
onkeypress按下并释放键盘键时触发(区分大小写)
ondblclick双击元素时触发
onresize浏览器窗口大小变化时触发

表单验证案例

需求

image.png

如上注册页面,对表单进行校验,如果输入的用户名、密码、手机号符合规则,则允许提交;如果不符合规则,则不允许提交。 完成以下需求:

  1. 当输入框失去焦点时,验证输入内容是否符合要求
  2. 当点击注册按钮时,判断所有输入框的内容是否都符合要求,如果不合符则阻止表单提交

环境准备

下面是初始页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>欢迎注册</title>
    <link href="../css/register.css" rel="stylesheet">
</head>
<body>
    <div class="form-div">
        <div class="reg-content">
            <h1>欢迎注册</h1>
            <span>已有帐号?</span> <a href="#">登录</a>
        </div>
        <form id="reg-form" action="#" method="get">
            <table>
                <tr>
                    <td>用户名</td>
                    <td class="inputs">
                        <input name="username" type="text" id="username">
                        <br>
                        <span id="username_err" class="err_msg" style="display: none">用户名不太受欢迎</span>
                    </td>
                </tr>

                <tr>
                    <td>密码</td>
                    <td class="inputs">
                        <input name="password" type="password" id="password">
                        <br>
                        <span id="password_err" class="err_msg" style="display: none">密码格式有误</span>
                    </td>
                </tr>

                <tr>
                    <td>手机号</td>
                    <td class="inputs"><input name="tel" type="text" id="tel">
                        <br>
                        <span id="tel_err" class="err_msg" style="display: none">手机号格式有误</span>
                    </td>
                </tr>
            </table>
            <div class="buttons">
                <input value="注 册" type="submit" id="reg_btn">
            </div>
            <br class="clear">
        </form>
    </div>
    <script>
    
    </script>
</body>
</html>

验证输入框

此小节完成如下功能:

  • 当输入不符合规则时,会通过特定的 span 标签给出用户提示;若所有输入都符合规则,则允许提交表单,否则阻止表单提交。
  • 分别对用户名、密码和手机号输入框进行验证,验证规则要求如下:
    • 用户名:长度为 6 - 12 位。
    • 密码:长度为 6 - 12 位。
    • 手机号:长度为 11 位。

代码如下:

//1. 验证用户名是否符合规则 
//1.1 获取用户名的输入框 
var usernameInput = document.getElementById("username");  
 
//1.2 绑定onblur事件 失去焦点 
usernameInput.onblur  = function () { 
    //1.3 获取用户输入的用户名 
    var username = usernameInput.value.trim();   //trim()方法用于去除字符串两端的空白字符 
 
    //1.4 判断用户名是否符合规则:长度 6~12 
    if (username.length  >= 6 && username.length  <= 12) { 
        //符合规则 
        document.getElementById("username_err").style.display  = 'none'; 
    } else { 
        //不合符规则 
        document.getElementById("username_err").style.display  = ''; 
    } 
} 

密码和手机号的验证代码结构与上述代码类似,只是验证规则逻辑代码和操作的元素 ID 不同。

验证表单

需求及解决方案

  • 需求:在用户点击注册按钮时,需要对所有输入项进行校验。
  • 为避免代码重复,要将每个输入框的验证代码抽象成有名字的函数,方便在表单提交时调用。
  • 实现该功能需要 一个函数获取所有表单元素对象,并绑定 onsubmit 事件,每个函数都返回结果来决定是提交表单还是阻止表单提交

函数抽象

以下是抽象后的验证函数:

// 验证用户名是否符合规则 
// 获取用户名的输入框 
function checkUsername() {{
    var usernameInput = document.getElementById("username");   
    // 获取用户输入的用户名
    var username = usernameInput.value.trim();   
    // 判断用户名是否符合规则:长度 6~12
    var flag = username.length  >= 6 && username.length  <= 12; 
    if (flag) {{ 
        //符合规则 
        document.getElementById("username_err").style.display  = 'none'; 
    }} else {{ 
        //不符合规则 
        document.getElementById("username_err").style.display  = ''; 
    }} 
    return flag; 
}} 
 
// 验证密码是否符合规则
// 获取密码的输入框
function checkPassword() {{ 
    var passwordInput = document.getElementById("password");   
    // 获取用户输入的密码
    var password = passwordInput.value.trim();   
    // 判断密码是否符合规则:长度 6~12
    var flag = password.length  >= 6 && password.length  <= 12; 
    if (flag) {{ 
        //符合规则 
        document.getElementById("password_err").style.display  = 'none'; 
    }} else {{ 
        //不符合规则 
        document.getElementById("password_err").style.display  = ''; 
    }} 
    return flag; 
}} 
 
// 验证手机号是否符合规则 
// 获取手机号的输入框 
function checkTel() {{ 
    var telInput = document.getElementById("tel");   
    // 获取用户输入的手机号 
    var tel = telInput.value.trim();   
    // 判断手机号是否符合规则:长度 11
    var flag = tel.length  == 11; 
    if (flag) {{ 
        //符合规则 
        document.getElementById("tel_err").style.display  = 'none'; 
    }} else {{ 
        //不符合规则 
        document.getElementById("tel_err").style.display  = ''; 
    }} 
    return flag; 
}} 

//获取表单对象
var regForm = document.getElementById("reg-form"); 

//绑定onsubmit 事件
regForm.onsubmit  = function () {
    //判断每一个表单项是否都符合要求,如果有一个不合符,则返回false
    var flag = checkUsername() && checkPassword() && checkTel();
    return flag;
}

RegExp对象

RegExp 对象
JavaScript 中封装正则表达式的内置对象,用于判断字符串是否符合特定规则。例如验证字符串是否符合邮箱规则。

如下图是百度贴吧中的帖子

image.png

我们可以通过爬虫技术去爬取该页面源代码,然后获取页面中所有的邮箱,后期我们可以给这些邮箱地址发送推广的邮件。那么问题来了,如何才能知道页面内容中哪些是邮箱地址呢?这里就可以使用正则表达式来匹配邮箱。

正则表达式

  1. 正则表达式定义
    正则表达式定义了字符串组成的规则,用于判断指定字符串是否符合规则以快速验证格式提取特定模式的文本片段
    符合则返回 true,不符合返回 false。它与语言无关,很多语言都支持,不同语言使用方式有别,在 JavaScript 中需通过正则对象使用。

    核心作用:验证输入合法性(如邮箱格式)、批量提取数据(如网页中的邮箱)、文本替换。

  2. 常用规则符号

    1. 边界符号
    • ^:表示字符串的开始。
    • $:表示字符串的结束。
    1. 字符范围符号
    • []:代表某个范围内的单个字符,如 [0 - 9] 表示单个数字字符。
    • .:代表任意单个字符,但不包括换行和行结束符。
    • \w:代表单词字符,包括字母、数字、下划线,相当于 [A - Za - z0 - 9_]
    • \d:代表数字字符,相当于 [0 - 9]
  3. 量词

    1. +:表示匹配至少一个指定字符。
    2. *:表示匹配零个或多个指定字符。
    3. ?:表示匹配零个或一个指定字符。
    4. {x}:表示匹配 x 个指定字符。
    5. {m,}:表示匹配至少 m 个指定字符。
    6. {m,n}:表示匹配至少 m 个、最多 n 个指定字符。

正则对象使用

创建对象

正则对象有两种创建方式,核心区别在于特殊字符转义规则和灵活性:

  1. 直接量方式(推荐)
    var reg = /正则表达式/修饰符;  // 无需引号,直接写模式 
    
    • 特点:语法简洁性能更优,无需转义特殊字符(如\b直接写作/\b/
    • 示例:
      var reg = /\bis\b/g;  // 匹配独立单词"is",全局搜索 
      
  2. 构造函数方式(动态生成时使用)
    var reg = new RegExp("正则表达式", "修饰符");  // 字符串参数需注意转义 
    
    • 特点:适合动态拼接正则规则,但需双重转义特殊字符(如\b需写成"\\b"
    • 示例:
      var reg = new RegExp("\\bis\\b", "gi");  // 等价于直接量 /\bis\b/gi 
      
函数:test(str)

作用:检测字符串是否包含匹配模式的子串,返回布尔值 true或 false
语法:

reg.test(str);  // reg 为正则对象,str 为待检测字符串 

使用示例:

var reg = /\d{3}/;  // 匹配连续3位数字 
console.log(reg.test("abc123"));  // true(包含3位数字)
console.log(reg.test("a1b2c3"));  // false(无连续3位数字)

注意事项:

  1. 全局模式(g)的副作用
    启用全局匹配时,test() 会更新正则对象的 lastIndex 属性,导致连续调用结果不一致:

    var reg = /\d/g;
    console.log(reg.test("a1b2"));  // true(匹配到1)
    console.log(reg.test("a1b2"));  // true(匹配到2)
    console.log(reg.test("a1b2"));  // false(无更多匹配)
    

    解决方法:非必要不使用 g 修饰符,或重置 lastIndex

    reg.lastIndex = 0;  // 重置匹配位置 
    
  2. 空正则匹配
    若正则表达式为空(如//),默认匹配任意非空字符串:

    var reg = //;
    console.log(reg.test(""));     // false 
    console.log(reg.test("abc"));  // true 
    

代码示例

// 规则:单词字符,长度 6 到 12 
// 1. 创建正则对象,封装正则表达式 
var reg = /^\w{6,12}$/; 
 
var str = "abcccc"; 
// 2. 判断 str 字符串是否符合 reg 封装的正则表达式的规则 
var flag = reg.test(str); 
alert(flag); 

在这个示例中,先创建了一个正则对象 reg,其规则为字符串以单词字符开头和结尾,且长度在 6 到 12 之间。然后使用 test 方法判断字符串 str 是否符合该规则,并将结果存储在 flag 变量中,最后通过 alert 弹窗显示判断结果。

:模式修饰符速查表

修饰符作用示例
g全局匹配(非首次匹配后停止)/a/g
i忽略大小写/a/i
m多行模式(影响^$的行为)/^a/gm

改进表单校验案例

表单校验案例中的规则是我们进行一系列的判断来实现的,现在学习了正则对象后,就可以使用校验的强大工具——正则对象来改进这个案例,代码实现:

<!DOCTYPE html> 
<html lang="en"> 
 
<head> 
    <meta charset="UTF-8"> 
    <title>欢迎注册</title> 
    <link href="../css/register.css"  rel="stylesheet"> 
</head> 
 
<body> 
 
    <div class="form-div"> 
        <div class="reg-content"> 
            <h1>欢迎注册</h1> 
            <span>已有帐号?</span> <a href="#">登录</a> 
        </div> 
        <form id="reg-form" action="#" method="get"> 
 
            <table> 
 
                <tr> 
                    <td>用户名</td> 
                    <td class="inputs"> 
                        <input name="username" type="text" id="username"> 
                        <br> 
                        <span id="username_err" class="err_msg" style="display: none">用户名不太受欢迎</span> 
                    </td> 
 
                </tr> 
 
                <tr> 
                    <td>密码</td> 
                    <td class="inputs"> 
                        <input name="password" type="password" id="password"> 
                        <br> 
                        <span id="password_err" class="err_msg" style="display: none">密码格式有误</span> 
                    </td> 
                </tr> 
 
 
                <tr> 
                    <td>手机号</td> 
                    <td class="inputs"><input name="tel" type="text" id="tel"> 
                        <br> 
                        <span id="tel_err" class="err_msg" style="display: none">手机号格式有误</span> 
                    </td> 
                </tr> 
 
            </table> 
 
            <div class="buttons"> 
                <input value="注 册" type="submit" id="reg_btn"> 
            </div> 
            <br class="clear"> 
        </form> 
 
    </div> 
 
 
    <script> 
        // 获取用户名输入框 
        const usernameInput = document.getElementById("username");  
 
        // 为用户名输入框绑定失去焦点事件,调用验证函数 
        usernameInput.onblur  = checkUsername; 
 
        // 验证用户名是否符合规则 
        function checkUsername() { 
            // 获取用户输入的用户名并去除首尾空格 
            const username = usernameInput.value.trim();  
 
            // 定义用户名的正则表达式规则:长度 6 - 12,由单词字符组成 
            const reg = /^\w{6,12}$/; 
 
            // 测试用户名是否符合规则 
            const flag = reg.test(username);  
 
            // 根据验证结果显示或隐藏错误信息 
            document.getElementById("username_err").style.display  = flag ? 'none' : ''; 
 
            return flag; 
        } 
 
        // 获取密码输入框 
        const passwordInput = document.getElementById("password");  
 
        // 为密码输入框绑定失去焦点事件,调用验证函数 
        passwordInput.onblur  = checkPassword; 
 
        // 验证密码是否符合规则 
        function checkPassword() { 
            // 获取用户输入的密码并去除首尾空格 
            const password = passwordInput.value.trim();  
 
            // 定义密码的正则表达式规则:长度 6 - 12,由单词字符组成 
            const reg = /^\w{6,12}$/; 
 
            // 测试密码是否符合规则 
            const flag = reg.test(password);  
 
            // 根据验证结果显示或隐藏错误信息 
            document.getElementById("password_err").style.display  = flag ? 'none' : ''; 
 
            return flag; 
        } 
 
        // 获取手机号输入框 
        const telInput = document.getElementById("tel");  
 
        // 为手机号输入框绑定失去焦点事件,调用验证函数 
        telInput.onblur  = checkTel; 
 
        // 验证手机号是否符合规则 
        function checkTel() { 
            // 获取用户输入的手机号并去除首尾空格 
            const tel = telInput.value.trim();  
 
            // 定义手机号的正则表达式规则:长度 11 位,以 1 开头,后面跟 10 位数字 
            const reg = /^[1]\d{10}$/; 
 
            // 测试手机号是否符合规则 
            const flag = reg.test(tel);  
 
            // 根据验证结果显示或隐藏错误信息 
            document.getElementById("tel_err").style.display  = flag ? 'none' : ''; 
 
            return flag; 
        } 
 
        // 获取表单对象 
        const regForm = document.getElementById("reg-form");  
 
        // 为表单绑定提交事件 
        regForm.onsubmit  = function () { 
            // 依次验证用户名、密码和手机号是否都符合要求 
            const flag = checkUsername() && checkPassword() && checkTel(); 
 
            return flag; 
        } 
    </script> 
</body> 

</html>