FLEX表单验证带重置功能<WEB用户体验>

本文详细阐述了在富因特网应用程序中应用用户界面设计原则的重要性,包括预防错误、即时反馈、简化用户操作以及合理校验等关键原则。通过Flex应用程序的实例,展示了如何遵循这些原则来创建高效、用户友好的界面。

有用的校验方法必须最低限度的也要支持富因特网应用程序的用户界面设计原则。

1.防患于未然,而不是事后责备。
校验错误的表单不应该被用户提交。防止,不责骂原则的意思是,能够准确无误的放置用户犯错误,那么就应该那么做,而不是允许他们犯错误,而事后责备他们。

当做客户端校验时,明显的违反这一原则的情况是,当用户已经提交完整个表单以后,校验用户的输入数据。在Flex应用程序中,你可以创建一个行为,触发校验器,相应表单上提交按钮的单击事件。

2.马上给出反馈
用户操作控件时应该能够得到即时的反馈。当控件值变为有效时,用户应该收到正确的反馈。当控件值变为无效时应该得到错误的反馈。当用户离开控件时给出用户反馈,也非凡上一条原则。

当控件没有给出用户即时反馈,用户只有在离开控件时才能发现错误。要更正错误,用户需要返回控件,因此会花费更多的努力。(这个例子也违反了另一个相关的原则:考虑用户的操作)。更重要的,当用户编一个一个校验错误的输入框的值,用户不知道是否用户的改变会使控件值生效。用户需要离开控件才能知道结果,并且如果依然不合法则需要返回控件继续改变它。

默认的Flex校验器的行为监听valueCommit事件。这导致行为描述就像刚才的那样,只有当用户离开控件以后才能收到反馈。为了给出即时反馈,你必须手工指定触发校验响应change事件,而不是valueCommit事件。

前边的的连个例子展示了没有即时反馈的客户体验。

3.让用户工作
虽然给出即时提示是好事情,你的应用程序在一定程度上,还应该做到不中断用户工作流程。漂浮提示框不中断用户,通常是最好的玄色。只有当完全必要的时候,才能够使用完全中断用户操作的模式对话窗口。

4.验证有罪之前,都是清白的
只有用户与控件交互以后,用户在校验失败后应该给出警告。(换句话说,初始状态,和初始化控件时不应该运行校验并显示校验信息。类似的,重置表单应该移除所有校验错误信息。

连接:设计web应用程序用户界面更多的信息,请查看Aral Balken的著作《User Interface Design Principles for Web Applications》

 

有用的客户端校验的例子

下边的例子示例了在Flex3中创建校验的最佳实践。它遵循了上文所述的4个用户界面设计的原则。用户在验证有罪之前是清白的,初始的表单上没有校验错误信息,当表单被清除。用户马上可以收到信息当控件值变得可用(给出即时反馈)并且放置用户提交一个错误表单(放置,不是时候责备)。校验错误信息显示为漂浮提示框并且这样可以在不中断用户操作的情况下引导用户填写正确的信息。

  • 两个标志,formIsValid和formIsEmpty跟踪当前表单的状态。Submit按钮的enabled属性被绑定在 formIsValid标志,因此,放置用户提交无效的表单。类似的,绑定Clear form按钮的enabled属性到fromIsEmpty标志上,以便只有用户输入过信息之后此按钮才有效。
  • focussedFormControl属性持有最后一个发送change事件的引用(换句话说,是用户当前所在的控件)。 validate()帮助方法使用这个属性来指定只显示当前控件的校验错误消息。这很重要,可以防止没有与用户交互的组件的错误信息显示出来。
  • 当表单控件的值被改变时,validateForm()事件处理方法使用validate()帮助方法来校验所有的表单控件。只有当所有校验器校验成功,formIsValid标志的值被这是为true然后用户允许提交表单。
  • resetFocus()方法调用FocusManager的setFocus方法来将焦点放置于表单的第一个元素。当表单被第一次载入和后来的当表单被用户清空时,resetFocus()方法被调用。将焦点至于第一个控件,可以节省用户的点击次数,。

注意:由于浏览器处理Flash内容的限制,用户必须在Flash应用程序上点击一次才能将焦点移入到Web页面的flash程序中。

  • clearFormHandler方法清楚表单控件的值,并且也重置validator到恰当的状态。

例子

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
	xmlns:mx="http://www.adobe.com/2006/mxml" 
	viewSourceURL="src/ValidationUsable/index.html"
	width="500" height="250" 
	defaultButton="{submitButton}"
	creationComplete="creationCompleteHandler();"
	>
	<mx:Script>
		<![CDATA[
			import mx.validators.Validator;
			import mx.events.ValidationResultEvent;
			import mx.controls.Alert;
			//表单是否有效
			[Bindable]
			public var formIsValid:Boolean = false;
			//表单是否为空
			[Bindable]
			public var formIsEmpty:Boolean = true;
			
			//持有该目前集中控制的对象。
			private var focussedFormControl:DisplayObject;
			
			/**
			 * 验证表单方法
			 * */
			private function validateForm(event:Event):void 
			{                    
				//检查验证传递和返回一个布尔值相应。
				//保存引用当前集中表单控件
				//这样isValid()辅助方法可以只通知
				//当前集中形式控制和不影响
				//任何其他的表单控件。
				focussedFormControl = event.target as DisplayObject;  
				
				// 标记表单有效的开始                
				formIsValid = true;          
				
				// 检查表单是否为空
				formIsEmpty = (nameInput.text == "" && emailInput.text == ""
					&& phoneInput.text == "");
				
				//运行每个验证器反过来,使用isValid()
				//辅助方法和更新formIsValid的价值
				//因此。
				validate(nameValidator);                
				validate(phoneValidator);
				validate(emailValidator);
			}
			
			/**
			 * 验证方法
			 * */
			private function validate(validator:Validator):Boolean
			{                
				//得到验证对象
				var validatorSource:DisplayObject = validator.source as DisplayObject;
				
				//镇压事件如果当前控制被验证的不是
				//当前集中控制的形式。这阻止了用户
				//从接收视觉验证提示在其他表单控件。
				var suppressEvents:Boolean = (validatorSource != focussedFormControl);
				
				//执行验证。返回一个ValidationResultEvent。
				//传递null作为第一个参数使验证器
				//使用属性中定义的属性的标记
				// < mx:Validator >标记。
				var event:ValidationResultEvent = validator.validate(null, suppressEvents); 
				
				//检查验证传递和返回一个布尔值。
				var currentControlIsValid:Boolean = (event.type == ValidationResultEvent.VALID);
				
				// 修改验证标记
				formIsValid = formIsValid && currentControlIsValid;
				
				return currentControlIsValid;
			}
			
			/**
			*组件构件完成事件
			 * */
			private function creationCompleteHandler():void
			{
				// 初始化定焦点为第一个控件上
				resetFocus(); 
			}
			
			/**
			 * 表单提交
			 * */
			private function submitForm():void 
			{
				Alert.show("提交"); 
			}
			
			/**
			 *  清除验证信息 重置功能
			 * */
			private function clearFormHandler():void
			{
				// 清除所有的值
				nameInput.text = "";
				phoneInput.text = "";
				emailInput.text = "";
				
				// 清除错误信息
				nameInput.errorString = "";
				phoneInput.errorString = "";
				emailInput.errorString = "";
				
				// 标记为清空
				formIsEmpty = true;
				
				// 获取到焦点
				resetFocus();               
			}
			
			// 设置第一个控件获取到焦点
			private function resetFocus():void
			{
				focusManager.setFocus(nameInput);
			}
		]]>
	</mx:Script>
	
	<!-- 
	Validators 
	-->
	
	<!-- Name must be longer than 2 characters long -->
	<mx:StringValidator 
		id="nameValidator"
		source="{nameInput}" 
		property="text"
		minLength="2"
		/>
	
	<!-- Validate phone number -->
	<mx:PhoneNumberValidator 
		id="phoneValidator"
		source="{phoneInput}" property="text"
		/>
	
	<!-- Validate email -->
	<mx:EmailValidator
		id="emailValidator"
		source="{emailInput}" property="text"
		/>
	
	<!-- 
	User interface 
	-->
	<mx:Panel title="Phone number validator">        
		<mx:Form>
			<mx:FormItem label="Name:">
				<mx:TextInput 
					id="nameInput"
					change="validateForm(event);"
					/>
			</mx:FormItem>
			<mx:FormItem label="Phone: ">
				<mx:TextInput 
					id="phoneInput"
					change="validateForm(event);"
					/>
			</mx:FormItem>
			<mx:FormItem label="Email: ">
				<mx:TextInput 
					id="emailInput"
					change="validateForm(event);"
					/>
			</mx:FormItem>
		</mx:Form>
		<mx:ControlBar horizontalAlign="center">
			<mx:Button 
				id="submitButton"
				label="Submit" 
				enabled="{formIsValid}"
				/>
			<mx:Button 
				label="Clear form" 
				enabled="{!formIsEmpty}"
				click="clearFormHandler();"
				/>
		</mx:ControlBar>
	</mx:Panel>
	
</mx:Application>


 

@model List<UserManagementSystem.Web.Models.ApplicationUser> @{ ViewData["Title"] = "用户管理"; } <h2>👥 用户管理</h2> @if (TempData["Success"] != null) { <div class="alert alert-success">@TempData["Success"]</div> } @if (TempData["Error"] != null) { <div class="alert alert-danger">@TempData["Error"]</div> } <div class="mb-3 d-flex justify-content-between"> <a asp-action="CreateUser" class="btn btn-primary">➕ 添加用户</a> <form method="get" class="form-inline"> <input type="text" name="search" value="@ViewBag.Search" class="form-control me-1" placeholder="搜索用户名/邮箱/真实姓名/村ID" style="width: 250px;" /> <button type="submit" class="btn btn-outline-secondary">🔍 搜索</button> </form> </div> <table class="table table-striped table-hover"> <thead class="table-dark"> <tr> <th>用户名</th> <th>邮箱</th> <th>真实姓名</th> <th>所属村ID</th> <th>账户状态</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var user in Model) { <tr> <td>@user.UserName</td> <td>@user.Email</td> <td>@(string.IsNullOrEmpty(user.RealName) ? "-" : user.RealName)</td> <td>@user.CmbId</td> <td> @if (user.IsActive) { <span class="badge bg-success">启用</span> } else { <span class="badge bg-secondary">禁用</span> } </td> <td> <a asp-action="EditUser" asp-route-id="@user.Id" class="btn btn-sm btn-info" title="编辑用户信息"> <i class="bi bi-pencil"></i> 编辑 </a> <a asp-action="ResetPassword" asp-route-id="@user.Id" onclick="return confirm('确定要为用户 @user.UserName 重置密码吗?');" class="btn btn-warning btn-sm" title="重置用户密码"> <i class="bi bi-key"></i> 重置密码 </a> @if (user.Email != "admin@example.com") { <form asp-action="DeleteUser" method="post" style="display:inline;" onsubmit="return confirm('确定要删除用户 @user.Email 吗?此操作不可恢复!');"> <input type="hidden" name="id" value="@user.Id" /> <button type="submit" class="btn btn-sm btn-danger" title="删除用户"> <i class="bi bi-trash"></i> 删除 </button> </form> } else { <small class="text-muted">(系统账户)</small> } </td> </tr> } </tbody> </table> <!-- 分页 --> <nav aria-label="用户分页" class="mt-4"> <ul class="pagination justify-content-center"> @for (int i = 1; i <= ViewBag.TotalPages; i++) { <li class="@(i == ViewBag.CurrentPage ? "page-item active" : "page-item")"> <a class="page-link" asp-action="Users" asp-route-search="@ViewBag.Search" asp-route-page="@i" asp-route-pageSize="@ViewBag.PageSize"> @i </a> </li> } </ul> </nav> <!-- 添加分页大小选择 --> <div class="d-flex justify-content-end mt-3"> <div class="btn-group" role="group"> <a asp-action="Users" asp-route-search="@ViewBag.Search" asp-route-page="1" asp-route-pageSize="10" class="btn @(ViewBag.PageSize == 10 ? "btn-primary" : "btn-outline-primary")">10条/页</a> <a asp-action="Users" asp-route-search="@ViewBag.Search" asp-route-page="1" asp-route-pageSize="20" class="btn @(ViewBag.PageSize == 20 ? "btn-primary" : "btn-outline-primary")">20条/页</a> <a asp-action="Users" asp-route-search="@ViewBag.Search" asp-route-page="1" asp-route-pageSize="50" class="btn @(ViewBag.PageSize == 50 ? "btn-primary" : "btn-outline-primary")">50条/页</a> </div> </div>这个页面点击增加用户按钮后 An unhandled exception occurred while processing the request. InvalidOperationException: The view 'CreateUser' was not found. The following locations were searched: /Views/Admin/CreateUser.cshtml /Views/Shared/CreateUser.cshtml /Pages/Shared/CreateUser.cshtml Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable<string> originalLocations)
10-05
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String msg = request.getParameter("msg"); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"><title>登录 - 宿舍器材管理系统</title> <style> html,body{height:100%;margin:0;font-family:"微软雅黑";background:#f2f2f2;} .box{width:320px;background:#fff;border-radius:6px;padding:30px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 8px #ccc;} h3{text-align:center;margin-top:0;} .msg{color:red;text-align:center;margin-bottom:10px;} input[type=text],input[type=password]{width:100%;padding:8px;margin:6px 0;box-sizing:border-box;} input[type=submit]{width:100%;padding:8px;margin-top:10px;} .bottom-row{display:flex;justify-content:space-between;margin-top:8px;font-size:14px;} a{color:#007BFF;text-decoration:none;}a:hover{text-decoration:underline;} </style> </head> <body> <div class="box"> <h3>宿舍器材管理系统</h3> <% if(msg!=null){ %><div class="msg"><%=msg%></div><%} %> <form action="login" method="post"> <input type="text" name="account" placeholder="账号" required> <input type="password" name="password" placeholder="密码" required> <input type="submit" value="登录"> </form> <div class="bottom-row"> <a href="forgot.jsp">忘记密码</a> <a href="register.jsp">注册</a> </div> </div> </body> </html><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String msg = request.getParameter("msg"); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"><title>重置密码 - 宿舍器材管理系统</title> <style> html,body{height:100%;margin:0;font-family:"微软雅黑";background:#f2f2f2;} .box{width:320px;background:#fff;border-radius:6px;padding:30px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 8px #ccc;} h3{text-align:center;margin-top:0;} .msg{color:red;text-align:center;margin-bottom:10px;} input[type=text],input[type=password]{width:100%;padding:8px;margin:6px 0;box-sizing:border-box;} input[type=submit]{width:100%;padding:8px;margin-top:10px;} .center{margin-top:15px;text-align:center;font-size:14px;} a{color:#007BFF;text-decoration:none;}a:hover{text-decoration:underline;} </style> </head> <body> <div class="box"> <h3>重置密码</h3> <% if(msg!=null){ %><div class="msg"><%=msg%></div><%} %> <form action="forgot" method="post"> <input type="text" name="account" placeholder="账号" required> <input type="password" name="newpassword" placeholder="新密码" required> <input type="submit" value="重置密码"> </form> <div class="center"><a href="login.jsp">← 返回登录</a></div> </div> </body> </html><%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String msg = request.getParameter("msg"); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"><title>注册 - 宿舍器材管理系统</title> <style> html,body{height:100%;margin:0;font-family:"微软雅黑";background:#f2f2f2;} .box{width:320px;background:#fff;border-radius:6px;padding:30px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 8px #ccc;} h3{text-align:center;margin-top:0;} .msg{color:red;text-align:center;margin-bottom:10px;} input[type=text],input[type=password]{width:100%;padding:8px;margin:6px 0;box-sizing:border-box;} input[type=submit]{width:100%;padding:8px;margin-top:10px;} .center{margin-top:15px;text-align:center;font-size:14px;} a{color:#007BFF;text-decoration:none;}a:hover{text-decoration:underline;} </style> </head> <body> <div class="box"> <h3>用户注册</h3> <% if(msg!=null){ %><div class="msg"><%=msg%></div><%} %> <form action="register" method="post"> <input type="text" name="account" placeholder="新账号" required> <input type="password" name="password" placeholder="新密码" required> <input type="submit" value="注册"> </form> <div class="center"><a href="login.jsp">← 返回登录</a></div> </div> </body> </html>给我将这三个代码相互连通
最新发布
12-07
<script setup lang="ts"> import { ref, onMounted } from 'vue' /* 导入部门类型 */ /* 导入部门类型 */ import type { DeptModelArray } from '@/api/model/model' import { addApi, queryAllApi } from '@/api/api' import { ElMessage } from 'element-plus' /* 表格数据 ref<指定的类型> 指定的类型:可以通过interface定义出来 */ const tableData = ref<DeptModelArray>([]) /* mock云端假数据:前端测试的时候,后端还没写好,就可以先用mock造些假数据 */ /* 在页面启动时候通过钩子函数获取数据,渲染到前端页面 */ const deptSearch = async () => { const result = await queryAllApi() tableData.value = result.data } onMounted(() => { deptSearch() }) const dialogFormVisible = ref(false) const addDept = () => { dialogFormVisible.value = true //当添加部门数据时候,就清除上次的记录 form.value = { name: '' } } const form = ref({ name: '', }) const submitDept = async () => { const result = await addApi(form.value) dialogFormVisible.value = false if (result.code == 1) { ElMessage.success('部门添加成功') deptSearch() } else { ElMessage.error(result.msg) } } </script> <template> <h1>部门管理</h1> <el-button type="primary"> <el-icon><Search /></el-icon> 搜索 </el-button> <el-button type="success" @click="addDept"> <el-icon><plus /></el-icon>新增 </el-button> <el-button type="danger"> <el-icon><delete /></el-icon>批量删除 </el-button> <br /><br /> <el-table :data="tableData" border stripe> <el-table-column type="selection" width="45" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column prop="name" label="部门名称" min-width="100" /> <el-table-column prop="createTime" label="创建时间" min-width="160" align="center" /> <el-table-column prop="updateTime" label="最后修改" min-width="160" align="center" /> <el-table-column label="操作" align="center" fixed="right"> <template #default=""> <div class="action-buttons"> <el-button size="small" type="primary"> <el-icon><edit /></el-icon>编辑 </el-button> <el-button size="small" type="danger"> <el-icon><delete /></el-icon>删除 </el-button> </div> </template> </el-table-column> </el-table> <!-- 内嵌在对话框中的表单提交数据 --> <el-dialog v-model="dialogFormVisible" title="添加部门" width="500"> <el-form :model="form"> <el-form-item label="部门名称"> <el-input v-model="form.name" autocomplete="off" /> </el-form-item> </el-form> <template #footer> <div class="dialog-footer"> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="submitDept"> 添加 </el-button> </div> </template> </el-dialog> </template> <style scoped></style> 我的项目是vue3+element-plus构建的,帮我完善剩下的功能,美化样式
07-19
// /Profiles/MappingProfile.cs using UserManagementSystem.Web.Models.ViewModels; // 添加这行! using AutoMapper; using UserManagementSystem.Web.Models; namespace UserManagementSystem.Web.Profiles { public class MappingProfile : Profile { public MappingProfile() { // Cmb 实体 ↔ ViewModel 映射 CreateMap<Cmb, CmbListViewModel>(); CreateMap<Cmb, CmbEditViewModel>(); CreateMap<CmbEditViewModel, Cmb>(); // 其他映射... // CreateMap<ApplicationUser, UserViewModel>(); } } } using System.ComponentModel.DataAnnotations; namespace UserManagementSystem.Web.Models { /// <summary> /// 表示个行政村(村级单位) /// </summary> public class Cmb { [Key] public int Id { get; set; } [Required] [StringLength(50)] [Display(Name = "村名")] public string Name { get; set; } = null!; [Display(Name = "排序号")] public int SortOrder { get; set; } = 0; // 默认为0,值越小越靠前 // 可选:关联多个用户 public ICollection<ApplicationUser> Users { get; set; } = new List<ApplicationUser>(); } } // Extensions/DictionaryExtensions.cs using System.Collections.Generic; namespace UserManagementSystem.Web.Extensions { public static class DictionaryExtensions { /// <summary> /// 安全地从字典中获取值,如果键不存在或字典为 null,则返回类型的默认值。 /// </summary> /// <typeparam name="TKey">键类型</typeparam> /// <typeparam name="TValue">值类型</typeparam> /// <param name="dict">字典</param> /// <param name="key">要查找的键</param> /// <returns>对应的值或默认值</returns> public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) { return dict?.ContainsKey(key) == true ? dict[key] : default!; } } } 下面要开发Cmb信息管理功能
10-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萧三皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值