整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

第66节 表单按钮下拉选项及表单序列化-Web前端开发之JavaScript

内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。

按钮Button:
按钮是最常用的表单元素之一,有两种形式的按钮,button按钮和radio单选、checkbox复选按钮;
提交和重置元素本身就是按钮,并且有相关联的默认动作,如果其click事件处理程序返回false,也就取消它的默认行为了;也可以使用它们的click事件来执行表单的验证及提交,但最为常用的还是使用form对象本身的submit事件进行验证和提交;
普通按钮是没有默认行为的,一般来说使用它们来执行自定义脚本,当然也可以用它来执行form.submit()方法来提交表单;
对于type为”submit”或type=”image”的按钮,HTML5新增了formaction、formmethod、formenctype、formtarget属性,其中formaction属性用于覆盖form的 action属性,作用是为不同的提交按钮增加formaction属性,使得在单击时可以将表单提交给不同的页面;formmethod属性为每个不同的提交按钮分别指定不同的提交方法;formenctype属性为每个不同的提交按钮分别指定不同的编码方式;formtarget属性用于为每个不同的提交按钮指定在何处打开提交页面;这些属性在Javascript中都有相对应的同名属性,如:

<form action="demo.php">
    <input type="submit" formaction="center/" formmethod="GET" formtarget="_blank" formenctype="multipart/form-data" value="用户中心" />
    <input type="submit" formaction="admin/" formmethod="POST" formaction="_self" formenctype="application/x-www-form-urlencoded" value="后台管理" />
</form>
<script>
var btnSubmit = document.forms[0].elements[0];
console.log(btnSubmit.formAction);
console.log(btnSubmit.formMethod);
console.log(btnSubmit.formTarget);
console.log(btnSubmit.formEnctype);
</script>

radio单选和checkbox复选按钮(框)是开关按钮,其只有两种状态:选中或未选中;

<form id="myForm" name="myForm">
<p>性别:
<input type="radio" name="sex" id="male" value="1" />男
<input type="radio" name="sex" id="remale" value="0" checked />女
</p>
<p>课程:
HTML<input type="checkbox" name="course" id="c1" value="HTML" />
CSS<input type="checkbox" name="course" id="c2" value="CSS" checked />
JavaScript<input type="checkbox" name="course" id="c3" value="JavaScript" />
</p>
</form>
<script>
var male = document.getElementById("male");
console.log(male); // <input>
male = document.forms["myForm"].elements["male"];
console.log(male);  // <input>
</script>

单选和复选按钮都定义了checked属性,该属性为可读写的布尔值;defaultChecked属性对应的是HTML的checked属性,也是布尔值,它指定了元素在第一次加载页面时是否选中;

var male = document.forms["myForm"].elements["male"];
var remale = document.forms["myForm"].elements["remale"];
console.log(male.checked);  // false
console.log(male.defaultChecked);  // false
console.log(remale.checked);  // true
console.log(remale.defaultChecked);  // true
male.checked = true;
console.log(male.checked);  // true
console.log(male.defaultChecked);  // false
console.log(remale.checked);  // false
console.log(remale.defaultChecked);  // true
male.defaultChecked = true;
console.log(male.checked);  // true
console.log(male.defaultChecked);  // true
console.log(remale.checked);  // false
console.log(remale.defaultChecked);  // true

checked会令一个单选按钮组中所有元素互斥,defaultChecked也是可写的(W3C定义其是只读的,所以写入的操作是不规范的),但它不是互斥的;所以可以利用这两个属性把单选按钮恢复到默认的状态,如:

male.checked = true;
male.checked = male.defaultChecked; 
remale.checked = remale.defaultChecked;

对于复选框,也是类似的,但其checked不是互斥的,因为它本身就允许多选;
例如:复位单选和复选状态;

<p><input type="button" value="重置单选和复选" id="resetRadioCheckbox" /></p>
<script>
var resetRadioCheckbox = document.getElementById("resetRadioCheckbox");
resetRadioCheckbox.onclick = function(){
    // var radioList = document.querySelectorAll('input[type="radio"]');
    var radioList = document.getElementsByName("sex"); // 也可以
    console.log(radioList);
    for(var i=0,len=radioList.length; i<len; i++)
        radioList[i].checked = radioList[i].defaultChecked;
    
    var checkList = document.getElementsByName("course");
    for(var i=0,len=checkList.length; i<len; i++)
        checkList[i].checked = checkList[i].defaultChecked; 
}
</script>

单选和复选按钮本身并不显示任何文本,它们通常和相邻的HTML文本一起显示或与<label>元素相关联,所以其value属性并不显示出来,而只是为了提交给服务端;

var radioList = document.getElementsByName("sex");
for(var i=0,len=radioList.length; i<len; i++){
    if(radioList[i].checked)
        console.log("被选中的值是:" + radioList[i].value);
}
var checkList = document.getElementsByName("course");
var checkStr = "";
for(var i=0,len=checkList.length; i<len; i++){
    if(checkList[i].checked)
        checkStr += checkList[i].value + ",";
}
if(checkStr != "")
    checkStr = checkStr.substring(0,checkStr.length - 1);
else
    checkStr = "无";
console.log("被选中的值是:" + checkStr);

同时,也会根据获取来的值来设置单选或复选按钮的选中状态,如:

window.onload = function(){
    var sexValue = 1; // 从服务端获取
    var radioList = document.getElementsByName("sex");
    for(var i=0,len=radioList.length; i<len; i++){
        if(radioList[i].value == sexValue){
            radioList[i].checked = true;
            break;
        }
    }
    var courseValue = "JavaScript,HTML";  // 从服务端获取
    var arrCourse = courseValue.split(",");
    var checkList = document.getElementsByName("course");
    for(var i=0,len=checkList.length; i<len; i++){
        // if(arrCourse.indexOf(checkList[i].value) >= 0) // 或者
        if(arrCourse.includes(checkList[i].value))
            checkList[i].checked = true;
        else
            checkList[i].checked = false;
    }
}

其往往成组并使用共享的name,如果使用共享的name获取这些元素时,返回是一个类数组而不是单个元素;

<script>
var sex = document.getElementsByName("sex");
console.log(sex);  // NodeList
var sex = document.forms["myForm"].elements["sex"];
console.log(sex);  // RadioNodeList
</script>

使用elements集合,返回的类型是更具体的RadioNodeList,该类型拥有一个value属性,返回单选按钮组中选中的value值;该属性是可读写的,在设置value属性时,value属性等于值的第一个单选按钮元素将被设置为checked,如:

console.log(sex.value);  // 0
sex.value = "1";  // 男就被选中的
console.log(sex.value);

radio单选按钮的本意就是在一组单选按钮组中只能选择唯一一个,如果只有一个radio按钮,是没有多大实际意义的;即使如此,如果使用elements属性,其返回的就不是NodeList,而是单个元素对象;

<p><input type="radio" id="single" name="single" value="单个按钮" /></p>
</form>
<script>
var single = document.forms[0].elements["single"];
console.log(single);  // <input>
single.checked = true;
console.log(single.checked);
console.log(single.defaultChecked);
console.log(single.value);  // 单个按钮
</script>

在获取checkbox时,如:

var courses = document.getElementsByName("course");
console.log(courses);  // NodeList<input>
var courses = document.forms["myForm"].elements["course"];
console.log(courses); // RadioNodeList<input>

虽然当前为checkbox组,并不是radio组,但返回的也是RadioNodeList,并不是类似的CheckboxNodeList类型,而且也不存在这个类型;
其返回的RadioNodeList集合的value属性无用;获取所有选中复选按钮的值,可以遍历所有被选中的选项;

当单击单选或复选按钮时,会触发onclick事件,如果单击时改变了开关按钮的状态,也会触发change事件;

var sexList = document.forms[0].elements["sex"];
for(var i=0,len=sexList.length; i<len; i++){
    var sex = sexList[i];
    sex.addEventListener("change", function(event){
        console.log(event.target.checked);
        console.log(event.target.defaultChecked);
    });
}
var courseList = document.forms[0].elements["course"];
var log = document.getElementById("log");
var arrCourse = [];
for(var i=0,len=courseList.length; i<len; i++){
    if(courseList[i].checked)
        arrCourse.push(courseList[i].value);
}
console.log(arrCourse.join());
log.innerText = arrCourse.join();
for(var i=0,len=courseList.length; i<len; i++){
    var course = courseList[i];
    course.addEventListener("change", function(event){
        if (event.target.checked) {
            arrCourse.push(event.target.value);
        }else{
            arrCourse.splice(arrCourse.indexOf(event.target.value),1);
        }
        console.log(arrCourse.join());
        log.innerText = arrCourse.join();
    },false);
}

示例:全选:

<p>
HTML<input type="checkbox" name="course" value="HTML" />
CSS<input type="checkbox" name="course" value="CSS" />
JavaScript<input type="checkbox" name="course" value="JavaScript" />
</p>
<p><button id="all">全选</button>
    <button id="not">全不选</button>
<button id="reverse">反选</button></p>
<script>
var chkBoxs = document.getElementsByName("course");
// 全选
var all = document.getElementById("all");
all.onclick = function(){
    for(var i=0; i<chkBoxs.length; i++){
        chkBoxs[i].checked = true;
    }
}
// 全不选
var not = document.getElementById("not");
not.onclick = function(){
    for(var i=0; i<chkBoxs.length; i++){
        chkBoxs[i].checked = false;
    }
}
// 反选
var reverse = document.getElementById("reverse");
reverse.onclick = function(){
    for(var i=0; i<chkBoxs.length; i++){
        chkBoxs[i].checked = !chkBoxs[i].checked;
    }
}
</script>

示例:同意提交

<div id="content">
<p>Lorem ...</p>
</div>
<p><label>同意此协议</label><input type="checkbox" id="cbAgree" disabled /></p>
<input type="submit" value="提交" id="btnSubmit" disabled />
<script>
window.onload = function(){
    var cbAgree = document.getElementById("cbAgree");
    var btnSubmit = document.getElementById("btnSubmit");
    var s = 5;
    var timer = setInterval(function(){
        btnSubmit.value = "等待" + s + "秒";
        if(--s < 0){
            clearInterval(timer);
            btnSubmit.value = "提交";
            cbAgree.disabled = false;
        }
    },1000);
    cbAgree.addEventListener("change", function(event){
        btnSubmit.disabled = !cbAgree.checked;
    },false);
}
</script>

Label标签元素:
其与其它表单元素关联,关联的方式有两种:一是使用for属性,二是将<input>直接嵌套在<label>中,在这种情况下,不需要for和id属性,因为关联是隐式的;
表单的elements集合中并不包括Lable;

Label属性:

  • form:只读,是一个HTMLFormElement对象,表示与其关联的Form;如果没有关联Form,则为null;
  • control:只读,表示与标签关联的表单元素;
  • htmlFor:可读可写,是一个字符串,表示与其关联的表单元素的ID,与其HTML的for属性对应;
var label = document.getElementsByTagName("label")[1];
console.log(label);
console.log(label.form);
console.log(label.control);
console.log(label.htmlFor);
label.htmlFor = "c2";
console.log(label.control);  // checkbox
console.log(label.htmlFor);  // c2

表单元素的labels属性:只读,返回表单元素关联的所有<label>元素的NodeList,如:

<p><label for="content">内容:</label><br/>
<textarea id="content" name="content"></textarea><br/>
<label for="content">请输入简要的内容</label></p>
</form>
<script>
var content = document.forms["myForm"].elements["content"];
console.log(content.labels);  // NodeList(2)
var label = content.labels[0];
console.log(label);  // label
console.log(label.textContent);  // 内容:
console.log(label.form);  // <form>
console.log(label.control);  // textarea#content
console.log(label.htmlFor);  // content
</script>

select选择框:
选择框是通过<select>和<option>元素创建的,其属于HTMLSelectElement类型,浏览器通常将其渲染为下拉菜单的形式或设置其size属性大于1呈现为列表的形式;

<form id="myForm" name="myForm">
<select name="province" id="province">
    <option value="beijing" label="大北京">北京</option>
    <option>安徽</option>
    <option value="jiangsu">江苏</option>
    <option value="guangdong">广东</option>
    <option value="shangdong">山东</option>
</select>
</form>

其拥有除了所有表单元素共有的属性和方法外,还提供了:

  • size :选择框中可见的行数;等价于HTML中的size特性;
  • multiple:布尔值,表示是否允许多选;等价于HTML中的multiple特性;
  • type:值为”select-one”或”select-multiple”,取决于HTML代码中有没有multiple特性;
  • options:控件中所有<option>元素的HTMLCollectoin;
  • selectedIndex:选中项的索引,如果没有选中项,为0;对于多选,只保存选中项中第一项的索引;
  • selectedOptions:表示所选中<option>元素集的HTMLCollection;
  • add(newOptoin, relOption):向<select>中插入新<option>元素,其位置在指定项relOption之前;
  • remove(index):移除给定位置的<option>选项;
  • length:返回<option>数量;
  • value:由当前选中项决定:如果没有选中的项,则为空字符串;如果有一个选中项,而且该项的value特性已经在HTML中指定,就等于该option的value值,即使该value是空字符,也是如此;如果有一个选中项,但该项的value特性在HTML中未指定,则该value等于该项的文本(text);如果有多个选中项,取得第一个选中项的值;当其type为select-one和select-multiple时,其选择的行为是不一样的,如果为select-multiple,允许多选,但此时,其value返回的是第一个option的value值;
  • options属性,其返回包含了多个Option元素的HTMLOptionsCollection集合,如:
var province = document.forms[0].elements["province"];
console.log(province.options);  // HTMLOptionsCollection

该集合拥有length、selectedIndex属性和add()及remove()方法;其中selectedIndex返回的是选中项的索引;通过options的索引可以返回一个option对象;

console.log(province.options.selectedIndex);  // 2
console.log(province.selectedIndex);  // 2
console.log(province.options[1]);  // <option>

通过select对象的item(index)方法或select的索引也可以返回一个option对象;

var opt = selectbox.item(1);
var opt = selectbox[1];
console.log(opt);
console.log(opt.index);
console.log(opt.text);

每个<option>元素属于HTMLOptionElement类型,该类型继承自成 HTMLElement,其拥有下列属性:

  • index:当前项在options集合中的索引;
  • form:只读,其所属的form,与其所在的HTMLSelectElement 对象的form属性一致;
  • label:当前选项的Label属性;如果没有此属性,则返回元素的text;
  • selected:布尔值,表示当前选项是否被选中;将这个属性设置为true可以选中当前选项;
  • defaultSelected:对应其HTML的selected特性的初始值;
  • text:选项显示的纯文本字符串;
  • value:选项的值;等价于HTML中的value特性,即提交给服务端的文本;

设置这些属性的目的,是为了方便对选项数据的访问,虽然可以使用常规的DOM功能来访问这些信息,但效率比较低:

var province = document.forms[0].elements["province"];
// 不推荐
// var text = province.options[0].firstChild.nodeValue;
var text = province.options[0].textContent; // 或
var value = province.options[0].getAttribute("value");
console.log(text, value);
// 推荐
var text = province.options[0].text;
var value = province.options[0].value;
console.log(text, value);
console.log(province.options[0].index);
console.log(province.options[0].selected);
console.log(province.options[0].label);
province.options[2].selected = true;
// options[1]没有value,所以返回其text
console.log(province.options[1].value);

在未指定value特性的情况下,IE7会返回空字符串,其他会返回与text特性相同的值;

<opggroup>:
<optgroup>HTML元素在<select>元素中创建一组选项,其属于HTMLOptGroupElement类型,属性为:
disabled:是一个布尔值,表示整个子项列表<option>是否已禁用(true)或未禁用(false);
label:表示组label属性;

<form>
<select id="selectbox">
    <optgroup label="前端" disabled>
        <option>HTML</option>
        <option>CSS</option>
        <option>JavaScript</option>
    </optgroup>
    <optgroup label="后端">
        <option>C#</option>
        <option>Java</option>
        <option>PHP</option>
    </optgroup>
</select>
<script>
var selectbox = document.getElementById("selectbox");
var optgroup = selectbox.getElementsByTagName("optgroup")[0];
console.dir(optgroup);  // HTMLOptGroupElement
console.dir(optgroup.label);  // 前端
</script>

选择选项:
对于只允许选择一项的选择框,最简单的方式就是直接使用selectedIndex属性,利用此属性既可以获取选中的项,也可设置某个项被造中;如:

var selectedIndex = province.selectedIndex;
var selectedOption = province.options[selectedIndex];
console.log("选中项的索引:" + selectedIndex + ",text" + selectedOption.text + ",value:" + selectedOption.value);
province.selectedIndex = 1;  // 根据索引设置选中项
var selectedIndex = province.selectedIndex;
var selectedOption = province.options[selectedIndex];
console.log("选中项的索引:" + selectedIndex + ",text" + selectedOption.text + ",value:" + selectedOption.value);

对于multiple多项的选择,单个selectedIndex属性不足以表示被选中的多个选项,即使选中多个,读取则只会返回选中项第一项的索引值且其value值也是第一个选中的Option的value值;

selected属性:另一种选择选项的方式,即取得某一项的引用,然后将其selected属性设置为true;

console.log(province.options[0].selected); // false
console.log(province.options[2].selected); // true
province.options[0].selected = true;
province.options[1].selected = true;

与selectedIndex不同的是,在允许多选的选择框中设置选项的selected属性,不会取消对其他选中项的选择,因而可以动态选中任意多个项;但如果是在单选择框中,会取消对其他选择的选择;

selected属性的作用主要是确定用户选择了选择框中的哪些项;要取得所有选中的项,可以遍历Options选项集合,逐个测试每个选项的selected属性:

var province = document.forms[0].elements["province"];
function getSelectedOptions(selectbox){
    var result = new Array();
    var option = null;
    for(var i=0, len=selectbox.options.length; i<len; i++){
        option = selectbox.options[i];
        if(option.selected){
            result.push(option);
        }
    }
    return result;
}
var province = document.forms[0].elements["province"];
var selectedOptions = getSelectedOptions(province);
var msg = "";
for(var i=0,len = selectedOptions.length; i<len; i++){
    msg += "index:" + selectedOptions[i].index + ",text:" + selectedOptions[i].text + ",value:"+ selectedOptions[i].value  + ";";
}
console.log(msg);

selectedOptions属性:只读属性,其返回当前选定的<option>元素的HTMLCollection;

console.log(province.selectedOptions); // HTMLCollection

如果是select-one单选,其中包含一个option,如果是select-mutiple多选,就包括所有选定的option;
例如:获取所有选中项

<label for="foods">你喜欢吃什么?</label><br>
<select id="foods" name="foods" size="7" multiple>
    <option value="1">苹果</option>
    <option value="2">香蕉</option>
    <option value="3">桔子</option>
    <option value="4">披萨</option>
    <option value="5">西红柿</option>
</select>
<br>
<button name="order" id="order">确定</button>
<p id="output"></p>
<script>
var orderButton = document.getElementById("order");
var itemList = document.getElementById("foods");
var outputBox = document.getElementById("output");
orderButton.addEventListener("click", function() {
    var collection = itemList.selectedOptions;
    var output = "";
    for (var i=0; i<collection.length; i++) {
        if (output === "") {
            output = "你喜欢吃的食物如下:";
        }
        output += collection[i].text;
        if(i === (collection.length - 2) && (collection.length < 3))
            output +=  "和";
        else if(i < (collection.length - 2))
            output += ",";
        else if(i === (collection.length - 2))
            output += "和";
    }
    if(output === "")
    output = "你啥也不喜欢";
    outputBox.innerHTML = output;
}, false);
</script>

添加选项:
可以动态添加选项,并将它们添加到选择框中;有多种添加的方式:
第一种:使用DOM方法:

var newOption = document.createElement("option");
newOption.appendChild(document.createTextNode("天津"));
// newOption.setAttribute("value", "tianjin");
newOption.value = "tianjin";
selectbox.appendChild(newOption);

第二种:使用Option构造函数来创建新选项:
语法:var option = new Option(text?, value?, ?defaultSelected, ?selected);参数text和value分别设置Option对象的text和value;后两个参数,分别设置option的defaultSelected和selected属性,4个参数均为可选;其会返回一个<option>元素;

var newOption = new Option("上海", "shanghai");
selectbox.appendChild(newOption);
newOption = new Option("四川","sichuan",true,true);
selectbox.appendChild(newOption);
newOption = new Option();
newOption.text = "贵州";
newOption.value = "guizhou";
newOption.label = "美丽贵州";
newOption.selected = true;
selectbox.appendChild(newOption);

IE7以下不可用,因为它不能正确设置新选项的text属性;

第三种:使用选择框的add()方法:
语法:select.add(option[, before);其接受两个参数:要添加的新选项option和将位于新选项之后的选项before;before即可以是一个option也可以是选项的索引;before为可选,如果要在列表的最后添加选项,应该将第二个参数设置为null、undefined或者不设;如:

var newOption = new Option("上海", "shanghai");
selectbox.add(newOption, selectbox.options[1]); // 第2个位置
selectbox.add(newOption, 1); // 第2个位置
selectbox.add(newOption, null); // 最后位置
selectbox.add(newOption, undefined); // 最后位置
selectbox.add(newOption, 100); // 最后位置
selectbox.add(newOption); // 最后位置

如果将新选项添加到任意位置,使用DOM技术和insertBefore()方法也可以;

第四种,使用options属性也可以把新的option添加到选择框中,或者使用表单索引,如:

var newOption = new Option("上海", "shanghai");
selectbox.options[selectbox.options.length] = newOption; // 或者
selectbox[selectbox.options.length] = newOption;
// 如,添加多个
var arrOptions = ['重庆','云南','广西'];
arrOptions.forEach(function(v,i){
    selectbox[selectbox.options.length] = new Option(v);
});
// 或
arrOptions = [
    {text: "重庆", value: "chongqing"},
    {text: "云南", value: "yunnan"},
    {text: "广西", value: "guangxi"}
];
arrOptions.forEach(function(v,i){
    selectbox[selectbox.options.length] = new Option(v.text, v.value);
});

移除选项:
移除选项也有多种方式:首先可以使用DOM的removeChild()方法,为其传入要移除的选项;其次可以使用选择框的remove()方法,为其传入要移除选项的索引;最后,可以将相应选项设置为null;

selectbox.removeChild(selectbox.options[1]);
selectbox.remove(2);
selectbox.options[2]=null;
// 如果不带参数,会删除selectbox本身
selectbox.remove();

移除选择框中所有的项,可以迭代所有选项并逐个移除:

function clearSelectbox(selectbox){
    for(var i=0,len=selectbox.options.length; i<len; i++){
        selectbox.remove(0);
    }
}
clearSelectbox(selectbox);

使用options属性也可以移除全部或某个选项,

selectbox.options[1] = null;  // 移除第2个
selectbox.options.length = 2; // 截断,只保留2个
// selectbox.options.length = 0; // 移除所有
selectbox.length = 0; // 移除所有

移动选项:
将一个选择框中的选项移动到另一个选择框中,使用DOM的appendChild()方法,因为使用appendChild()方法并传入一个已存在的元素,那么就会先从该元素的父节点中移除它,再把它添加到新的指定的位置;

var selectbox1 = document.getElementById("selLocation1");
var selectbox2 = document.getElementById("selLocation2");
selectbox2.appendChild(selectbox1.options[1]);

移动和移除选项有一个共同之外,即会重置每一个选项的index属性;

<h3>移动选项</h3>
<select name="sel1" id="sel1" size="8" multiple>
    <option value="">唐</option>
    <option value="">宋</option>
    <option value="">元</option>
    <option value="">明</option>
    <option value="">清</option>
</select>
<button id="toRight">>></button>
<button id="toLeft"><<</button>
<select name="sel2" id="sel2" size="8" multiple>
    <option value="">秦</option>
    <option value="">汉</option>
    <option value="">三国</option>
    <option value="">两晋</option>
    <option value="">南北朝</option>
</select>
<script>
var sel1 = document.getElementById("sel1");
var sel2 = document.getElementById("sel2");
var toRight = document.getElementById("toRight");
var toLeft = document.getElementById("toLeft");
toRight.onclick = function(){
    var options = sel1.selectedOptions;
    for(var i=options.length-1; i>=0; i--){
        sel2.appendChild(options[i]);
    }
};
toLeft.onclick = function(){
    var options = sel2.selectedOptions;
    for(var i=options.length-1; i>=0; i--){
        sel1.appendChild(options[i]);
    }
}
</script>

重排选项:
重排选项的次序,最好的方式也是DOM方法,如appendChild()适合将选项添加到选择框的最后,insertBefore()可以将选项移动到指定位置,如:

var optionToMove = selectbox.options[1];
// 向上移一下
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index - 1]);
// 向下移一下
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index + 2]);

select的事件:
选择框的change事件与其他表单控件的change事件触发的条件不一样,其他控件的change事件是在值被修改且焦点离开时触发,而选择框的change事件只要选中了选项就会触发;
选择不同的选项时,也会触发input事件,如:

selectbox.addEventListener("change", function(event){
    console.log(event.target.selectedIndex);
});
function inputHandler(e){
    console.log(e.target.value);
}
selectbox.addEventListener("input", inputHandler);

示例:跳转

<select id="links">
    <option value="https://www.zeronetwork.cn">零点网络</option>
    <option value="https://cn.bing.com">Bing</option>
    <option value="https://www.apple.com">苹果</option>
</select>
<script>
var links = document.getElementById("links");
links.addEventListener("change", function(event){
    location.href = event.target.options[event.target.selectedIndex].value;
});
</script>

表单序列化:
随着Ajax的出现,表单序列化已经成为一种常见需求;在Javascript中,可以利用表单元素的type属性,连同name和value属性一起实现对表单的序列化;
浏览器把数据发送给服务器原理:

  • 对表单字段的名称和值进行URL编码,使用和号(&)分隔;
  • 不发送禁用的表单字段;
  • 只发送勾选的复选框和单选按钮,并且复选框中的每个选中的值单独一个条目;
  • 不发送type为”reset”和”button”的按钮;
  • 多选选择框中的每个选中的值单独一个条目;

如:表单简单序列化;

var btn = document.getElementById("btn");
btn.addEventListener("click", submitHandler, false);
function submitHandler(event){
    var myForm = document.forms[0];
    var username = myForm.elements["username"].value;
    var userpwd = myForm.elements["userpwd"].value;
    var sex = myForm.elements["sex"].value;
    var courseValue = [];
    var courseList = myForm.elements["course"];
    for(var i=0, len=courseList.length; i<len; i++){
        if(courseList[i].checked)
            courseValue.push(courseList[i].value);
    }
    var params = "username=" + username +
                "&userpwd=" + userpwd +
                "&sex=" + sex +
                "&course=" + courseValue;
    console.log(params);
}

如:通用序列化:

function serialize(form){
    // 后面要用到的变量
    var params = new Array();
    var field = null,
        i, j, len,
        optLen,
        option,
        chkObj = {};
        
    for(i=0, len=form.elements.length; i<len; i++){
        field = form.elements[i];
        switch(field.type){
            // 如果是select,包含单选和多选
            case "select-one":
            case "select-multiple":
                arrOpt = [];
                for(j=0, optLen=field.options.length; j<optLen; j++){
                    option = field.options[j];
                    if(option.selected){
                        arrOpt.push(encodeURIComponent(option.value));
                    }
                }
                arrOpt = arrOpt.join(",");
                params.push(encodeURIComponent(field.name) + "=" + arrOpt);
                break;
            // 如果是fieldset、file、submit、reset、button不提交
            case undefined: //字段集
            case "file":    //文件域
            case "submit":  //提交
            case "reset":   //重置
            case "button":  //按钮
                break;
            // 如果是单选或复选框
            case "radio":
            case "checkbox":
                if(field.checked){
                    if(chkObj[field.name])
                        chkObj[field.name].push(encodeURIComponent(field.value));
                    else
                        chkObj[field.name] = [encodeURIComponent(field.value)];
                }
                break;
            default:
                // 如果没有名字的表单元素,不提交
                if(field.name.length)
                    params.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));
        }
    }
    for(var o in chkObj){
        params.push(encodeURIComponent(o) + "=" + chkObj[o].join(","));
    }
    return params.join("&");
}
// 应用
var btn = document.getElementById("btn");
btn.addEventListener("click", submitHandler, false);
function submitHandler(event){
    var myForm = document.forms[0];
    var params = serialize(myForm);
    console.log(params);
}

无刷新提交(局部刷新):

<script>
function saveUserInfo(){
    var msg = document.getElementById("msg");
    var form = document.forms[0];
    // 提交地址
    var url = "./demo.php"; 
    // POST的值,把每个变量都通过&来联接
    var postStr = serialize(form);
        
    // XmlHTTP
    var XmlHTTP;
    if(window.XMLHttpRequest) {
        XmlHTTP = new XMLHttpRequest();
    }else if(window.ActiveXObject) {
        XmlHTTP = new ActiveXObject("Microsoft.XMLHTTP");
    }
    XmlHTTP.open("POST", url, true);
    //定义传输的文件HTTP头信息
    XmlHTTP.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    XmlHTTP.send(postStr); //发送POST数据
    //获取执行状态
    XmlHTTP.onreadystatechange = function() {
        //如果执行状态成功,那么就把返回信息写到指定的层里
        if (XmlHTTP.readyState == 4 && XmlHTTP.status == 200) {
            msg.innerHTML = XmlHTTP.responseText;
        }
    }
}
</script>
<div id="msg"></div>
<form name="userinfo" method="post" action="">
    姓名:<input type="text" id="username"name="username" /><br />
    年龄:<input type="text" name="age" /><br />
    性别:<input type="text" name="sex" /><br />
    <input type="button" value="提交表单" onClick="saveUserInfo()">
</form>

demo.php:

<?php
$username = $_POST['username'];
$age = $_POST['age'];
$sex = $_POST['sex'];
echo "$username <br>";
echo "$userage <br>";
echo "$usersex <br>";
// 链接数据库,并保存到数据库,$result为执行结果
$result = true;
if ($result){
    echo "提交成功!";
}
else {
    echo "提交失败!";
}
?>

整合:saveUserInfo()中换成:

    // 提交地址
    var url = "./demo.php"; 
    // POST的值,把每个变量都通过&来联接
    var postStr = serialize(form);

submitHandler()事件处理函数:

今天就来聊聊在为了您更好的体验,本文章聊聊如何仅支持谷歌浏览器访问查看页面?这篇文章中提到的浏览器兼容问题,以此篇文章来证明自己并非不了解浏览器兼容性问题,而是当时其他因素导致选择了一刀切的方法来处理需求(我就是一个不粘锅)。

嘿,xdm~既然点进来了,不妨就继续看下去吧^_^

概念

所谓的浏览器兼容性问题,是指因为不同的浏览器对同一段代码有不同的解析,造成页面显示效果不统一的情况

上面的定义就是大白话,我们来看看来自百度百科的权威解释:浏览器兼容性问题又被称为网页兼容性或网站兼容性问题,指网页在各种浏览器上的显示效果可能不一致而产生浏览器和网页间的兼容问题。在网站的设计和制作中,做好浏览器兼容,才能够让网站在不同的浏览器下都正常显示。而对于浏览器软件的开发和设计,浏览器对标准的更好兼容能够给用户更好的使用体验。

产生的原因

造成浏览器兼容性问题的根本原因就是各浏览器使用了不同的内核,并且它们处理同一件事情的时候思路不同。

怎么理解上述文字?即:不同浏览器使用的内核及所支持的HTML等网页语言标准不同,以及用户客户端的环境不同(如分辨率不同)造成了显示效果不能达到理想效果

解决方法

前端开发经常需要检查浏览器的兼容性,这里推荐(Can I Use)这个查询网站。它是一个针对前端开发人员定制的一个查询CSS、JS、HTML5、SVG在主流浏览器中特性和兼容性的网站,可以很好的保证网页在浏览器中的兼容性。有了这个工具我们就可以快速地了解到代码在各个浏览器中的兼容情况了,强烈推荐一波,大家赶紧去体验吧✈!界面效果如下图所示:

工具只能给我们显示查询的特性在不同浏览器上的兼容情况,至于如何解决兼容问题还得看下述的解决办法→

CSS兼容问题

1、不同浏览器的标签默认的内外边距不同

解决方案:*{margin: 0; padding: 0;}

其实清除浏览器自带的默认样式,每个前端开发者所用的方法大同小异,这里给出我选用的清除默认样式的重置样式代码:

/**
 * 该文件用于清除浏览器样式
 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    padding:0;
    margin:0;
    border:0;
    outline: 0;
    font-family: "Helvetica Neue For Number", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
    word-wrap:break-word;
}
html, body {
    width: 100%;
    height: 100%;
}
a {
    text-decoration: none;
    -webkit-tap-highlight-color:rgba(255,255,255,0);
}
ul, ol {
    list-style-type: none;
}
textarea {
    resize: none;
}
/*去除input button默认样式*/
input, button, textarea {
    -webkit-appearance: none;
    -webkit-tap-highlight-color: rgba(255, 225, 225, 0);
    padding: 0;
    border: 0;
    outline: 0;
}
// 修改placeholder属性默认文字颜色
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder {
    /* WebKit browsers */
    color: #999;
}
input:-moz-placeholder, textarea:-moz-placeholder {
    /* Mozilla Firefox 4 to 18 */
    color: #999;
}
input::-moz-placeholder, textarea::-moz-placeholder {
    /* Mozilla Firefox 19+ */
    color: #999;
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
    /* Internet Explorer 10+ */
    color: #999;
}

除了自己定义清除默认样式的代码,也可选择引用别人写好的成熟插件Normalize.css来清除默认样式;

2、图片加a标签在IE9中会有边框

解决方案:img{border: none;}

3、IE6及更低版本浮动元素,浮动边双倍边距

解决方案:不使用margin,使用padding

4、IE6及更低版本中,部分块元素拥有默认高度

解决方案:给元素设置font-size: 0;

5、a标签蓝色边框

解决方案:a{outline: none;}

6、IE6不支持min-height属性

解决方案:{min-height: 200px; _height: 350px;}

7、IE9以下浏览器不能使用opacity

解决方案:Firefox/Chrome/Safari/Opera浏览器使用opacity;IE浏览器使用filter

opacity: 0.7; /*FF chrome safari opera*/
filter: alpha(opacity:70); /*用了ie滤镜,可以兼容ie*/

8、IE6/7不支持display:inline-block

解决方案:{display: inline-block; *display: inline;}

9、cursor兼容问题

解决方案:统一使用{cursor: pointer;}

10、IE6/7中img标签与文字放一起时,line-height失效的问题

解决方案:文字和<img>都设置float

11、table宽度固定,td自动换行

解决方案:table设置 {table-layout: fixed},td设置 {word-wrap: break-word}

12、相邻元素设置margin边距时,margin将取最大值,舍弃小值

解决方案:不让边距重叠,可以给子元素加一个父元素,并设置该父元素设置:{overflow: hidden}

13、a标签css状态的顺序

解决方案:按照link--visited--hover--active的顺序编写

14、IE6/7图片下面有空隙的问题

解决方案:img{display: block;}

15、ul标签在Firefox中默认是有padding值的,而在IE中只有margin有值

解决方案:ul{margin: 0;padding: 0;}

16、IE中li指定高度后,出现排版错误

解决方案:设置line-height

17、ul或li浮动后,显示在div外

解决方案:清除浮动;须在ul标签后加<div style="clear:both"></div>来闭合外层div

18、ul设置float后,在IE中margin将变大

解决方案:ul{display: inline;},li{list-style-position: outside;}

19、li中内容超过长度时,用省略号显示

li{
    width: 200px;
    white-space: nowrap;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    overflow: hidden;
}

20、div嵌套p时,出现空白行

解决方案:li{display: inline;}

21、IE6默认div高度为一个字体显示的高度

解决方案:{line-height: 1px;}或{overflow: hidden;}

22、在Chrome中字体不能小于10px

解决方案:p{font-size: 12px; transform: scale(0.8);}

23、谷歌浏览器上记住密码后输入框背景色为黄色

input{
    background-color: transparent !important;
}
input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill{
    -webkit-text-fill-color: #333 !important;
    -webkit-box-shadow: 0 0 0 1000px transparent inset !important;
    background-color: transparent !important;
    background-image: none !important;
    transition: background-color 5000s ease-in-out 0s;
}

24、CSS3兼容前缀表示

写法

内核

浏览器

-webkit-

webkit渲染引擎

chrome/safari

-moz-

gecko渲染引擎

Firefox

-ms-

trident渲染引擎

IE

-o-

opeck渲染引擎

Opera

如:

  .box{
       height: 40px;
       background-color: red;
       color: #fff;
       -webkit-border-radius: 5px; // chrome/safari
       -moz-border-radius: 5px; // Firefox
       -ms-border-radius: 5px; // IE
       -o-border-radius: 5px; // Opera
       border-radius: 5px;
   }

JS兼容问题

1、事件对象的兼容

e = ev || window.event

2、滚动事件的兼容

scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

3、阻止冒泡的兼容

  if (e.stopPropagation) {
      e.stopPropagation();
  } else {
      e.cancelBubble=true;
  }

4、阻止默认行为的兼容

  if (e.preventDefault) {
      e.preventDefault();
  } else {
      e.returnValue = false;
  }

5、添加事件监听器的兼容

  if (target.addEventListener) {
      target.addEventListener("click", fun, false);
  } else {
      target.attachEvent("onclick", fun);
  }

6、ajax创建对象的兼容

  var xhr = null;
  if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
  } else {
      xhr = new ActiveXObject("Microsoft XMLHTTP");
  } 

7、鼠标按键编码的兼容

function mouse (ev) {
      var e = ev || window.event; 
      if (evt) {
          return e.button;
      } else if (window.event) {
          switch (e.button) {
              case 1: return 0;
              case 4: return 1;
              case 2: return 2;
          }
      }  
}

8、在IE中,event对象有x,y属性,Firefox中与event.x等效的是event.pageX,而event.pageX在IE中又没有

x = event.x ? event.x : event.pageX;

9、在IE下,event对象有srcElement属性,但是没有target属性;Firefox下,event对象有target属性,但是没有srcElement属性

var source = ev.target || ev.srcElement;
var target = ev.relatedTarget || ev.toElement;

10、在Firefox下需要用CSS禁止选取网页内容,在IE用JS禁止

-moz-user-select: none; // Firefox 
obj.onselectstart = function() {return false;} // IE

11、innerText在IE中能正常工作,但在FireFox中却不行

if (navigator.appName.indexOf("Explorer") > -1) {
    document.getElementById('element').innerText = "IE";
} else {
    document.getElementById('element').textContent = "Firefox";
}

12、在Firefox下,可以使用const关键字或var关键字来定义常量;在IE下,只能使用var关键字来定义常量

解决方案:统一使用var关键字来定义常量

移动端兼容问题

1、禁止iOS识别长串数字为电话

解决方案:<meta content="telephone=no" name="format-detection" />

2、禁止iOS弹出各种操作窗口

解决方案:-webkit-touch-callout:none

3、禁止Android手机识别邮箱

解决方案:<meta content="email=no" name="format-detection" />

4、禁止iOS和Android用户选中文字

解决方案:-webkit-user-select:none

5、iOS下取消input在输入的时候英文首字母的默认大写

解决方案:<input autocapitalize="off" autocorrect="off" />

6、Android下取消输入语音按钮

解决方案:input::-webkit-input-speech-button {display: none}

7、在移动端修改难看的点击的高亮效果,iOS和安卓下都有效

解决方案:* {-webkit-tap-highlight-color:rgba(0,0,0,0);}

8、iOS下input为type=button属性disabled设置true,会出现样式文字和背景异常问题

解决方案:使用opacity=1;

9、input为fixed定位,在iOS下input固定定位在顶部或者底部,在页面滚动一些距离后,点击input(弹出键盘),input位置会出现在中间位置

解决方案:内容列表框也是fixed定位,这样不会出现fixed错位的问题

10、移动端字体小于12px使用四周边框或者背景色块,部分安卓文字偏上bug问题

解决方案:可以使用整体放大1倍(width、height、font-size等等),再使用transform缩放

11、在移动端图片上传图片兼容低端机的问题

解决方案:input 加入属性accept="image/*" multiple

12、在Android上placeholder文字设置行高会偏上

解决方案:input有placeholder情况下不要设置行高

13、overflow: scroll或auto;在iOS上滑动卡顿的问题

解决方案:加入-webkit-overflow-scrolling: touch;

14、iOS中日期如:2022-02-22 00:00:00格式的时间转时间戳不成功

解决方案:需要将时间中的'00:00:00去除之后才能转为时间戳'

15、iOS中需要将时间格式转为/,如:2022/02/22

let date = '2022-02-22';
let dateStr = date.replace(/-/g, '/'); // 2022/02/22

16、移动端click300ms延时响应

解决方案:使用Fastclick

window.addEventListener( "load", function() { 
    FastClick.attach( document.body ); 
}, false );

17、移动端1px边框问题

解决方案:原先元素的border去掉,然后利用:before或者:after重做border,并transform的scale缩小一半,原先的元素相对定位,新做的border绝对定位

.border-1px{ 
    position: relative; 
    border:none; 
}

.border-1px:after{
    content: '';
    position: absolute; 
    bottom: 0;
    background: #000;
    width: 100%; 
    height: 1px;
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0; 
}

至此,关于浏览器兼容性问题的相关知识和解决方案就聊完了,最后还穿插了关于移动端兼容的问题描述,肯定还有很多没有总结到的兼容性问题,希望xdm在下方评论↘提供。

看文至此,顺手点个赞再走呗,3Q^_^

后语

伙伴们,如果觉得本文对你有些许帮助,点个或者➕个关注在走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。

猪脚本(原飞猪脚本)以按键精灵教学为主,涉及UiBot,Python,Lua等脚本编程语言,教学包括全自动办公脚本,游戏辅助脚本,引流脚本,网页脚本,安卓脚本,IOS脚本,注册脚本,点赞脚本,阅读脚本以及网赚脚本等各个领域。想学习按键精灵的朋友可以添加金猪脚本粉丝交流群:554127455 学习路上不再孤单,金猪脚本伴你一同成长.

1.什么是网页元素特征字符串?

请参考网页特征字符串详解;

2.Html系列命令

2.1.HtmlSelect命令

1)HtmlSelect命令只能够根据Select项的值来进行选择,注意这里不是显示在Select项上的文字,而是该项的value。

一个典型的下拉框HTML代码如下:

<select name="city">

<option value="1">北京</option>

<option value="2">上海</option>

<option value="3">广州</option>

</select>

这里如果要选择上海,需要选择值为2的项;

2)级联的下拉列表组合。

在有的网页中,会有几个级联的下拉列表,后一个下拉框会随前一个框的值变化而发生变化,典型的有注册页面上的省份城市选择,HtmlSelect命令能够触发Onchange事件,会导致后一个下拉框值发生变化,但是如果执行脚本太快,而导致后一个未能选中正确的值,可以在前一个HtmlSelect后加上适当的延时;

3)多选表单中的列表控件;有的列表支持多选,在有一些个求职网站中,职业是可以多选的,这时候可以用%将多个需要选择的值连接起来传递给HtmlSelect命令实现多选;

2.2.HtmlExists命令

HtmlExists命令,能够判断指定特征的元素是否存在,并能够返回具备该特征的元素的个数。这个命令能够用来判断某个元素是否存在,如果为0证明不存在;

2.3.HtmlGet命令

HtmlGet命令比较复杂,但是功能也非常强大,该命令具备两个参数,第一个参数为获取类型,目前支持的值如下所示:

序号 值 适用对象

1 text 得到指定元素的文本值,对应DOM属性innerText

2 html 得到指定元素内部的HTML代码,对应DOM属性innerHTML

3 outerHtml 得到元素整体的HTML代码,对应DOM属性的outerHTML

4 value 得到元素的Value值,用于获取表单元素内部的值

5 src 得到图像元素的src属性,用于IMG标签对象

6 href 得到链接元素的链接地址,用于A标签

7 …其他名称 其他属性,如果您使用的是合法的属性名称,就能够返回对应的值。如何才是合法的属性?请参阅HTML标准。

第二个参数为特征字符串,如果匹配多个,只能返回第一个元素的值;

例如,获得淘宝货物价格:

Plugin price=Web.HtmlGet("text","id:id_Price")

获取某个表单文本的值

Plugin email=Web.HtmlGet("value","name:Email")

2.4.RunJS命令

RunJS命令提供了直接运行Javascript的功能,如果您对JS非常熟悉,就能够极大的扩展WQM的功能。

RunJS命令支持两中执行方式,第一个参数设置为0时,能够执行一段没有返回值的Javascript,

例如:

RunJS(0,"alert('hello');")

第一个参数设置为1时,能执行一段js并返回由return语句返回的值,返回值为字符串类型;

例如:返回Html文档的title;

RunJS(1,"var t=document.title;return t;")

如果您分析到网页中某个按钮实际上就是执行了一个函数,例如

<input type="Button" … />

您就可以直接调用

RunJS(0,"dosomething();")

JQuery的支持,网页按键精灵集成了Jquery1.3.2,为了不与其他JQ的库发生冲突,使用了wqmjq来代替$操作符,如果您需要直接使用JQ来操作网页,可使用wqmjq来执行Jquery语句:

RunJS(0,"wqmjq('#test').click();")


上一篇:HTML 列表
下一篇:Html5实现下拉菜单