根据自己2015年阅读清单的总结,大致也映射出2016年学习的总体方向。双12,图灵电子书1折期间,一口气买下了3本Web前端方面的书籍,两本JavaScript相关。既然目标已经如此明确了,那么就要勇敢的跨出第二步,该埋头一门心思钻进去了。

1. 学会改变Style

我并不是第一次接触编程,也并不是第一次接触JavaScript,之前学习过一段时间Java Web,对于基本的Web技术略懂一些,也自学过一段时间Node.js,对Node的相关技术也略懂一些,对于什么HTML、CSS前端技术也略懂一些,所以总结来说:啥也不明白,懵懵懂懂过了好长时间,能写出几个简单的页面,但是从没有完成一个完整的项目,究其原因还是代码量太少,太嫩了。

为什么选择JavaScript?个人比较热衷于Web的相关技术,速度快,做了就能出效果;并且我是一个标准的视觉动物,喜欢一切美好漂亮的事物。当然也想真正拥有那些漂亮的Pages,能完成一些设计的工作更好了,不过这需要的是一种天赋一种感觉,热衷于此,兴趣所在。

学习日志,当然还是要以学习内容为主,记载只是为了自我监督而已。一些特别基础的教程我是没有耐心读下去的,特别讨厌我这种高不成低不就的感觉,希望能再往高爬爬。

学习JavaScript,都是要从操作DOM开始的,这可以说是最基础的了。今天学习的内容就是学会操作DOM。以下例子,或者点击此处实际演示。

<!DOCTYPE html>
<html>
<head>
    <title>Study_JavaScript_001</title>
    <script type="text/javascript" src='001.js'></script>
</head>
<body>
    <a href="lupeng.me" style="font-style: italic">HOME</a>
    <div id="content">
        <p id='test-p'></p>
    </div>
    <button onclick="addSomeText()">addSomeText</button>
    <button onclick="changeStyle()">changeStyle</button>
</body>
</html>

简单的HTML代码,下面是js代码

// 001.js
function addSomeText(){
    var p = document.getElementById("test-p");
    // innerHTML非常重要的属性,往DOM节点里添加任何内容(注意不是绝对)
    p.innerHTML = "Hello,JavaScript!"  
}
function changeStyle(){
    var p = document.getElementById("test-p");
    // 改变style样式,注意驼峰写法
    p.style.fontSize = "2em";  
    p.style.color = "red";
    p.style.fontWeight = "bold";
    p.style.padding = "1em";
    p.style.backgroundColor = "yellow";
    p.style.fontFamily = "fantasy";
    p.style.fontStyle = "italic";
}

总结:

  1. 获取DOM节点,document对象的三个方法,getElementById()getElementsByClassName()getElementsByTagName()
  2. innerHTML属性值,添加的内容可能是文本,亦可以是HTML片段;
  3. 改变样式方法,使用驼峰变量写法;

2. 增删DOM节点

忙真的不是借口,并不能因为忙就把刚刚给自己定下来的学习目标抛之脑后。虽然这周真的很忙,公司一个破项目把我这几个月折腾得够呛,虽说是上线了,但是还是一堆的问题需要解决,大家都懂得,上线不等于就完事,特别是那种被追赶出来的东西。

第一天,主要是学习了修改Style,今天就增删DOM节点的内容来总结一下,其实这个内容跟第一天的内容完全可以合并,由于第一天『励志』要开始学习JavaScript,并记录学习笔记,写了很多的废话,于是就把增删DOM节点的学习内容分开记录了。

1. 增加DOM节点

简单学习过一些数据库的知识,我是知道增删改查的基本概念的,第一天学习了如何查找一个DOM节点,通过
document.getElementById()
document.getElementsByClassName()
document.getElementsByTagName()
可以找到HTML上的DOM节点,那么增加DOM节点呢?

其实这里应该有3中方法来实现。

  1. innerHTML属性值,第一天的时候就知道,在一个节点里添加一些内容,这些内容可以是HTML的片段,这样就相当往节点里增加了其他的DOM节点;
  2. appendChild方法,在父节点中插入一个DOM节点;
  3. insertBefore方法,将一个DOM节点插入到指定的位置上;

知道了方法,就得动手实践了,不动手写代码,估计我永远也提高不了编程水平。实际演示代码点击这里>

2. 删除DOM节点

世界总是平衡的,有正就要有负,有增加就应该有删除,删除节点的方法就相对简单点,除了document.getElementById("xxx").innerHTML = ''之外,还有一个方法。

removeChild方法,跟appendChild相对,实际演示代码点击这里>

下面贴上JavaScript代码便于日后查看,HTML就免了,当然可以直接点击上述链接审查代码。

// 002.js
function add1(){
    //将已有的节点插入到list列表中
    var list = document.getElementById("list");
    var javascript = document.getElementById("javascript");
    javascript.style.color = "red";
    list.appendChild(javascript);
}
function add2(){
    //创建一个节点,并插入到list列表中
    var java = document.createElement("p");
    java.setAttribute("id","java");
    java.innerHTML = "Java";
    list.appendChild(java);
}
function add3(){
    //创建一个节点,并插入到list列表中
    var php = document.createElement("p");
    php.setAttribute("id","php");
    php.innerHTML = "PHP";
    list.insertBefore(php,java);  //将php节点插入到java节点前面
}
function removeSomething(){
    var java = document.getElementById("java");
    var list = document.getElementById("list");
    list.removeChild(java);  //移除指定节点
}

参考内容:JavaScript教程 - 廖雪峰的官方网站

3. DOM节点排序

今天学习笔记内容是DOM节点的排序,要点就是前面两篇的内容,外加上Array的一些内容。

这个例子其实就是JavaScript教程 - 廖雪峰的官方网站中的一个例子,我觉得这个例子非常好,于是记载在这里了。

题目

根据列表的内容,对列表节点进行排序,如下html片段,根据li节点的内容进行排序。

<ol id="test-list">
    <li class="lang">Scheme</li>
    <li class="lang">JavaScript</li>
    <li class="lang">Python</li>
    <li class="lang">Ruby</li>
    <li class="lang">Haskell</li>
    <li class="lang">Html</li>
    <li class="lang">Css</li>
</ol>

解题

这里我总结了大概下列5种解题方案

  1. 直接取出DOM节点,存入一个Array中,然后针对Array进行sort排序,最后依次插入到父节点中;
  2. 取出每个li节点的文本信息,存入Array队列中,然后针对文本进行排序,创建的节点,将文本赋值,替代父节点innerHTML信息;
  3. 前面同2一样,后面不用创建新的节点,直接给父节点的children赋值;
  4. 采用排序算法,直接取出最小或者最大的节点,插入到父节点中;
  5. 采用冒泡排序算法,使用insertBefore方法冒泡处理;(此处参考教程评论处)

OK,代码实践如下,亦或者直接点击此处查看效果。

// 直接将DOM节点保存在Array列表中进行排序
function sortDOM1 () {
    var list = document.getElementById('test-list');
    var arr = [].slice.call(document.getElementsByClassName("lang"));
    arr.sort(function(x1,x2){
        if (x1.innerHTML < x2.innerHTML){
            return -1;
        }else if (x1.innerHTML > x2.innerHTML){
            return 1;
        }else{
            return 0;
        }
    });
    for(var i = 0 ; i < arr.length ; i++){
        list.appendChild(arr[i]);
    }
}
// 先清空,再创建
function sortDOM2(){
    var list = document.getElementById("test-list");
    var lang = document.getElementsByClassName("lang");
    var arrList = [];
    for (var i = 0 ; i < lang.length ; i ++){
        arrList[i] = lang[i].innerHTML;
    }
    arrList.sort();
    list.innerHTML = ""; // 清空一个DOM节点的方法,简单粗暴
    for (var i = 0 ; i < arrList.length ; i ++){
        var newElement = document.createElement("li");
        newElement.setAttribute("class","lang");
        newElement.innerHTML = arrList[i];
        list.appendChild(newElement);
    }
}
// 直接更改children
function sortDOM3(){
    var list = document.getElementById("test-list");
    var lang = document.getElementsByClassName("lang");
    var arrList2 = [];
    for (var i = 0 ; i < lang.length ; i ++){
        arrList2[i] = lang[i].innerHTML;
    }
    arrList2.sort();
    for(var i = 0 ; i < arrList2.length ; i ++){
        list.children[i].innerHTML = arrList2[i];
    }
}
// 排序算法
function sortDOM4 () {
    var list = document.getElementById("test-list");
    var lang = document.getElementsByClassName("lang");
    for (var i = 0 ; i < lang.length-1 ; i++){
        for(var j = i+1 ; j < lang.length ; j ++){  //     取出最大的那个,插入第一个
            if (lang[i].innerHTML < lang[j].innerHTML){
                var a ;
                a = lang[i].innerHTML;
                lang[i].innerHTML = lang[j].innerHTML;
                lang[j].innerHTML = a; 
            }
        }
        list.children[i].innerHTML = lang[i].innerHTML;
    }
}
// 冒泡排序算法
function sortDOM5 (){
    var list = document.getElementById("test-list");
    var lang = document.getElementsByClassName("lang");
    for (var i = 0 ; i < lang.length ; i ++){
        for(var j = 0 ; j < lang.length - i -1 ; j ++){  // 每次遍历次数递减
            if(lang[j].innerHTML > lang[j+1].innerHTML){
                list.insertBefore(lang[j+1],lang[j]);
            }
        }
    }
} 

4. 添加选项界面

朋友圈里看到一句戳心窝的话:『间歇性踌躇满志,持续性混吃等死』

坚持下去总是好的,永远记住当时你为什么有那么一会的踌躇满志,不管什么理由,反正是不想要现在的状态。

今天是对前面学习内容的一个小结,这个小内容其实在很早之前就一直想完成了,当然之前只是一直想,想,想...

内容就是完成一个『添加选项的界面』,很多地方都会用到这个小功能模块,基本功能就是一个表单,可以随时添加选项,同时可以随时删除选项。

功能很简单,对于代码量少得可怜的我来说,实实在在写出来才是最真实的。

<form id="test-form">
      <ol id = "test-ol"></ol>
      <button onclick="addOption()">Add</button>
</form>

页面就是这么简单,一个表单,一个按钮,接下来就是JS的上场时间了。

var count = 1    ;
function addOption () {
    var form = document.getElementById('test-form');
    var ol = document.getElementById('test-ol');
    var li = document.createElement("li");
    li.setAttribute("class","li-options");
    li.id = "li" + count;
    var input = document.createElement("input");
    input.setAttribute("class","options");
    input.setAttribute("type","text");
    var button = document.createElement("button");
    button.innerHTML = "Remove";
    button.setAttribute("class","removeButton");
    button.id = count;
    button.setAttribute("onclick","removeOption(this.id)");

    ol.appendChild(li);
    li.appendChild(input);
    li.appendChild(button);
    count ++;
}
function removeOption(iCount){
    var ol = document.getElementById("test-ol");
    var removeId = "li" + iCount;
    var needRemove = document.getElementById(removeId);
    ol.removeChild(needRemove);
}

添加的功能很容易,跟之前的内容结合起来就很容易实现了;移除功能需要想想办法了,这里使用了一个变量count来定位到底是哪个remove按钮点击了,传入this.id到函数removeOption中,然后删除对应的li节点。

查看效果直接点击此处,也许写的方法有些笨,但是最终还是实现基本的要求,后续更加深入学习再回头看看之前的代码应该也是很有乐趣的吧。

5. 表单验证

根据一万个小时的理论,也就是说不管是什么内容,持续坚持学习一万个小时,你也就变成了个中高手。那么一个万个小时是多长概念呢,对于一个业余爱好来说大概是多长时间呢?假设每天能平均抽出2个小时来学习,那麽一年下来是:2*365=730小时,一万个小时就是10000/730=13.7年。哇,不想了,接着学习吧,如果真的喜欢,那便是快乐,与其他无关。

今天学习的内容是表单验证,这个要多普遍就有多普遍,基本上所有的网站都要用到这个。注册、登录、评论等等,只要是想往服务器POST信息的,基本上都要用到form,好了,接着看例子。

<form action="#" id="test-form" onsubmit="return checkForm()">
  <div><span class="text">username:</span><input type="text" name="username" id="username"></div>
  <div><span class="text">password:</span><input type="text" name="password" id="password"></div>
  <div><span class="text">re-password:</span><input type="text" name="password2" id="password2"></div>
  <div id="error" class="text"></div>
  <button type="submit" name="submit">Submit</button>
  <button type="reset" name="reset">Reset</button>
</form>

用户名,密码是注册登录界面最基本的元素,还有好多基本的元素就不一一写出来了,那些东西都是练习得多了,自然就会了。关键还是在代码量。

实现功能:

  1. 用户名要求数字,字母3-10位;
  2. 密码要求6-12位;
  3. 两次密码输入要一致;

第一个要点要使用到正则表达式来匹配

  • 用户名匹配用/^[0-9a-zA-Z]{3,10}$/
  • 密码匹配用到/^.{6-12}$/

第二个要点就是表单提交的方法

  • 一是使用了表单的submit()方法;
    document.getElementById("formId").submit()
  • 二是浏览器默认提交方法<button type="submit">,使用submit类型的button按钮来提交,这种方法需要在form中添加onsubmit属性值。

主要内容就是这些,那么接下来就是代码实现了。

function checkForm() {
  var form = document.getElementById('test-form');
  var username = document.getElementById("username").value;
  var password = document.getElementById("password").value;
  var rePassword = document.getElementById('password2').value;
  var error = document.getElementById('error');
  // 不允许为空
  if (username.length <= 0 || password.length <= 0 || password2 <= 0){
    error.innerHTML = "not allow empty";
    return false;
  }
  // 用户名为字符数字,3到10位
  var reg_username = /^[0-9a-zA-Z]{3,10}$/;
  if(!reg_username.test(username)){
    error.innerHTML = "username is not valid, please retry";  
    return false;
  }
  // 密码需为6到12位
  var reg_password = /^.{6,12}$/;
  if(!reg_password.test(password)){
    error.innerHTML = "password is not valid, please retry";
    return false;
  }
  // 两次输入密码需一致
  if (password != rePassword) {
    error.innerHTML = "inconsistent password";
    return false;
  }
  error.innerHTML = "Success";
  alert("Access Success");
  return true;
}

直接点击这里,查看效果。

6. 函数对象

JavaScript 最令人感兴趣的莫过于函数实际上就是功能完整的对象,JavaScript中所有的事物都是对象,包括函数。函数名只是指向函数对象的一个引用,行为就像其他对象一样。甚至可以使两个变量指向同一个函数,因此函数可以当做参数传递给另外一个函数。

上面是我在学习JavaScript函数对象对我感触最深的一段话,当然这也是JavaScript的特别之处。

1. 创建函数的方法

创建一个函数非常简单,如:

function sayHello(name){
    alert("Hello," + name);
}

既然函数名只是指向函数对象的一个引用,那么就是说sayHello就如同其他变量一样。当然你也可以这样定义一个函数:

var sayHello = function(name){
    alert("Hello..." + name);
}

两种方式得到的效果是一样的,sayHello都是函数对象的一个引用,可以理解为指向一个对象的指针变量。如果对一个变量重新赋值的话,就会改变指针指向的对象。

function sayHello(name){
    alert("Hello," + name);
}
var sayHello = function(name){
    alert("Hello..." + name);
}
sayHello("JavaScript");

这样弹出的窗口肯定是"Hello...JavaScript"而不是"Hello,JavaScript",因为指向的对象变了。

函数实际上就是功能完整的对象,对象是某个类的实例。那么通过Function类肯定也是可以创建一个函数的。

Function类可以创建任何函数,语法如下:

var function_name = new function(arg1, arg2, ..., argN, function_body);

那么上面那个例子就可以表示为:

var sayHello = new function("name", "alert(\"Hello,\" + name);");

看起来就觉得别扭,所以通常情况下不会这么去创建一个函数对象。但是这种方式却很直接的将函数名只是函数对象的一个引用的概念表现出来了,所有函数都应看作Function类的实例。既然函数名只是一个引用,当然就可以将一个函数当作参数变量传递给另一个函数。看下面例子:

function calcSomething(regular,value1,value2){
    alert(regular(value1,value2));
}
function plus(x1,x2){
    return  x1 + x2;
}
function minus(x1,x2){
    return x1 - x2;
}
calcSomething(plus,5,10);
calcSomething(minus,5,10);

plus以及minus当作一个参数传入另外一个函数中。

2. Function对象(类)的属性与方法

每一个对象都有它的属性和方法,既然函数是Function类的一个对象,那么每一个函数都应该继承Function类的属性与方法。比较常见的有length属性以及toString方法。

  1. calcSomething.length等于3,代表有3个参数;
  2. calcSomething.toString()打印出函数主体;

3. 特殊对象arguments

JavaScript还有一个特殊的对象arguments,也就是函数的参数。我们无需指定一个函数的参数,就可以直接访问到它。并且可以接受最多255个参数。看个简单的例子,大致的用法就清楚了。

function addSum(){
    var sum = 0;
    if (arguments.length == 0) {
        return sum;
    }else{
        for (var i = 0; i < arguments.length; i++) {
            sum = sum + arguments[i];
        };
        return sum;
    };
}
  1. arguments.length代表函数参数的个数;
  2. arguments[i]参数列表可以当做数组来访问;

这里只是JavaScript函数对象的初步了解,待后续继续深入学习。

7. DOM事件

前面的例子一直都在使用鼠标的click事件,之前也零零散散的了解过一些事件,诸如:focusmouseover等,这里重新针对这些鼠标事件再学习总结一遍。

JavaScript操作HTML,最重要的知识应该就是这块了,没有这块的相关鼠标事件,真的很难想象JavaScript还能对HTML做些什么。这里就从网页加载开始,系统学习一下这些DOM事件。

1. onload&onunload事件

用户进入或者离开页面时被触发。onload事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。onloadonunload事件可用于处理 cookie。

2. onfocus&onblur&onchange事件

把它们列在一组,是因为在input输入框中比较常用。

  • onfocus获取焦点的时候
  • onblur失去焦点的时候
  • onchange内容被改变的时候

3. onmouseover&onmouseout事件

顾名思义,鼠标悬浮移入移开的时候触发。在动态加载某些内容的时候,较常用。

4. onmousedown&onmouseup&onclick事件

这一组是鼠标点击的一套动作。按下鼠标onmousedown,松开鼠标onmouseup,完成点击onclick。通过这些可以做出很漂亮的效果以及用户体验。

练习时间

实现inputbutton一些最简单的交互动作,例如:点击文本控件时,清空默认文本;点击按钮的时候,突出按钮按钮样式。也许看起来特别简单,但是非常有必要自己写出来。初期代码写得肯定渣,但是随着一步一步学习,相信后续有所改善。查看代码or效果,请点击此处>>>

以上只是列举了我觉得比较常用的一些事件,需要更多的请查看参考手册:HTML DOM Event 对象