如何防止重复提交表单

在金融消费等敏感领域,重复提交表单将会导致费用翻倍.最常见的解决方案就是在提交一次之后禁用提交按钮(当然后端接口也要进行严密判断)。

1
2
3
4
5
6
7
form.addEventListener('submit',function(ev){
var target = ev.target
// 取得提交按钮
var submitBtn = target.elements['submitBtn'] // 通过name属性
// disable it
submitBtn.disabled = true
})

需要注意的是:不能通过onclick来实现,因为不同浏览器之间存在”时差”,换言之:onlicksubmit的触发顺序是不确定的.

html5为表单新增了autofocus属性,表单字段将自动得到焦点.

过滤输入

过滤字符

考虑这样一种需求:电话号码中不能包含非数字字符.因此我们需要监听keypress事件,并阻止其默认行为,极端情况下可以屏蔽所有的按键操作.

1
2
3
4
5
6
7
text.addEventListener('keypress',function(ev){
var target = ev.target
var charCode = ev.charCode
// 字符编码转字符串,保证不阻止基本键
if(!/\d/.test(String.fromCharCode(charCode)) && charCode > 9 && !ev.ctrlKey)
ev.preventDefault()
})

操作剪切板

提供以下的6个事件:

  • beforecopy
  • copy
  • beforecut
  • cut
  • beforepaste
  • paste

注意,通过beforeXXX可以在XXX事件之前向剪切板发送或者取得剪切板中的数据之前修改数据,取消beforeXXX方法并不会取消对剪切板的操作,只有取消copy,cut,paste事件才能阻止相应操作发生.

取得剪切板中的数据可以使用clipboardData对象,在IE中它是window的属性,而其他浏览器中它是对应event对象的属性.该对象有3个方法:setData(),getData()clearData().

自动切换焦点

例如我们常见的软件的激活码,当输入特定字符后光标会自动切换到下一个输入框,极大强化了用户体验.我们可以通过以下的方法来模拟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<input type="text" id="tel1" maxlength="3">
<input type="text" id="tel2" maxlength="3">
<input type="text" id="tel3" maxlength="4">
<script>
(function(){
function tabForward(ev){
var target = ev.target
if(target.value.length === target.maxLength){
var form = target.form
for(var i= 0,len = form.elements.length;i < len;i++){
if(form.elements[i] === target){
// 找到下一个表单字段,并获得焦点
if(form.elements[i+1]){
form.elements[i+1].focus()
}
return
}
}
}
}
var txt1 = document.getElementById('tel1')
var txt2 = document.getElementById('tel2')
var txt3 = document.getElementById('tel3')

txt1.addEventListener('keyup',tabForward)
txt2.addEventListener('keyup',tabForward)
txt3.addEventListener('keyup',tabForward)
}())
</script>

表单序列化

首先思考这样一个问题:浏览器怎样将数据发送给服务器?

  • 对表单字段的key和value进行url编码,使用&分隔
  • 不发送禁用的表单字段
  • 只发送勾选的的复选框和单选按钮
  • 不发送type为reset和button的按钮
  • 多选选择框中的每个选中的值单独一个条目
  • 在单击提交按钮提交表单的情况下,也会发送提交按钮;否则,不发送提交按钮
  • <select>元素的值,就是选中的<option>元素的value特性的值。如果<option>元素没有value特性,则是`

以下是序列化函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
function serialize(form){
var parts = [],
field = null,
i,
len,
j,
optLen,
option,
optValue;

for(i = 0,len = form.elements.length;i < len;i++){
field = form.elements[i]

switch(field.type){
case 'select-one':
case 'select-multiple':

if(field.name.length){
for(j = 0,optLen = field.options.length;j < optLen;j++){
option = field.options[j]
if(option.selected){
optValue = ''
if(option.hasAttribute){
optValue = (option.hasAttribute('value') ? option.value : option.text)
} else {
optValue = (option.attributes['value'.specified] ? option.value : option.text)
}
parts.push(encodeURICompenent(field.name) + '=' + encodeURIComponent(optValue))
}
}
}
break

case undefined: // 字段集
case 'file':
case 'submit':
case 'reset':
case 'button':
break

case 'radio':
case 'checkbox':
if(!field.checked)
break
default:
// 不包含没有名字的表单字段
if(field.name.length){
parts.push(encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value))
}
}
}
return parts.join('&')
}

富文本编辑器

WYSIWYG(what you see is what you get),所见即所得.本质是在页面中嵌入一个包含空html页面的iframe,通过设置designMode属性,这个空白html可以被编辑,而编辑对象则是该页面的<body>元素的html代码;另外的一种实现是将元素设置为contenteditable