Javascript DOM编程艺术读书笔记12

综合示例

导航栏

  • 不同页面的导航栏拥有不同的样式,当前页面的导航栏应该颜色更深

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
function highlightPage() {
if (!document.getElementsByTagName) return false;
if (!document.getElementById) return false;
var headers = document.getElementsByTagName('header');
if (headers.length == 0) return false;
var navs = headers[0].getElementsByTagName('nav');
if (navs.length == 0) return false;
//取得导航链接,然后循环遍历它们
var links = navs[0].getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
var linkurl;
for (var i=0; i<links.length; i++) {
//取得链接中的URL
linkurl = links[i].getAttribute("href");
//window.location.href取得当前页面的URL。String.indexOf(substring)返回字符串第一次出现的位置,用于在字符串中寻找子字符串的位置。比较当前链接的URL与当前页面的URL
if (window.location.href.indexOf(linkurl) != -1) {
//如果找到就添加here类
links[i].className = "here";
//取得当前链接的文本,将其转换成小写形式。如果链接中的文本是"Home",那么linktext的值是home。
var linktext = links[i].lastChild.nodeValue.toLowerCase();
//为body添加上id属性,可以为不同弄的页面设置不同的页面头部
document.body.setAttribute("id",linktext);
}
}
}
}

z-index

  • z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。
  • Z-index 仅能在定位元素上奏效(例如 position:absolute;)

内部导航

  • 点击内部导航,只出现对应的那一部分内容,其他的内容不可见。
  • 1.传入元素ID,设置其可见,其余不可见。修改每个部分的display属性,除了作为参数传入的id对应的部分,其他部分的display属性都被设置成“none”,而与传入id对应的那个部分的display属性被设置成block。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function showSection(id) {
    var sections = document.getElementsByTagName("section");
    for (var i=0; i<sections.length; i++ ) {
    if (sections[i].getAttribute("id") != id) {
    sections[i].style.display = "none";
    } else {
    sections[i].style.display = "block";
    }
    }
    }
  • 2.设置onclick点击事件,传入需要可见部分的元素ID。<article><nav><li><a href="#jay">Jay Skript</a></li></nav></article> 需要在

    中的

    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
    function prepareInternalnav() {
    if (!document.getElementsByTagName) return false;
    if (!document.getElementById) return false;
    var articles = document.getElementsByTagName("article");
    if (articles.length == 0) return false;
    var navs = articles[0].getElementsByTagName("nav");
    if (navs.length == 0) return false;
    var nav = navs[0];
    var links = nav.getElementsByTagName("a");
    for (var i=0; i<links.length; i++ ) {
    // array=string.split(character)数组中的第一个元素是character以前的所有字符,第二个元素是character以后的所有字符
    var sectionId = links[i].getAttribute("href").split("#")[1];
    //确保真的存在相应的id元素
    if (!document.getElementById(sectionId)) continue;
    //页面加载以后,默认隐藏所有部分
    document.getElementById(sectionId).style.display = "none";
    //sectionId是一个局部变量,在onclick事件处理函数时就已经不存在了,可以设置一个属性
    links[i].destination = sectionId;
    //事件处理函数
    links[i].onclick = function() {
    showSection(this.destination);
    return false;
    }
    }
    }

增强表单

  • 点击label元素,关联的表单字段就会获得焦点。并不是所有的浏览器都实现了该行为。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    function focusLabels() {
    if (!document.getElementsByTagName) return false;
    //取得文档的label元素
    var labels = document.getElementsByTagName("label");
    for (var i=0; i<labels.length; i++) {
    //如果label有for属性,添加一个事件处理函数
    if (!labels[i].getAttribute("for")) continue;
    labels[i].onclick = function() {
    //在label被单击时,提取for属性的值,这个值就是相应表单字段的id。
    var id = this.getAttribute("for");
    //确保存在相应的表单字段
    if (!document.getElementById(id)) return false;
    var element = document.getElementById(id);
    //让相应的表单字段获得焦点
    element.focus();
    }
    }
    }

form对象和DOM

  • form.elements返回input、select、textarea以及其他表单字段。childNodes返回表单中的所有节点。
  • 每个表单元素都有自己的一组属性。element.value与element.getAttribute(“value”)等价。

  • 在不支持placeholder属性的浏览器中也能实现就编写如下方法。这个方法与11章的方法类似,只是用的是HTML的form方法,11章用的是DOM方法。

    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
    function resetFields(whichform) {
    //检查浏览器是否支持placeholder属性,如果不支持,继续
    if (Modernizr.input.placeholder) return;
    //循环遍历表单中的每个元素
    for (var i=0; i<whichform.elements.length; i++) {
    var element = whichform.elements[i];
    //如果当前元素是提交按钮,跳过。
    if (element.type == "submit") continue;
    //如果没有placeholder属性,继续。
    if (!element.getAttribute('placeholder')) continue;
    //元素获得焦点的事件添加一个处理函数。如果字段的值等于占位符文本,则将字段的值设置为空
    element.onfocus = function() {
    if (this.value == this.getAttribute('placeholder')) {
    this.value = "";
    }
    }
    //元素失去焦点的事件添加一个处理函数。如果字段的值为空,则将字段的值设置为占位符
    element.onblur = function() {
    if (this.value == "") {
    //为了应用样式,在字段显示占位符值的时候,添加placeholder类
    this.className='placeholder';
    //鉴于不同的浏览器对位置属性的实现方式有所不同。同时使用了DOM placeholder属性和DOM的getAttribute('placeholder')方法
    this.value = this.getAttribute('placeholder')|| this.getAttribute('placeholder');
    }
    }

    element.onblur();
    }
    }

表单验证

使用JS验证表单的注意事项

  1. 验证脚本写的不好,反而不如没有验证
  2. 千万不要完全依赖JS。客户端验证并不能取代服务器端的验证。即使有了JS验证,服务器照样还应该对接收到的数据再次验证。
  3. 客户端验证的目的在于帮助用户填好表单,避免他们提交未完成的表单,从而节省他们的时间。服务器验证的目的在于保证数据库和后台系统的安全。
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
//表单验证
function validateForm(whichform) {
//循环遍历表单的elements数组
for (var i=0; i<whichform.elements.length; i++) {
var element = whichform.elements[i];
//如果发现了required属性,把相应的元素传递给isFilled函数
if (element.getAttribute("required") == 'required') {
if (!isFilled(element)) {
//如果isFilled函数返回false,显示警告信息,并且validateForm函数也返回false
alert("Please fill in the "+element.name+" field.");
return false;
}
}
//如果发现了email类型的字段,把相应的元素传递给isEmail函数
if (element.getAttribute("type") == 'email') {
if (!isEmail(element)) {
//如果isEmail函数返回false,显示警告信息,并且validateForm函数也返回false
alert("The "+element.name+" field must be a valid email address.");
return false;
}
}
}
//否则validateForm返回true
return true;
}

function isFilled(field) {
return (field.value.length > 1 && field.value != field.placeholder);
}

function isEmail(field) {
return (field.value.indexOf("@") != -1 && field.value.indexOf(".") != -1);
}

Ajax

  • 提交表单能够发送一个Ajax请求,感谢信息以嵌入方式添加到表单所在的页面,体验会更好。就是表单提交成功后,不打开新页面了,而是拦截请求,自己显示结果。
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    //创建XMLHttpRequest对象
    function getHTTPObject() {
    if (typeof XMLHttpRequest == "undefined")
    XMLHttpRequest = function () {
    try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
    catch (e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
    catch (e) {}
    try { return new ActiveXObject("Msxml2.XMLHTTP"); }
    catch (e) {}
    return false;
    }
    return new XMLHttpRequest();
    }

    //展示loading图片
    function displayAjaxLoading(element) {
    // 删除所有子元素
    while (element.hasChildNodes()) {
    element.removeChild(element.lastChild);
    }
    // 创建一个图像元素
    var content = document.createElement("img");
    content.setAttribute("src","images/loading.gif");
    content.setAttribute("alt","Loading...");
    // 将图像添加到该元素中
    element.appendChild(content);
    }

    function submitFormWithAjax( whichform, thetarget ) {
    //在修改DOM和显示加载图像之前,首先要检查是否存在有效的XMLHttpRequest对象
    var request = getHTTPObject();
    if (!request) { return false; }
    //调用displayAjaxLoading函数,删除目标元素的子元素,并添加loading.gif图像
    displayAjaxLoading(thetarget);

    //循环遍历表单的每个字段,手机他们的名字和编码后的值
    var dataParts = [];
    var element;
    for (var i=0; i<whichform.elements.length; i++) {
    element = whichform.elements[i];
    dataParts[i] = element.name + '=' + encodeURIComponent(element.value);
    }
    //收集到所有数据后,把数组中的项用和号&连接起来
    var data = dataParts.join('&');
    //向原始表单的action属性指定的处理函数发送post请求
    request.open('POST', whichform.getAttribute("action"), true);
    //并在请求头部添加application/x-www-form-urlencoded头部。这个头部信息对于POST请求是必须的,它表示请求中包含URL编码的表单
    request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    request.onreadystatechange = function () {
    if (request.readyState == 4) {
    if (request.status == 200 || request.status == 0) {
    //数组matches的第一个元素是responseText中的整个模式匹配的部分,即包括<article>和</article>在内的部分
    //数组matches的第二个元素responseText中与补货组中的模式匹配的部分
    var matches = request.responseText.match(/<article>([\s\S]+)<\/article>/);
    if (matches.length > 0) {
    thetarget.innerHTML = matches[1];
    } else {
    thetarget.innerHTML = '<p>Oops, there was an error. Sorry.</p>';
    }
    } else {
    thetarget.innerHTML = '<p>' + request.statusText + '</p>';
    }
    }
    };
    request.send(data);
    return true;
    };

    //提交表单触发的onclick按钮
    function prepareForms() {
    for (var i=0; i<document.forms.length; i++) {
    var thisform = document.forms[i];
    resetFields(thisform);
    thisform.onsubmit = function() {
    //如果表单没有通过验证,就返回false.验证失败,不能提交表单
    if (!validateForm(this)) return false;
    var article = document.getElementsByTagName('article')[0];
    //submitFormWithAjax函数成功发送了Ajax请求并返回true,则让submit事件处理函数返回false,以便阻止浏览器重复提交表单
    if (submitFormWithAjax(this, article)) return false;
    //submitFormWithAjax函数没有成功发送了Ajax请求,故submit事件返回true,让表单 像什么也没有发生一样继续通过页面提交
    return true;
    }
    }
    }

压缩代码

  • 谷歌的closure Compiler可以压缩代码