☰
EasyUI登录页开发实战:从jQuery表单校验到AJAX会话保持
2026/10/14 10:48:36 网站建设 项目流程

简介:这是一套基于EasyUI开发的简单登录界面完整示例,适合前端入门者或需要快速搭建后台管理登录页的开发者参考。界面综合运用了EasyUI的布局、表单、按钮及验证组件,同时包含Java Servlet后端处理逻辑,可帮助理解前后端配合的完整流程。压缩包共332个文件,其中90个gif、58个png用于界面图标与提示图片,53个js和52个css构成脚本与样式核心,50个html则展示页面结构,另有json、xml、db等配置与数据文件,整体仅482KB,小巧便于按目录拆解学习。已有898人学习下载,适合边看边练,既能掌握EasyUI控件的基础用法,也能对照登录提交与响应的Java实现,提升Web交互开发能力。

1. EasyUI 简单登陆界面:为什么一个"老"框架的登录页到今天还有用

这个 EasyUI 简单登陆界面资源包,解决的是后台管理系统里最不起眼、但又绕不开的那扇门。很多从 Vue、React 入门的开发者看到 EasyUI 会下意识觉得过时,但真正去维护那些跑了好几年的后台项目时,打开页面第一眼看到的往往就是这套 jQuery 时代的登录界面:账号框、密码框、登录按钮,外加一段 AJAX 提交和校验逻辑。这个包的价值在于它把登录页最常见的组件和完整可运行的代码装进了一个压缩包,解压后打开 login.html 就能看到效果,不需要重装环境、不需要构建工具,浏览器直接跑。适合刚接手老系统、要快速改样式的新人,也适合做内部工具和课程设计、不想在登录页上浪费时间的开发者。

2. EasyUI 登录页的结构与选型逻辑:这套资源里到底装了什么

2.1 解压之后:登录页模板的典型文件构成

拿到压缩包的第一件事是解压并对照文件结构。不同人打包的资源在细节上有差异,但核心文件基本固定:一个 HTML 入口、jQuery 库、EasyUI 核心库、主题样式和图标样式。我按最常见的布局整理成了下表,方便你逐一比对。

文件作用要不要改
login.html登录页唯一入口,页面结构、表单和脚本都集中在这里主要改这个
jquery.min.jsjQuery 核心库,是 EasyUI 的运行基础一般不动
jquery.easyui.min.jsEasyUI 组件库,提供 validatebox、linkbutton 等组件一般不动
easyui/themes/default/easyui.css默认主题样式,决定整体配色和控件外观想换主题才动
easyui/themes/icon.css组件用到的图标样式一般不动

这里最需要注意的是加载顺序。EasyUI 本质上是 jQuery 的插件体系,所以 jQuery 必须先加载,紧接着才是 EasyUI 核心库,最后是样式文件。有人图省事把两个 script 标签顺序写反,结果页面打开后按钮没有任何 EasyUI 风格,控制台直接报$ is not defined,整个页面变成一堆裸控件。head 区域的标准写法如下。

<script src="easyui/jquery.min.js"></script> <script src="easyui/jquery.easyui.min.js"></script> <link rel="stylesheet" href="easyui/themes/default/easyui.css"> <link rel="stylesheet" href="easyui/themes/icon.css">

从这段标签能看出两个细节。第一,样式文件放后面对功能没影响,因为 CSS 加载不依赖脚本执行,但脚本之间顺序绝对不能颠倒。第二,如果资源包目录层级不同,比如 js 和 css 分开放,这里的相对路径要跟着调整,否则控制台会报 404。按下 F12 打开 Network 面板,能看到这三个文件按顺序加载,任何一个失败都会让登录页功能残缺。我拿到任何 EasyUI 资源包,第一步不是打开页面,而是先检查 script 标签的引用路径和顺序,这一步能省掉后面一个小时的排错时间。

2.2 为什么选 EasyUI 而不是自己写一套登录页

接手老系统改造时,最怕的不是功能复杂,而是技术栈不统一。如果整个后台都是 EasyUI 组件体系,新页面贸然引入 React 或 Vue,光样式冲突和重复引库就够折腾半天。登录页看似简单,但它是整个系统的门面,和后台保持同一套 UI 体系,视觉和交互上才能一致。所以选型逻辑首先不是"哪个框架新",而是"哪个框架和现状兼容"。

EasyUI 对后端开发者特别友好,这是它能在存量系统里长期存活的重要原因。表单、按钮、对话框、校验这些高频能力都封装成了现成组件,你不用自己拼一堆 CSS 和原生 JS,只需要通过class="easyui-validatebox"声明组件类型,再在>{ "success": true, "msg": "登录成功", "data": { "userId": 1001, "userName": "admin", "token": "a3f8c2e91b" } }

约定里success是前端判断的核心,msg是给用户看的提示文案,data里可以携带 userId、userName、token 等业务字段。有的团队把success换成code加message的组合,但思路一样:前端先判断业务状态,再决定走成功分支还是失败分支。理解了这条链路,再看资源包里的代码就不会觉得是一堆散标签,而是每一步都有明确职责。后面第三章节会按这个链路逐段拆解。

3. 把登录页拆开重装:从静态页面到可提交的登录流程

3.1 页面骨架:form 表单与居中布局的实现

先搭登录页的 HTML 骨架。这份完整代码是我按最常见做法整理的最小可运行版本,外层容器用绝对定位加负 margin 实现水平垂直居中,避免不同分辨率下登录框贴边或错位。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>后台管理系统登录</title> <link rel="stylesheet" href="easyui/themes/default/easyui.css"> <link rel="stylesheet" href="easyui/themes/icon.css"> <style> .login-wrap { position: absolute; left: 50%; top: 40%; width: 360px; margin-left: -180px; padding: 24px 32px; border: 1px solid #ddd; border-radius: 6px; background: #fff; } .login-wrap h2 { text-align: center; font-size: 18px; margin-bottom: 20px; } .login-wrap input { width: 100%; height: 36px; margin-bottom: 16px; box-sizing: border-box; } .login-wrap a { width: 100%; height: 38px; line-height: 38px; } </style> <script src="easyui/jquery.min.js"></script> <script src="easyui/jquery.easyui.min.js"></script> </head> <body> <div class="login-wrap"> <h2>后台管理系统登录</h2> <form id="loginForm" method="post"> <input id="username" name="username" class="easyui-validatebox" >// 写法一:在>$(function () { $('#loginBtn').click(function () { // 提交前先做统一校验,不通过直接终止 if (!$('#loginForm').form('validate')) { return; } // 拿到按钮对象并置灰,防止重复提交 var btn = $(this); btn.linkbutton('disable'); $.ajax({ url: 'login', type: 'POST', data: $('#loginForm').serialize(), dataType: 'json', success: function (result) { if (result.success) { // 登录成功:保存会话信息并跳转首页 sessionStorage.setItem('userId', result.data.userId); sessionStorage.setItem('userName', result.data.userName); window.location.href = 'index.html'; } else { // 后台业务校验不通过,弹出提示并恢复按钮 $.messager.alert('提示', result.msg, 'error'); btn.linkbutton('enable'); } }, error: function () { // 网络层错误统一处理 $.messager.alert('提示', '网络异常,请稍后重试', 'error'); btn.linkbutton('enable'); } }); }); });

逐段拆解。serialize()方法把表单里带 name 属性的字段拼成username=admin&password=123456这样的查询串,后台拿到后直接解析,不需要你手写取值代码。dataType: 'json'告诉 jQuery 期望返回 JSON,如果后台返回的不是合法 JSON,会直接走进 error 回调——联调时这个坑很常见,后台明明返回了数据,前端却提示"网络异常",多半是 content-type 没配对。

success 回调里先用result.success做分支。成功才保存 session 并跳转,失败则弹出 messager 窗口并重新启用按钮。这里把按钮置灰放在请求之前,是为了挡住用户重复点击;等请求结束再 enable,按钮状态和请求生命周期保持一致。如果你不希望失败后按钮马上恢复,也可以改成"连续失败三次再恢复",不过登录场景一般没必要。

关于 AJAX 参数的调整,有一点值得单独说。开发现场接口地址经常变化,如果前端直接把url写死成'login',后端加了个/api前缀就会 404。我一般会把接口地址统一收在一个变量里,方便联调时快速替换:

// 接口地址统一配置,联调时只改这里 var API = { login: 'api/login' }; // 请求时引用 url: API.login

这种写法不是 EasyUI 特有的,但在老的 jQuery 项目里很实用。后端接口文档改一次,你只需要动一处,不用满页面找url:一个个换。对刚入职要改老系统的新人来说,这个习惯能减少不少无效沟通。

3.4 会话保持:登录成功之后把凭证放哪

登录接口验证通过后,前端面临的第一个选择是:用户信息放 sessionStorage、localStorage 还是 cookie。这三种方式各有适用场景,不能只凭习惯选。

// 方式一:sessionStorage,关闭标签页即失效 sessionStorage.setItem('sessionId', result.data.token); // 方式二:localStorage,浏览器重启后仍在,适合"记住用户名" localStorage.setItem('rememberUser', result.data.userName); // 方式三:需要带着凭证调用其他接口时,统一加请求头 $.ajaxSetup({ headers: { 'Authorization': sessionStorage.getItem('sessionId') } });

三行代码对应三种诉求。sessionStorage 的典型用途是保存当前会话的 token,标签页一关登录态就没了,相对安全;localStorage 更适合存"记住用户名"这类非敏感信息,建议不要直接存密码;$.ajaxSetup则是给页面后续所有请求统一加上请求头,避免每个 AJAX 都写一遍 header。也有团队选择把 token 交给后端写进 HttpOnly cookie,前端完全不用管,安全性更高,但登录页代码里需要去掉手动 setItem 的步骤。

存储方式生命周期典型用途
sessionStorage标签页关闭即失效当前会话 token
localStorage手动清除才失效记住用户名、主题偏好
cookie按过期时间HttpOnly 会话标识

资源包里一般只到登录跳转为止,不会包含会话保持这段,但实际联调时大概率用得上。下一章我会把使用 EasyUI 登录页过程中最容易翻车的几个点串起来讲,每个都是我在真实项目里踩过的。

4. EasyUI 登录页常见问题与排查:五个让我翻过车的细节

4.1 登录框错位:换台电脑就变形

现象:在自己电脑上登录页看着很正常,分辨率稍一变,登录框要么整体偏左,要么按钮跑到输入框外面;在同事的 1366x768 笔记本上打开,甚至出现横向滚动条。

原因:早年很多模板直接用固定像素的表格布局,没有考虑窗口缩放;常见的是外层容器宽度写死、没有最小宽度兜底。另一种情况是 input 没有加box-sizing: border-box,padding 把输入框撑得比父容器还宽。

解决:把容器从表格布局改为绝对定位加 margin 居中,同时给输入框和按钮设置百分比宽度或box-sizing: border-box。代码层面最关键的是width: 100%加box-sizing: border-box配合,两者缺一不可。我现在看这类登录页,第一件事就是按 F12 把窗口拖到 1024 宽度以下看一眼,这个习惯替我挡掉了不少兼容性麻烦。

4.2 中文乱码:标题和提示全变成问号

现象:页面 title 是乱码,data-options 里的 missingMessage 显示成??????,登录按钮的文字也变成一堆问号。

原因:绝大多数情况是文件没有保存为 UTF-8 编码,或者 head 里的 charset 声明和实际文件编码不一致。用记事本或老版本编辑器改过 HTML 后,文件被另存为 ANSI,而 meta 里仍写charset="UTF-8",浏览器按 UTF-8 解码 ANSI 内容自然乱码。

解决:统一把所有文件改成 UTF-8 无 BOM 编码,并且确认 head 里第一行 meta 声明。这段排查同样适用于 JS 文件——JS 里的中文提示乱码,通常是 JS 文件本身编码不对。一个好习惯是改动代码前先看一眼编辑器右下角显示的编码格式,确认是 UTF-8 再动手;如果已经改坏了,用编辑器"以 UTF-8 重新打开"即可恢复。

4.3 validatebox 校验不生效:空表单也能提交

现象:输入框什么也不填,直接点登录按钮,页面没有红框提示,AJAX 请求照样发出去,后台收到一堆空参数。

原因:点击事件里少了form('validate')的判断,或者 validatebox 初始化失败。后者在引入多个 jQuery 版本时尤其常见:EasyUI 插件被后加载的高版本 jQuery 覆盖,validatebox 根本没注册成功,class 声明自然不会被解析。

解决:提交回调开头加判断if (!$('#loginForm').form('validate')) { return; },同时在控制台执行$('#username').validatebox({})验证组件是否存在。如果返回 undefined,回头检查脚本加载顺序和是否有重复引库。还有一个冷门原因是输入框没有name属性——validatebox 本身能工作,但serialize()序列化时带不上这个字段,后台收到的参数里就少了它。

4.4 登录接口 404:后端路由对不上

现象:点击登录按钮后 Network 面板里有一条红色 404 请求,后台接口文档里明明有这个地址,前端却一直进不了 success 回调。

原因:URL 写法和后端路由不匹配。常见的是拼写错误、缺少项目上下文路径、或者 POST 写成了 GET。后端如果配了访问前缀,比如/api/login,而前端写成login,自然找不到。另外页面部署在子目录时,以/开头的绝对路径会直接指到域名根目录,也会 404。

解决:先打开 Network 面板,点击请求行看完整 URL,再用 curl 或 Postman 单独测一下后端地址,确认接口本身通。无误后回头改前端代码里的url。路径尽量用相对当前页面计算,或者按照部署目录写基准路径。还有一个细节:联调时后端接口可能还在改,前端记得清一下浏览器缓存,避免旧的 JS 文件里还留着旧地址。

4.5 重复提交:快速点两下发出两条请求

现象:用户双击登录按钮,后台日志里出现两条相同账号的登录记录;第二次请求有时还会因为 token 刷新导致前一次会话失效。

原因:按钮点击后没有进入"处理中"状态,用户完全可以再次点击。linkbutton 默认点击一次执行一次 click 事件,双击就触发两次,后端如果没做幂等处理,就会产生两条重复记录。

解决:点击后立刻执行btn.linkbutton('disable'),等 success 或 error 回调里再重新 enable。为了兜底,我一般会再加一个请求锁:

var isLogging = false; $('#loginBtn').click(function () { if (isLogging) return; isLogging = true; var btn = $(this); btn.linkbutton('disable'); // 原有 ajax 逻辑 // 在 success 和 error 回调里重置 isLogging = false,并 btn.linkbutton('enable') });

两层防护能挡住极端场景:linkbutton('disable')让按钮变灰,视觉上提示用户别点了;isLogging则杜绝了回调还没返回、按钮还没被重新启用间隙里的重复点击。我早期做类似页面时没加锁,测试人员连点三下登录,后台连续收到三份请求,从那以后这个习惯再也没丢过。

5. 让登录页从"能跑"到"好用":三个低成本升级

5.1 记住用户名:localStorage 的一次写入与回填

很多后台系统只需要记住账号、不记住密码。做法是在登录成功回调里把用户名写进 localStorage,下次打开登录页时自动回填。涉及两处代码:一处是在成功分支存数据,另一处是在$(function(){})里读数据并给输入框赋值。

// 登录成功时保存 if ($('#rememberMe').is(':checked')) { localStorage.setItem('rememberUser', result.data.userName); } // 页面加载时回填 var savedName = localStorage.getItem('rememberUser'); if (savedName) { $('#username').val(savedName); }

简单几行,体验提升明显。注意别顺手把密码也存进去,明文密码进 localStorage 等于裸奔。真要"记住密码",必须配合后端做加密令牌,而不是在浏览器端存明文,这一点没有商量余地。

5.2 回车键也能触发登录

用户输完密码后习惯按回车。如果页面没有绑定回车事件,这个动作不会触发任何东西,用户会以为系统卡了。给整个表单加一个 keydown 监听即可。

$('#loginForm').on('keydown', function (e) { if (e.keyCode === 13) { $('#loginBtn').trigger('click'); } });

这里用trigger('click')而不是直接调用提交函数,好处是会自动经过按钮点击逻辑里的校验、置灰和锁判断,不会绕过流程。绑定在 form 上比绑定在 password 输入框上覆盖更全,用户焦点在用户名框时按回车同样有效。

5.3 交付前的自查清单

我在把登录页交付出去之前,总会按一份固定清单走一遍:第一,换 1024 和 1920 两种宽度看布局是否错位;第二,清掉浏览器缓存后刷新,确认 JS 和 CSS 加载顺序无误;第三,故意输错密码、再断网分别确认业务错误和网络错误提示;第四,打开 Network 面板,确认登录请求只发出一条、没有重复提交。这套流程做完,大部分坑已经被拦在前面。EasyUI 登录页虽然看着简单,但校验、请求、跳转、异常处理每一环都有它自己的脾气,希望这些踩坑记录能帮你在复现和改造时少走几段弯路,也希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询