打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
DOM编程艺术(表单操作)
1、表单元素
一、编写表单的步骤:
1、构建表单----------------》2、服务器处理(主要是提供负责接收数据的接口,用来处理数据的存储等信息)------------》3、配置表单
示例:
披萨预定表单:
<form action=''>
<p><label>姓名:<input></label></p><!--用label标签来做元素的关联-->
<p><label>电话:<input type='tel'></label></p>
<p><label>邮箱:<input type='email'></label></p>
<fieldset>
<legend> 披萨大小 </legend>
<label><input type='radio' name='size'> 小 </label>
<label><input type='radio' name='size'> 中 </label>
<label><input type='radio' name='size'> 大 </label>
</fieldset>
<fieldset>
<legend> 披萨配料 </legend>
<label><input type='checkbox'> 熏肉 </label>
<label><input type='checkbox'> 奶酪 </label>
<label><input type='checkbox'> 洋葱 </label>
<label><input type='checkbox'> 蘑菇 </label>
</fieldset>
<p><label>配送时间:<input type='time' min='11:00' max='21:00' step='900'></label></p>
<p><button>提交订单</button></p>
</form>
配置表单:
<form method='post' action='https://pizza.example.com/order' enctype='application/x-www-form-urlencoded'>
<!--action属性配置接收数据的地址,enctype指定编码方式-->
<p><label>姓名:<input name='custname'></label></p>
<p><label>电话:<input type='tel' name='custtel'></label></p>
<p><label>邮箱:<input type='email' name='custemail'></label></p>
<fieldset>
<legend> 披萨大小 </legend>
<label><input type='radio' name='size' value='small'> 小 </label>
<label><input type='radio' name='size' value='medium'> 中 </label>
<label><input type='radio' name='size' value='large'> 大 </label>
</fieldset>
<fieldset>
<legend> 披萨配料 </legend>
<label><input type='checkbox' name='topping' value='bacon'> 熏肉 </label>
<label><input type='checkbox' name='topping' value='cheese'> 奶酪 </label>
<label><input type='checkbox' name='topping' value='onion'> 洋葱 </label>
<label><input type='checkbox' name='topping' value='mushroom'> 蘑菇 </label>
</fieldset>
<p><label>配送时间:<input type='time' name='delivery' min='11:00' max='21:00' step='900'></label></p>
<p><button>提交订单</button></p>
</form>
二、表单元素
1、form标签:
name属性:主要用于之后的API:var pizzaForm = document.forms.pizza;
autocomplete属性:属性值有on / off ,当值为on时,鼠标焦点到“姓名”的输入框中时,下面会出现之前输入过的值以备候选,候选值也会根据输入情况更改;当值为off时,也出现提示,就与浏览器的设置有关了。
elements:包含:①该表单子孙表单控件(除图片按钮(<input type='image'>))(表单控件有 button、fieldset、input、keygen、object、output、select、textarea)
②归属于该表单的表单控件(除图片按钮),示例看下面的代码:(动态节点集合)
<form id='f'>
<p><label><input name='a'></label></p><!--符合①-->
<p><select name='b'><option>1</option></select></p><!--符合①-->
</form>
<p><label><input name='c'></label></p><!--不符合-->
<p><label><input name='d' form='f'></label></p><!--符合②-->
length:elements.length
2、获取form表单中的表单控件:
<form name='test'>
<input name='a' />
<input name='b' />
</form>
testForm.elements[0];
testForm.elements['a'];
testForm[0]; //form[index]
testForm['a']; //form[name]
*form[name]:
---------------------返回id或name为指定名称的表单控件(除图片按钮)
---------------------如果结果为空、则返回id为指定名称的img元素
---------------------如果有多个同名元素,则返回这些元素的动态节点集合
---------------------一旦用指定名称取过该元素,则不管该元素的id或者name怎么变化,只要节点还在页面上均可使用原名称获取该元素:
<form name='test'>
<input name='a' />
</form>
testForm['a'];
testForm.elements['a'];
testForm['a'].name = 'b';
testForm['a'];//<input name='b' />
testForm.elements['a'];//null
3、接口:
-----reset()
可重置元素:input、keygen、output、select、textarea
触发表单reset事件,阻止该事件的默认行为可取消重置
元素重置时不再触发元素上的change和input事件
示例:有一个文件选择器,已经选择了一个文件,现在我们想要把这个选择的文件删除:
<form name='file'>
<input name='image' type='file' />
</form>
<script>
fileForm['image'].value = ''; //根据浏览器的安全限制,这样做是无法删除已选中文件的
fileForm.reset();
</script>
-----submit()
-----checkValidity()
4、label标签
<label for='txtId' form='formId'></label>
主要通过for属性关联到相关的表单控件上
①、htmlFor
-------------------关联表单控件激活行为,也就是说关联之后,点击label的行为与表单控件的行为保持一致
-------------------可关联元素:button、input(除hidden外)、keygen、meter、output、progress、select、textarea
<form class='f-hidden'>
<input id='file' name='image' type='file'><!--0*0尺寸不可见-->
</form>
<label for='file' class='m-upload'>选择图片</label><!--上传按钮效果,这里最重要的就是将for属性指到input id为file,这里点击label就有与点击input标签选择文件行为相同的操作-->
②control
---------------------如果指定了for属性,则为该for属性对应ID的可关联元素
---------------------如果没有指定for属性,则为第一个子孙可关联元素
<label for='txtId'>文字<input name='desc'></label>
<span id='txtId'>only for test content here</span>
在上面代码中:a、指定了for属性
b、for属性对应ID的元素span为非可关联元素
c、label.control——>null
③form
----------------------关联归属表单
----------------------可关联元素:button,fieldset,input,keygen,label,object,output,select,textarea
----------------------只读属性,不可在程序中修改
label.setAttribute('form','newFormId');
5、input标签
①type
--------------------控件外观
--------------------数据类型
--------------------默认为text
示例:本地图片预览:
<input type='file' accept='image/*' multiple>
multiple表示可以多选,accept支持的属性值:audio/*、video/*、image/*、不带“;”的MIME type、以“.”开始的文件后缀名。
file.addEventListener('change', function(event){
var files = Array.prototype.slice.call(event.target.files,0);
files.forEach(function(item){
<strong>file2dataurl</strong>(item,function(url){
var image = new Image();
parent.appendChild(image);
image.src = url;
});
});
});
file2dataurl接口没有实现,思考。
6、select标签
<select name='course'>
<option>课程选择</option>
<optgroup label='1. DOM基础'>
<option value='1.1'>1.1 文档树</option>
<option value='1.2'>1.2 节点操作</option>
<option value='1.3'>1.3 元素遍历</option>
<option value='1.4'>1.4 样式操作</option>
<option value='1.5'>1.5 属性操作</option>
<option value='1.6'>1.6 表单操作</option>
</optgroup>
<optgroup label='2. 事件模型'>
<option value='2.1'>2.1 事件类型</option>
<option value='2.2'>2.2 事件模型</option>
<option value='2.3'>2.3 事件应用</option>
</optgroup>
</select>
①select属性和接口:
select:name、value、multiple、options、selectedOptions、selectedIndex、add(element[,before])、remove([index])
optgroup:disabled 、label(对相关性较大的做分组,disabled表示当前分组里的都是不可选的)
option:disabled、label、value、text、index、selected、defaultSelected
*创建选项:
------document.createElement
------new Option([text[,value[,defaultSelected[,selected]]]])
这两个方式的效果是一样的。
new Option('1.2 节点操作','1.2');
//两者等价
var option = document.createElement('option');
option.value = '1.2';
option.textContent = '1.2 节点操作';
生成了:<option value='1.2'>1.2 节点操作</option>
*添加选项:
------insertAdjacentElement
------select.add
//需插入的节点
var option = new Option('1.0 概述','1.0');
//opt11为参照点
opt11.insertAdjacentElement(option,'beforeBegin');
select.add(option,opt11);
*删除选项
------removeChild
------select.remove
opt12.parentNode.removeChild(opt12);
//2为待删除节点的索引值
select.remove(2);
②示例:级联下拉选择器
案例描述:两个select选择器,后一个选择器根据前一个选择的所选的内容发生改变:
涉及到的知识点:onchange、remove、add
<form name='course'>
<select name='chapter'>
<option>请选择章目录</option>
</select>
<select name='section'>
<option>请选择节目录</option>
</select>
</form>
接下来对章节的数据内容进行定义:
var chapters = [
{text:'1. DOM基础',value:'1'},
{text:'2. 事件模型',value:'2'}
];
var sections = {
1:[
{text:'1.1 文档树',value:'1.1'},
{text:'1.2 节点操作',value:'1.2'},
{text:'1.3 元素遍历',value:'1.3'},
{text:'1.4 样式操作',value:'1.4'},
{text:'1.5 属性操作',value:'1.5'},
{text:'1.6 表单操作',value:'1.6'}
],
2:[
{text:'2.1 事件类型',value:'2.1'},
{text:'2.2 事件模型',value:'2.2'},
{text:'2.3 事件应用',value:'2.3'}
]
};
提取通用的接口:
//用选定的数据列表填充选择器
function fillSelect(select,list){
for(var i=select.length-1; i>0; i --){
select.remove(i);
}
list.forEach(function(data){
var option = new Option(data.text,data.value);
select.add(option);
});
}
//对首级的选择器做填充
fillSelect(chapterSelect,chapters);
//章的选择器会导致节的选择器的变化
chapterSelect.addEventListener('change', function(event){
var value = event.target.value,
list = sections[value] || [];
fillSelect(sectionSelect,list);
});
7、textarea
①属性和接口:
name、value、select()(对内容全选之后就会触发这个接口)、selectionStart、selectionEnd、selectionDirection(用来控制shift+方向键的行为,当值为forward时,改变的是selectionEnd,值为backward时,改变的是selectionStart)、setSelectionRange(start,end[,direction])、setRangeText(replacement[,start,end[,mode]])
②@输入提示:
描述:比如QQ聊天时,对话框中输入@就会出现好友列表,可以选择其中的一个值填充到@后面,之后再输入其他文本。
涉及到的知识点:oninput、selectionStart、setRangeText
textarea.addEventListener(
'input',function(event){
var target = event.target,
cursor = target.selectionStart;
if(target.value.charAt(cursor - 1) === '@'){
doShowAtList(function(name){
var end = cursor+name.length;
target.setRangeText(name,cursor,end,'end');
});
}
}
);
2、表单验证
<form method='post' action='https://pizza.example.com/order' enctype='application/x-www-form-urlencoded'>
<!--action属性配置接收数据的地址,enctype指定编码方式-->
<p><label>姓名:<input name='custname' required></label></p>
<p><label>电话:<input type='tel' name='custtel' required></label></p>
<p><label>邮箱:<input type='email' name='custemail'></label></p>
<fieldset>
<legend> 披萨大小 </legend>
<label><input type='radio' name='size' value='small' required> 小 </label>
<label><input type='radio' name='size' value='medium' required> 中 </label>
<label><input type='radio' name='size' value='large' required> 大 </label>
</fieldset>
<fieldset>
<legend> 披萨配料 </legend>
<label><input type='checkbox' name='topping' value='bacon'> 熏肉 </label>
<label><input type='checkbox' name='topping' value='cheese'> 奶酪 </label>
<label><input type='checkbox' name='topping' value='onion'> 洋葱 </label>
<label><input type='checkbox' name='topping' value='mushroom'> 蘑菇 </label>
</fieldset>
<p><label>配送时间:<input type='time' name='delivery' min='11:00' max='21:00' step='900'></label></p>
<p><button>提交订单</button></p>
</form>
在必须要填写的表单标签中添加“required”属性,当用户没有填写完整时点击提交按钮就会马上返回提示信息。
一、验证:
1、验证元素:
---------可验证元素:button、input、select、textarea
---------以下情况不做验证:
①input && type = {hidden、reset、button}
②button && type = {reset、button}
③input / textarea && readonly
④作为datalist的子孙节点
⑤disabled
2、验证涉及到的属性或接口:
element:willValidate(判断表单提交时元素是否会被验证)、checkValidity()(用来验证元素,通过的话就会返回true,否则会触发validate事件)、validity、validationMessage(显示验证异常信息)、setCustomValidity(message)
①validity:存储了验证过程中可能出现的错误验证信息
②自定义异常:
-------oninvalid事件
-------setCustomValidity接口
a、将必填字段的提示信息自定义设置,默认为“请填写此字段。”,改为“请输入姓名!”
<form action='./api' method='post'>
<p><label>姓名:<input name='username' required /></label></p>
<p><button>submit</button></p>
</form>
input.addEventListener('invalid', function(event){
var target = event.target;
//如果是没用输入的话,就自定义异常信息
if(target.validity.valueMissing){
target.setCustomValidity('请输入姓名!');
}
});
③禁止验证:
描述案例:当一个input的type为number,而作用是输入电话号码,其中电话号码带有“-”,提交时就会显示验证错误信息“请输入一个数字”。(这种情况下设置type可能是为了唤起特定的键盘,这里就是数字键盘)
<form action='./api' method='post' novalidate>
<label>电话:<input type='number' name='tel' /></label>
<button>submit</button>
</form>
3、表单提交
一、隐式提交:
-------如:聚焦在输入框时按回车提交表单
-------需满足以下任一条件:
①表单有非禁用的提交按钮
②没有提交按钮时,不超过一个类型为text、search、url、email、password、date、time、number的input元素
1、提交过程:
①根据表单enctype指定的值构建要提交的数据结构
②使用method指定的方式发送数据到action指定的目标
1.1、构建提交数据(浏览器):从可提交元素中提取数据组装成指定的数据结构的过程。
可提交元素:button、input、keygen、object、select、textarea
1.2、编码方式(enctype)
可指定为以下三种方式之一:①application/x-www-form-urlencoded【默认】
②multipart/form-data
③text/plain  (一般文件上传使用这种方式)
以上三种编码方式分别使用method='post'提交数据:
<form action='./api' method='post'>
<input name='a' />
<input name='b' />
<input name='c' />
<button>submit</button>
</form>
enctype Content-Type数据格式组织形式
①①使用&分割的键值对
②②用回车换行分割的键值对
③③字节流
特殊案例:
-------name='isindex' && type='text'
*编码方式为application/x-www-form-urlencoded
*作为表单的第一个提交元素
*提交时只发送value值,不包含name
<form action='./api' method='post'>
<p><input name='isindex' /></p>
<p><input name='a' /></p>
<p><button>submit</button></p>
</form>
提交111111、22222,则之后看到提交的数据为:111111&a=22222
-------name='_charset_' && type='hidden'
*没有设置value值
*提交时value自动用当前提交的字符集填充
<form action='./api' method='post'>
<input type='hidden' name='_charset_' />
<p><input name='a' /></p>
<p><button>submit</button></p>
</form>
提交111111,而_charset_的值就会用当前数据的编码字符集来填充,则提交的数据为:_charset_=UTF-8&a=111111
2、submit() 提交
在表单提交中的一个重要接口就是submit(),除了用提交按钮来提交数据之外,我们还可以调用form上的submit()接口来提交表单。
①onsubmit——不管用什么方式提交表单都会触发onsubmit事件。
——表单提交事件
——在这个事件触发的时候我们可以做一些提交之前的数据验证
——如果这个验证没有通过,可以阻止事件的默认行为来取消表单提交。
form.addEventListener('submit', function(event){
var notValid = false;
var elements = event.target.elements;
//TODO 处理自定义的验证规则
if(notValid){
event.preventDefault();
}
});
示例:无刷新表单提交
常用的可能是ajax,但这里用另外一种方式:
涉及到的知识点:form、target、iframe
使用iframe做中间代理,结合表单的target。
说明:指定一个iframe的name,将form的target指向iframe的name,当form表单的数据提交到服务器上,服务器返回的结果就会到iframe中,然后就只需要将iframe中的结果提交到页面上就可以了。
<iframe name='targetFrame' class='f-hidden'></iframe>
<form action='./api' method='post' target='targetFrame'>
<p><input name='a'></p>
<p><input name='b' /></p>
<p><button>submit</button></p>
</form>
4、表单应用
当重新输入时,错误信息就会消失。
一、登录接口:
——请求地址:/api/login
——请求参数:
*telephone     手机号码
*password     密码,MD5加密
——返回结果:
*code       请求状态,200表示成功
*result      请求结果数据
登录表单:
<form action='/api/login' class='m-form' name='loginForm' target='result' autocomplete='off'>
<legend>手机号码登录</legend>
<fieldset>
<div class='msg' id='message'></div>
<div>
<label for='telephone'>手机号:</label>
<input id='telephone' name='telephone' class='u-txt' type='tel' maxlength='11' required pattern='^0?(13[0-9]|15[012356789]|18[0236789]|14[57])[0-9]{8}$' /><br/>
<span class='tip'>11位数字手机号码</span>
</div>
<div>
<label for='password'>密 码:</label>
<input id='password' name='password' type='password' class='u-txt' /><br/>
<span class='tip'>至少6位,同时包含数字和字母</span>
</div>
<div><button name='loginBtn'>登 录</button></div>
</fieldset>
</form>
var form = document.forms.loginForm;//登录表单的引用
var nmsg = document.getElementById('message');//信息提示节点的引用
/*控制提示消息的样式*/
.m-form .j-err{display:block;color:#FF0000;}
.m-form .j-suc{display:block;color:#158226;}
/*验证出错时输入框的效果*/
.m-form .j-error{border-color:#f00;background-color: #FFE7E7;}
/*标示按钮的禁用状态,用在登录按钮上*/
.m-form .j-disabled{cursor:default;background-color:#ddd;}
①通用方法:
//在信息提示节点上设置提示信息
function showMessage(clazz,msg){
if(!clazz){
nmsg.innerHTML = '';
nmsg.classList.remove('j-suc');
nmsg.classList.remove('j-err');
}else{
nmsg.innerHTML = msg;
nmsg.classList.add(clazz);
}
}
//输入验证失败的逻辑
function invalidInput(node,msg){
showMessage('j-err',msg);
node.classList.add('j-error');
node.focus();
}
//当用户有输入时,清除提示信息
function clearInvalid(node){
showMessage();
node.classList.remove('j-error');
}
//提交表单以后,服务器没有返回结果的这段时间,禁用登录按钮,防止用户重复提交
function disableSubmit(disabled){
form.loginBtn.disabled = !!disabled;
var method = !disabled?'remove':'add';
form.loginBtn.classList[method]('j-disabled');
}
②验证手机号:
//验证手机号(使用验证逻辑)
form.telephone.addEventListener('invalid', function(event){
event.preventDefault();
invalidInput(form.telephone,'请输入正确的手机号码');
});
③验证密码:
//验证密码,注意:验证时机是提交表单的时候,不是点击提交按钮的时候。原因:用户提交表单不一定是要点击提交按钮,还可以隐式提交
form.addEventListener('submit', function(event){
//密码验证
var input = form.password,
pswd = input.value,
emsg = '';
if(pswd.length<6){
emsg = '密码长度必须大于6位';
}else if(!/\d/.test(pswd)||!/[a-z]/i.test(pswd)){
emsg = '密码必须包含数字和字母';
}
//密码验证不通过
if(!!emsg){
event.preventDefault();
invalidInput(input,emsg);
return;
}
//TODO 提交数据
});
④表单提交:
//表单提交
form.addEventListener('submit', function(event){
//TODO 密码验证
input.value = md5(pswd);
//禁用提交按钮
disableSubmit(true);
});
⑤状态恢复:
//验证失败之后的状态恢复
form.addEventListener('input', function(event){
//还原错误状态
clearInvalid(event.target);
//还原登录按钮状态
disableSubmit(false);
});
案例介绍:利用iframe无刷新提交
<iframe name='result' id='result' style='display:none;'></iframe>
<form target='result' action='/api/login' class='m-form' name='loginForm'>
</form>
//从iframe中取出服务器返回结果并做处理
var frame = document.getElementById('result');
frame.addEventListener('load', function(event){
try{
var result = JSON.parse(frame.contentWindow.document.body.textContent);
//还原登录按钮状态
disableSubmit(false);
//识别登录结果
if(result.code === 200){
showMessage('j-suc','登录成功!');
form.reset();
}
}catch(ex){
//ignore
}
});
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
3、Form 表 单
jQuery选择器总结
WEB前端第五课——HTML表单
语义化——表单 - ajax,css,js,javascript,actionscript...
第五章 表单的制作
WEB前端——body内常用标签(form标签)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服