资讯专栏INFORMATION COLUMN

JS学习笔记(第14章)(表单脚本)

BlackHole1 / 1709人阅读

摘要:布尔值,表示当前字段是否被禁用。指向当前字段所属表单的指针只读。文本框脚本在中,有两种方式来表现文本框一种是使用元素的单行文本框,另一种是使用的多行文本框。然后,我们把这个函数指定为每个文本框的事件处理程序。

本章知识架构

var EventUtil = {
    //添加事件处理程序
    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    //检测按键button属性
    getButton: function(event){
        if (document.implementation.hasFeature("MouseEvents", "2.0")){
            return event.button;
        } else {
            switch(event.button){
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4: return 1;
            }
        }
    },
    //获取字符编码
    getCharCode: function(event){
        if (typeof event.charCode == "number"){
            return event.charCode;
        } else {
            return event.keyCode;
        }
    },
    //访问剪贴板中的数据,获取clipboardData对象
    getClipboardText: function(event){
        var clipboardData =  (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
    },
    //获取事件对象
    getEvent: function(event){
        return event ? event : window.event;
    },
    //获取相关元素
    getRelatedTarget: function(event){
        if (event.relatedTarget){
            return event.relatedTarget;
        } else if (event.toElement){
            return event.toElement;
        } else if (event.fromElement){
            return event.fromElement;
        } else {
            return null;
        }
    
    },
    //获取事件目标
    getTarget: function(event){
        return event.target || event.srcElement;
    },
    //鼠标滚轮事件的wheelDelta属性
    getWheelDelta: function(event){
        if (event.wheelDelta){
            return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    //阻止默认事件
    preventDefault: function(event){
        if (event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    //移除事件处理程序
    removeHandler: function(element, type, handler){
        if (element.removeEventListener){
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent){
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    
    setClipboardText: function(event, value){
        if (event.clipboardData){
            event.clipboardData.setData("text/plain", value);
        } else if (window.clipboardData){
            window.clipboardData.setData("text", value);
        }
    },
    //阻止冒泡事件
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }

};
1、表单的基础知识

JavaScript 中,表单对应的则是 HTMLFormElement 类型。 HTMLFormElement 继承了 HTMLElement,因而与其他 HTML 元素具有相同的默认属性。它自己下列独有的属性和方法。

 acceptCharset:服务器能够处理的字符集;等价于 HTML 中的 accept-charset 特性。
 action:接受请求的 URL;等价于 HTML 中的 action 特性。
 elements:表单中所有控件的集合( HTMLCollection)。
 enctype:请求的编码类型;等价于 HTML 中的 enctype 特性。
 length:表单中控件的数量。
 method:要发送的 HTTP 请求类型,通常是"get"或"post";等价于 HTML 的 method 特性。
 name:表单的名称;等价于 HTML 的 name 特性。
 reset():将所有表单域重置为默认值。
 submit():提交表单。
 target:用于发送请求和接收响应的窗口名称;等价于 HTML 的 target 特性。

取得

元素引用的方式:

(1)将它看成与其他元素一样,并为其添加 id 特性,然后再像下面这样使用 getElementById()方法找到它;

var form = document.getElementById("form1");

(2)通过 document.forms 可以取得页面中所有的表单。在这个集合中,可以通过数值索引或name 值来取得特定的表单;

var firstForm = document.forms[0]; //取得页面中的第一个表单
var myForm = document.forms["form2"]; //取得页面中名称为"form2"的表单

1.1 提交表单

(1)使用

(2)在 JavaScript 中,以编程方式调用 submit()方法也可以提交表单;

var form = document.getElementById("myForm");
//提交表单
form.submit();

解决重复提交表单这一问题的办法有两个:

在第一次提交表单后就禁用提交按钮,或者利用 onsubmit 事件处理程序取消后续的表单提交操作。

(3)在以调用 submit()方法的形式提交表单时,不会触发 submit 事件,因此要记得在调用此方法之前先验证表单数据。

//避免多次提交表单
EventUtil.addHandler(form, "submit", function(event){
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    //取得提交按钮
    var btn = target.elements["submit-btn"];
    //禁用它
    btn.disabled = true;
});
1.2 重置表单

(1)使用 type 特性值为"reset"的

(2)与提交表单一样,也可以通过 JavaScript 来重置表单;

var form = document.getElementById("myForm");

(3)与调用 submit()方法不同,调用 reset()方法会像单击重置按钮一样触发 reset 事件。

1.3 表单字段

可以像访问页面中的其他元素一样,使用原生 DOM 方法访问表单元素。此外,每个表单都有elements 属性,该属性是表单中所有表单元素(字段)的集合。这个 elements 集合是一个有序列表,其中包含着表单中的所有字段,例如之间。

2.1 选择文本

上述两种文本框都支持 select()方法,这个方法用于选择文本框中的所有文本。 在调用 select()方法时,大多数浏览器( Opera 除外)都会将焦点设置到文本框中。这个方法不接受参数,可以在任何时候被调用。

var textbox = document.forms[0].elements["textbox1"];
textbox.select();

2.1.1 选择(select)事件

select()方法对应的,是一个 select 事件。在选择了文本框中的文本时,就会触发 select事件。另外,在调用 select()方法时也会触发 select 事件。

var textbox = document.forms[0].elements["textbox1"];
EventUtil.addHandler(textbox, "select", function(event){
    var alert("Text selected" + textbox.value);
});

2.1.2 取得选择的文本

(1)采取的办法是添加两个属性: selectionStartselectionEnd。这两个属性中保存的是基于 0 的数值,表示所选择文本的范围(即文本选区开头和结尾的偏移量)。

function getSelectedText(textbox){
    return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}

因 为 substring() 方 法 基 于 字 符 串 的 偏 移 量 执 行 操 作 , 所 以 将 selectionStart 和selectionEnd 直接传给它就可以取得选中的文本。
(2)IE8 及更早的版本中有一个 document.selection 对象,其中保存着用户在整个文档范围内选择的文本信息。

//获取选中的文本
function getSelectedText(textbox){
    if (typeof textbox.selectionStart == "number"){
    return textbox.value.substring(textbox.selectionStart,
    textbox.selectionEnd);
} else if (document.selection){
    return document.selection.createRange().text;
    }
}

2.1.3 选择部分文本

(1)所有文本框都有一个setSelectionRange()方法。这个方法接收两个参数:要选择的第一个字符的索引和要选择的最后一个字符之后的字符的索引(类似于 substring()方法的两个参数)。【IE9、 Firefox、 Safari、 Chrome 和 Opera 】

textbox.value = "Hello world!"
//选择所有文本
textbox.setSelectionRange(0, textbox.value.length); //"Hello world!"
//选择前 3 个字符
textbox.setSelectionRange(0, 3); //"Hel"
//选择第 4 到第 6 个字符
textbox.setSelectionRange(4, 7); //"o w"

(2)IE 在所有文本框上提供的 createTextRange()方法创建一个范围,并将其放在恰当的位置上。然后,再使用 moveStart()和 moveEnd()这两个范围方法将范围移动到位。不过,在调用这两个方法以前,还必须使用 collapse()将范围折叠到文本框的开始位置。此时,moveStart()将范围的起点和终点移动到了相同的位置,只要再给 moveEnd()传入要选择的字符总数即可。最后一步,就是使用范围的 select()方法选择文本。【IE8 及更早版本】

textbox.value = "Hello world!";
var range = textbox.createTextRange();
//选择所有文本
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", textbox.value.length); //"Hello world!"
range.select();
//选择前 3 个字符
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", 3);
range.select(); //"Hel"
//选择第 4 到第 6 个字符
range.collapse(true);
range.moveStart("character", 4);
range.moveEnd("character", 3);
range.select(); //"o w"

(3)跨浏览器实现选择部分文本,可以将上述两个方案组合起来。

function selectText(textbox, startIndex, stopIndex){
    if (textbox.setSelectionRange){
        textbox.setSelectionRange(startIndex, stopIndex);
    } else if (textbox.createTextRange){
        var range = textbox.createTextRange();
        range.collapse(true);
        range.moveStart("character", startIndex);
        range.moveEnd("character", stopIndex - startIndex);
        range.select();
    }
    textbox.focus();
}

这个 selectText()函数接收三个参数:要操作的文本框、要选择文本中第一个字符的索引和要选择文本中最后一个字符之后的索引。首先,函数测试了文本框是否包含 setSelectionRange()方法。如果有,则使用该方法。否则,检测文本框是否支持 createTextRange()方法。如果支持,则通过创建范围来实现选择。最后一步,就是为文本框设置焦点,以便用户看到文本框中选择的文本。可以像下面这样使用 selectText()方法。

textbox.value = "Hello world!"
//选择所有文本
selectText(textbox, 0, textbox.value.length); //"Hello world!"
//选择前 3 个字符
selectText(textbox, 0, 3); //"Hel"
//选择第 4 到第 6 个字符
selectText(textbox, 4, 7); //"o w
2.2 过滤输入

2.2.1 屏蔽字符

有时候,我们需要用户输入的文本中包含或不包含某些字符。如果只想屏蔽特定的字符,则需要检测 keypress 事件对应的字符编码,然后再决定如何响应。例如,下列代码只允许用户输入数值。

EventUtil.addHandler(textbox, "keypress", function(event){
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var charCode = EventUtil.getCharCode(event);
    if (!/d/.test(String.fromCharCode(charCode)) && charCode > 9 &!event.ctrlKey){
        EventUtil.preventDefault(event);
    }
});

2.2.2 操作剪切板

下列就是 6 个剪贴板事件:

beforecopy:在发生复制操作前触发。

copy:在发生复制操作时触发。

beforecut:在发生剪切操作前触发。

cut:在发生剪切操作时触发。

beforepaste:在发生粘贴操作前触发。

paste:在发生粘贴操作时触发。

要访问剪贴板中的数据,可以使用 clipboardData 对象。这个 clipboardData 对象有三个方法: getData()setData()clearData()。 其中, getData()用于从剪贴板中取得数据,它接受一个参数,即要取得的数据的格式;setData()方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文本。

var EventUtil = {
    //从剪贴板中取得数据
    getClipboardText: function(event){
        var clipboardData = (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
    },
    //将文本放到剪贴板中
    setClipboardText: function(event, value){
        if (event.clipboardData){
            return event.clipboardData.setData("text/plain", value);
        } else if (window.clipboardData){
            return window.clipboardData.setData("text", value);
        }
    },
}  
2.3 自动切换焦点

使用 JavaScript 可以从多个方面增强表单字段的易用性。其中,最常见的一种方式就是在用户填写完当前字段时,自动将焦点切换到下一个字段。这种“自动切换焦点”的功能,可以通过下列代码实现:

(function(){
    function tabForward(event){
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        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 textbox1 = document.getElementById("txtTel1");
    var textbox2 = document.getElementById("txtTel2");
    var textbox3 = document.getElementById("txtTel3");
    EventUtil.addHandler(textbox1, "keyup", tabForward);
    EventUtil.addHandler(textbox2, "keyup", tabForward);
    EventUtil.addHandler(textbox3, "keyup", tabForward);
})();

开始的 tabForward()函数是实现“自动切换焦点”的关键所在。这个函数通过比较用户输入的值与文本框的 maxlength 特性,可以确定是否已经达到最大长度。如果这两个值相等(因为浏览器最终会强制它们相等,因此用户绝不会多输入字符),则需要查找表单字段集合,直至找到下一个文本框。找到下一个文本框之后,则将焦点切换到该文本框。然后, 我们把这个函数指定为每个文本框的 onkeyup事件处理程序。由于 keyup 事件会在用户输入了新字符之后触发,所以此时是检测文本框中内容长度的最佳时机。这样一来,用户在填写这个简单的表单时,就不必再通过按制表键切换表单字段和提交表单了。

2.4 HTML5约束验证API

2.4.1 必填字段

(1)第一种情况是在表单字段中指定了 required 属性

(2)在 JavaScript 中,通过对应的 required 属性,可以检查某个表单字段是否为必填字段。

var isUsernameRequired = document.forms[0].elements["username"].required;
//使用下面这行代码可以测试浏览器是否支持 required 属性。
var isRequiredSupported = "required" in document.createElement("input");

2.4.2 其他输入类型

(1)HTML5 为元素的 type 属性又增加了几个值。这些新的类型不仅能反映数据类型的信息,而且还能提供一些默认的验证功能。其中, "email""url"是两个得到支持最多的类型.

(2)要检测浏览器是否支持这些新类型,可以在 JavaScript 创建一个元素,然后将 type 属性设置为"email"或"url",最后再检测这个属性的值。不支持它们的旧版本浏览器会自动将未知的值设置为"text",而支持的浏览器则会返回正确的值。

var input = document.createElement("input");
input.type = "email";
var isEmailSupported = (input.type == "email");

2.4.3 数值范围

HTML5 还定义了另外几个输入元素。这几个元素都要求填写某种基于数字的值: "number"、 "range"、 "datetime"、 "datetime-local"、 "date"、 "month"、 "week",还有"time"。

对所有这些数值类型的输入元素,可以指定 min 属性(最小的可能值)、 max 属性(最大的可能值)和 step 属性(从 min 到 max 的两个刻度间的差值)。

//让用户只能输入 0 到 100 的值,而且这个值必须是 5 的倍数

以上这些属性在 JavaScript 中都能通过对应的元素访问(或修改)。此外,还有两个方法: stepUp()stepDown(),都接收一个可选的参数:要在当前值基础上加上或减去的数值。

input.stepUp(); //加 1
input.stepUp(5); //加 5
input.stepDown(); //减 1
input.stepDown(10); //减 10

2.4.4 输入模式

HTML5 为文本字段新增了 pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的值。

//如果只想允许在文本字段中输入数值,可以像下面的代码一样应用约束:

//在 JavaScript 中可以通过 pattern 属性访问模式。
var pattern = document.forms[0].elements["count"].pattern;
//使用以下代码可以检测浏览器是否支持 pattern 属性。
var isPatternSupported = "pattern" in document.createElement("input");

2.4.5 检测有效性

使用 checkValidity()方法可以检测表单中的某个字段是否有效。所有表单字段都有个方法,如果字段的值有效,这个方法返回 true,否则返回 false。

if (document.forms[0].elements[0].checkValidity()){
//字段有效,继续
} else {
//字段无效
}

与 checkValidity()方法简单地告诉你字段是否有效相比, validity 属性则会告诉你为什么字段有效或无效。这个对象中包含一系列属性,每个属性会返回一个布尔值。

customError :如果设置了 setCustomValidity(),则为 true,否则返回false。

patternMismatch:如果值与指定的pattern 属性不匹配,返回true。

rangeOverflow:如果值比 max 值大,返回 true。

rangeUnderflow:如果值比 min 值小,返回true。

stepMisMatch:如果 min 和 max 之间的步长值不合理,返回true。

tooLong:如果值的长度超过了maxlength 属性指定的长度,返回true。有的浏览器(如Firefox 4)会自动约束字符数量,因此这个值可能永远都返回false。

typeMismatch:如果值不是"mail"或"url"要求的格式,返回true。

valid:如果这里的其他属性都是false,返回 true。 checkValidity()也要求相同的值。

valueMissing:如果标注为 required 的字段中没有值,返回true。

2.4.6 禁用验证

通过设置 novalidate属性,可以告诉表单不进行验证。




//在 JavaScript 中使用 noValidate 属性可以取得或设置这个值,如果这个属性存在,值为 true,如果不存在,值为 false。
document.forms[0].noValidate = true; //禁用验证

如果一个表单中有多个提交按钮,为了指定点击某个提交按钮不必验证表单,可以在相应的按钮上添加 formnovalidate 属性。

//使用 JavaScript 也可以设置这个属性。 //禁用验证 document.forms[0].elements["btnNoValidate"].formNoValidate = true;
3、选择框脚本

选择框是通过