WEB開發 JavaScript
1,JavaScript簡介
web前端有三層:
-
HTML:從語義的角度,描述頁面的結構
-
CSS:從審美的角度,描述樣式(美化頁面)
-
JavaScript:從交互的角度,描述行為(提升用戶體驗)
JavaSctipt歷史背景介紹以及發展:

歷史背景介紹
布蘭登 艾奇 1995年在網景公司 發明的JavaScript
一開始的JavaScrip叫LiveScript
同一個時期 比如 VBScript,JScript等,但是后來被JavaScript打敗了,現在的瀏覽器只運行一種腳本語言叫JavaScript
JavaScript的發展
2003年之前,JavaScript被認為“牛皮鮮”,用來制作頁面上的廣告,彈窗、漂浮的廣告。什么東西讓人煩,什么東西就是JavaScript開發的。所以瀏覽器就推出了屏蔽廣告功能。
2004年,JavaScript命運開始改變,那一年,谷歌公司開始帶頭使用Ajax技術,Ajax技術就是JavaScript的一個應用。並且,那時候人們逐漸開始提升用戶體驗了。Ajax有一些應用場景。比如,當我們在百度搜索框搜文字時,輸入框下方的智能提示,可以通過Ajax實現。比如,當我們注冊網易郵箱時,能夠及時發現用戶名是否被占用,而不用調到另外一個頁面。
2007年喬布斯發布了第一款iPhone,這一年開始,用戶就多了上網的途徑,就是用移動設備上網。JavaScript在移動頁面中,也是不可或缺的。並且這一年,互聯網開始標准化,按照W3C規則三層分離,JavaScript越來越被重視。
2010年,人們更加了解HTML5技術,HTML5推出了一個東西叫做Canvas(畫布),工程師可以在Canvas上進行游戲制作,利用的就是JavaScript。
2011年,Node.js誕生,使JavaScript能夠開發服務器程序了。
React-native inoic
如今,WebApp已經非常流行,就是用網頁技術開發手機應用。手機系統有iOS、安卓。比如公司要開發一個“攜程網”App,就需要招聘三隊人馬,比如iOS工程師10人,安卓工程師10人,前端工程師10人。共30人,開發成本大;而且如果要改版,要改3個版本。現在,假設公司都用web技術,用html+css+javascript技術就可以開發App。也易於迭代(網頁一改變,所有的終端都變了)。
雖然目前WebApp在功能和性能上的體驗遠不如Native App,但是“WebApp慢慢取代Native App”很有可能是未來的趨勢。
JavaScript的組成
-
ECMAScript 5.0:定義了js的語法標准: 包含變量 、表達式、運算符、函數、if語句 for循環 while循環、內置的函數
-
DOM(Document,文檔模型) :操作網頁上元素的API。比如讓盒子顯示隱藏、變色、動畫 form表單驗證
-
BOM(瀏覽器對象模型):操作瀏覽器部分功能的API。比如刷新頁面、前進后退、讓瀏覽器自動滾動
2,ECMASctipt 5.0
前端常用開發工具:sublime、visual Studio Code、HBuilder、Webstorm。
那么大家使用的PCharm跟WebStorm是JetBrains公司推出的編輯工具,開發階段建議使用。
1,JS的引入方式
內接式:
<script type="text/javascript"> </script>
外接式:
<!--相當於引入了某個模塊--> <script type="text/javascript" src = './js/index.js'></script>
注意:
調試語句:
alert(''); 彈出警告框 console.log(''); 控制台輸出
js中單行注釋的快捷鍵是ctrl+/. 多行注釋的快捷鍵是ctrl+shift+/
2,變量的聲明
在js中使用var關鍵字進行變量的聲明,注意,分號作為一句話代碼的結束符。
var a = 100;
- 定義變量:var就是一個關鍵字,用來定義變量。所謂關鍵字,就是有特殊功能的小詞語。關鍵字后面一定要有空格隔開。
- 變量的賦值:等號表示賦值,將等號右邊的值,賦給左邊的變量。
- 變量名:我們可以給變量任意的取名字。
變量要先定義,才能使用。比如,我們不設置變量,直接輸出:
<script type="text/javascript"> console.log(a); </script> //這段代碼控制台將會報錯。
應該這么寫:
var a; //先定義 a = 100; // 后賦值 //也可以直接定義變量+賦值 var a = 100;
如果聲明了,但是沒有定義,則只會顯示undefine,不會報錯。
變量的命名規范
只能由英語字母、數字、下划線、美元符號$構成,且不能以數字開頭,並且不能是JavaScript保留字。
3,基本數據類型
五種基本數據類型:number,string,boolean,null,undefined
復雜(引用)數據類型:Function,Object,Arrary,Sting,Date(分別類似於python中的def,dict,list,string,time模塊)
①number:數值類型
如果一個變量中,存放了數字,那么這個變量就是數值型的
var a = 100; //定義了一個變量a,並且賦值100 console.log(typeof a); //輸出a變量的類型 使用typeof函數 檢測變量a的數據類型 //特殊情況 var b = 5/0; console.log(b); //Infinity 無限大 console.log(typeof b); //number 類型
ps:在JavaScript中,只要是數,就是數值型(number)的。無論整浮、浮點數(即小數)、無論大小、無論正負,都是number類型的。
②string:字符串類型
var a = 'qiuma'; //單引號和雙引號都可以表示字符串 console.log(typeof a); //srting類型 //對於未聲明的字符串,瀏覽器不會報錯,也不會顯示類型。 var a = "";
連字符和+號的區別
鍵盤上的 +
可能是連字符,也可能是數字的加號。如下:
console.log("我" + "愛" + "你"); //連字符,把三個獨立的漢字,連接在一起了 console.log("我+愛+你"); //當字符串處理,原樣輸出 console.log(1+2+3); //輸出6
將數值類型轉換成字符類型:
var c = 10+''; console.log(typeof c); //此時在瀏覽器控制台中的 c 則是字符串類型了
③boolean:布爾類型
var isShow = flase; console.log(typeof isShow); var a = 1==1; console.log(typeof a); //這些都是布爾類型,和python中類似
④null:空對象
var c1 = null;//空對象 瀏覽器顯示object對象 console.log(typeof c1);
⑤undefined:未定義
var d1; //表示變量未定義,值為undefined console.log(typeof d1);
4,運算符
①賦值運算符
以var x = 12,y=5來演示示例
②算數運算符
var a = 5,b=2;
③比較運算符
var x = 5;
④注意:
== 是比較值的相同。不參與比較數據類型
var x = 5; var y = '5'; console.log(x==y); //比較值是相同的,這里返回true
=== 等同於,是比較的是值和數據類型(內存地址)
console.log(x===y); //這里返回的是false
運算注意點:
var a = 5; var b = a++; console.log(a); console.log(b); //這里得到的結果是,a=6,b=5; //在這里,是先將a的值賦值給b輸出,然后再對a++進行運算,然后此時先得出b=5,a=6。 var b = ++a; console.log(a); console.log(b); //此時結果為:a=6,b=6; //這里是先將a++進行運算,再將a輸出 //++在前,先進行運算后賦值,++在后面,后進行運算。
在自增中適用此運算法則,在自減中同樣適用。
5,數據類型轉換
①將number類型轉換成string類型
隱式轉換
一個數字加上字符串,默認轉換成字符串類型
var n1 = 123; var n2 = '123'; var n3 = n1+n2; // 隱式轉換 console.log(typeof n3);
強制轉換
// 強制類型轉換String(),toString() var n1 = 123; var str1 = String(n1); console.log(typeof str1); //返回了一個字符串類型 var num = 234;
var numStr = num.toSting(); console.log(typeof numStr); //返回一個字符串類型
②將string類型轉換成number類型
var srtingNum = '121212';
var num = Number(srtingNum);
console.log(num); //返回121212
console.log(typeof num); //返回number
var stringNum = '789.123wadjhkd'; var num2 = Number(stringNum); console.log(num2); //返回NaN 表示Not a Number 但是一個number類型
console.log(typeof num2); //返回number // parseInt()可以解析一個字符串,並且返回一個整數,注意只保留開始前面的那一段整數 console.log(parseInt(stringNum)); //789
// parseFloat()可以解析一個字符串,返回一個浮點類型,保留開始前面那段數字
console.log(parseFloat(stringNum)); //789.123
6,流程控制
①if
var age = 20; if(age>18){ //{}相當於作用域 console.log('可以去會所'); } alert('qiuma'); //下面的代碼照樣執行
②if-else
var age = 20; if(age>18){ //{}相當於作用域 console.log('可以去會所'); }else{ console.log('好好學js,年紀夠了再去會所'); } alert('qiuma'); //下面的代碼照樣執行
③if-else if -else
var age = 18; if(age==18){ //{}相當於作用域 console.log('可以去會所'); }else if(age==30){ console.log('該娶媳婦了!!'); }else{ console.log('隨便你了') } alert('qiuma'); //下面的代碼照樣執行
④邏輯與 &&,邏輯或 ||

邏輯與&&、 邏輯或|| //1.模擬 如果總分 >400 並且數學成績 >89分 被清華大學錄入 //邏輯與&& 兩個條件都成立的時候 才成立 if(sum>400 && math>90){ console.log('清華大學錄入成功') }else{ alert('高考失利') } //2.模擬 如果總分>400 或者你英語大於85 被復旦大學錄入 //邏輯或 只有有一個條件成立的時候 才成立 if(sum>500 || english>85){ alert('被復旦大學錄入') }else{ alert('高考又失利了') }
⑤switch(開關)語句
var gameScore = 'better'; switch(gameScore){ //case表示一個條件 滿足這個條件就會輸出,知道遇到break跳出。break終止循環。 //如果某個條件中不寫 break,那么直到該程序遇到下一個break停止,這個就是'case穿透' case 'good': console.log('玩的很好') //break表示退出 break; case 'better': console.log('玩的老牛逼了') break; case 'best': console.log('恭喜你 吃雞成功') break; default: console.log('很遺憾') } //注意:switch相當於if語句 但是玩switch的小心case穿透
//default相當於else
⑥while循環
任何語言的循環離不開這三步:
- 初始化循環變量
- 判斷循環條件
- 更新循環變量
// 例子:打印 1~9之間的數 var i = 1; //初始化循環變量 while(i<=9){ //判斷循環條件 console.log(i); i = i+1; //更新循環條件 }
⑦do while
var i = 3; do{ console.log(i); i+=1; }while(i<10); //用途不大,就是不管條件如何,一上來先做一次,然后再去循環。
⑧for循環
for循環遍歷列表,是最常用的對數據的操作
//輸出1-10之間的數 for(var i = 1;i <=10;i++){ console.log(i) } //輸入1-100之間的所有數之和 var sum = 0; for(var j = 1;j<=100;j++){ sum = sum + j } console.log(sum);
//輸入1-100內的所有偶數
for(var i = 1; i <= 100;i++){
if(i%2==0){
console.log(i)
}
}
雙重for循環
document.write(" ");往頁面上寫入內容
for(var i=1;i<=3;i++){ for(var j=0;j<6;j++){ //控制星星的數量 document.write('*') } document.write('<br>') //控制換行 }
在瀏覽器中輸出直三角形:

for(var i = 1;i <= 6;i++){ for(var j = 1;j <= i;j++) { document.write('*'); } document.write('<br>'); }
在瀏覽器中輸出等腰三角形:

for(var i=1;i<=6;i++){ //控制行數,一共顯示6行 記得換行 document.write('<br>'); //控制我們的空格數 for(var s=i;s<6;s++){ document.write(' '); } //控制每行的輸出*數 for(var j=1;j<=2*i-1;j++){ document.write('*'); } document.write('<br>'); }
7,復雜數據類型
五種基本數據類型:number,string,boolean,null,undefined
復雜(引用)數據類型:Function,Object,Arrary,Sting,Date(分別類似於python中的def,dict,list,string,time模塊)
常用內置對象(復雜數據類型),所謂內置對象就是ECMAScript提供出來的一些方法,且都有相應的屬性和方法。
1,Array: 數組
js中的數組和python中的列表類似
①數組的創建
字面量方式創建,簡單粗暴
var colors = ['red','green','yellow'];
js中,所有的變量都掛載到了全局對象window中。
我們在瀏覽器開發者工具的console中,這里可以作為瀏覽器的一個解釋器來使用。
當直接在下面輸入window.colors同樣等於在解釋器中的代碼console.log(colors); 會顯示相同的結果。
在解釋器中,console.log(colors); = console.log(window.colors); 只是在平時,這個window我們一般省略不寫。
使用構造函數的方式創建
使用new關鍵詞對構造函數(js中創建對象)的方式來創建,構造函數與面向對象有關系。
var colors = new Array();
console.log(colors); //通過下標進行賦值 colors[0] = 'red'; colors[1] = 'green'; colors[2] = 'yellow'; console.log(colors);
遍歷列表:
for(var i = 0;i < colors.length;i++){ console.log(i,colors[i]); }
②數組的常用方法
下面為具體方法:
⑴concat(); 數組的合並
var north = ['北京','山東','天津']; var south = ['東莞','深圳','上海']; var newCity = north.concat(south); console.log(newCity)
⑵join(' '); 連接
將數組中元素使用指定的字符串連接起來,它會形成一個新的字符串
var score = [98,78,76,100,0]; var str = score.join('|'); console.log(str);//"98|78|76|100|0"
⑶slice(); 返回數組的一段記錄
slice(start,end); 返回數組的一段記錄,相當於切片,顧頭不顧尾
var arr = ['張三','李四','王文','趙六']; var newArr = arr.slice(1,3); console.log(newArr);//["李四", "王文"]
⑷pop 移除數組的最后一個元素
var arr = ['張三','李四','王文','趙六']; arr.pop(); console.log(arr);//["張三", "李四","王文"]
⑸push() 向數組最后添加一個元素
var arr = ['張三','李四','王文','趙六']; arr.push('小馬哥'); console.log(arr);//["張三", "李四","王文","趙六","小馬哥"]
⑹reverse() 反轉數據
var names = ['alex','xiaoma','tanhuang','angle']; names.reverse(); console.log(names);
⑺sort() 對數組排序
var names = ['alex','xiaoma','tanhuang','abngel']; names.sort(); console.log(names);// ["alex", "angle", "tanhuang", "xiaoma"]
⑻isArray() 判斷是否為數組,返回為 true | false
//布爾類型值 = Array.isArray(被檢測的值) ; var iArray = Array.isArray(iArray) if(iArray){ console.log('是數組') }else{ console.log('不是數組') } //是數組
⑼forEach(fn) 回調函數
forEach中的函數是一個匿名函數,同時也稱為一個回調函數。可以用在遍歷函數。
這是一個數組方法,是一個回調函數,匿名函數,通過forEach遍歷數組的每一項內容,回調函數中的參數,第一個參數為item(每一項內容)第二個參數是數組的索引。
var names = ['qiuma', 'zhengmi', 'touji'] names.forEach(function(item, index){ console.log(item); console.log(index); }) //執行結果 qiuma 0 zhengmi 1 touji 2
2,string: 字符串
⑴chartAt() 返回指定索引的位置的字符
var str = 'qiuma'; var charset = str.charAt(3); console.log(charset);//m
⑵concat 返回字符串值,表示兩個或多個字符串的拼接
var str1 = 'qiu'; var str2 = 'ma'; console.log(str1.concat(str2,'|',str1,str2));//qiuma|qiuma
⑶replace(a,b) 將字符串b替換成字符串a
var a = '1234567755'; var newStr = a.replace("4567","****"); console.log(newStr);//123****755
⑷indexof() 查找字符的下標,如果找到返回字符串的下標,找不到則返回-1 。跟seach()方法用法一樣
var str = 'alex'; console.log(str.indexOf('e'));//2 console.log(str.indexOf('p'));//-1
⑸slice(start,end) 左閉右開 分割字符串
var str = '小馬哥'; console.log(str.slice(1,2));//馬
⑹split('a',1) 以字符串a為分割字符串,並返回新的數組。如果第二個參數沒寫,表示返回整個數組,如果定義了個數,則返回相應個數的數組(從左往右數),如果是0,則返回一個空的數組,如果大於實際數字個數,則返回全部數組。
var str = '我的天呢,a是嘛,你在說什么呢?a哈哈哈'; console.log(str.split('a'));//["我的天呢,", "是嘛,你在說什么呢?", "哈哈哈"]
⑺substr(statr,end) 左閉右開
var str = '我的天呢,a是嘛,你在說什么呢?a哈哈哈'; console.log(str.substr(0,4));//我的天呢
⑻toLowerCase()轉小寫
var str = 'XIAOMAGE'; console.log(str.toLowerCase());//xiaomage
⑼toUpperCase()轉大寫
var str = 'xiaomage'; console.log(str.toUpperCase());//XIAOMAGE
特別:
//1.將number類型轉換成字符串類型 var num = 132.32522; var numStr = num.toString() console.log(typeof numStr)
//四舍五入 var newNum = num.toFixed(2) console.log(newNum)//132.32
//去除字符串中的前后空格
var str1 = ' qiuma ';
console.log(str1.trim());//qiuma
//創建一個空的字符串
var str = new String();
str[0] = 'a';
console.log(str);
不能用var str = ''; 創建
8,Math內置對象
⑴Math.ceil() 向上取整,'天花板函數'
var x = 1.234; //天花板函數 表示大於等於 x,並且與它最接近的整數是2 var a = Math.ceil(x); console.log(a);//2
//對頁面進行分頁設置
var = pageNum = 12345/30;
console.log(Math.ceil(pageNum));//如未取整,則得到的是一個小數
⑵Math.floor 向下取整,'地板函數'
var x = 1.234; // 小於等於 x,並且與它最接近的整數 1 var b = Math.floor(x); console.log(b);//1
⑶求兩個數的最大值和最小值
//求 兩個數的最大值 最小值 console.log(Math.max(2,5));//5 console.log(Math.min(2,5));//2
⑷隨機數 Math.random(),取值范圍是[0,1)。求min-max之間的隨機數 min + Math.random()*(max-min);
var ran = Math.random(); console.log(ran); //求200-500的數 console.log(200+Math.random()*300); //200加上300和隨機數的乘積。
9,函數的使用
函數:就是把將一些語句進行封裝,然后通過調用的形式,執行這些語句。命令打包,然后方便調用。
函數的作用:
- 解決大量的重復性的語句
- 簡化編程,讓編程模塊化
# python 中聲明並調用函數 def add(x,y): return x+y print(add(1,2)) //js中聲明並調用函數 function add(x,y){ return x+y; } console.log(add(1,2));
具體解釋:

函數對象:
var add = function(x, y){ return x + y; } console.log(typeof add); console.log(add(1,2));
//function
//3
10,arguments 偽數組
arguments代表的是實參。實際上不是一個數組,只是一個偽數組,它有數組的屬性,如length屬性,但是沒有數組的方法。
有個講究的地方是:arguments只在函數中使用。
fn(2,4); fn(2,4,6); fn(2,4,6,8); function fn(a,b,c) { console.log(arguments); console.log(fn.length); //獲取形參的個數 console.log(arguments.length); //獲取實參的個數 console.log("----------------"); }
11,Object 對象
1.使用Object或對象字面量創建對象
2.工廠模式創建對象
3.構造函數模式創建對象
4.原型模式創建對象
(總結:了解字面量創建對象,prototype方法調用對象的父類,繼承。function關鍵字創建類,new關鍵字創建對象)
①使用Object或字面量方式創建對象
JS中最基本創建對象的方式:
var student = new Object(); console.log(student); //{} console.log(typeof student); //object student.name = "easy"; student.age = "20";
這樣,一個student對象就創建完畢,擁有2個屬性name
以及age
,分別賦值為"easy"
和20
。
如果你嫌這種方法有一種封裝性不良的感覺。來一個對象字面量方式創建對象。
var sutdent = { name : "easy", age : 20 };
這樣看起來似乎就完美了。但是馬上我們就會發現一個十分尖銳的問題:當我們要創建同類的student1,student2,…,studentn時,我們不得不將以上的代碼重復n次....

var sutdent1 = { name : "easy1", age : 20 }; var sutdent2 = { name : "easy2", age : 20 }; ... var sutdentn = { name : "easyn", age : 20 };
②工廠模式創建對象
JS中沒有類的概念,那么我們不妨就使用一種函數將以上對象創建過程封裝起來以便於重復調用,同時可以給出特定接口來初始化對象。
python中使用class來創建類,而js中使用function來創建類。
function createStudent(name, age) { var obj = new Object(); obj.name = name; obj.age = age; return obj; } var student1 = createStudent("easy1", 20); var student2 = createStudent("easy2", 20); ... var studentn = createStudent("easyn", 20);
檢測student1是否是Object
console.log(student1 instanceof Object); //true
這樣一來我們就可以通過createStudent函數源源不斷地”生產”對象了。看起來已經高枕無憂了,但貪婪的人類總有不滿足於現狀的天性:我們不僅希望”產品”的生產可以像工廠車間一般源源不斷,我們還想知道生產的產品究竟是哪一種類型的。
比如說,我們同時又定義了”生產”水果對象的createFruit()函數:
function createFruit(name, color) { var obj = new Object(); obj.name = name; obj.color = color; return obj; } var v1 = createStudent("easy1", 20); var v2 = createFruit("apple", "green");
對於以上代碼創建的對象v1、v2,我們用instanceof操作符去檢測,他們統統都是Object類型。我們的當然不滿足於此,我們希望v1是Student類型的,而v2是Fruit類型的。為了實現這個目標,我們可以用自定義構造函數的方法來創建對象
③構造函數模式創建對象
在上面創建Object這樣的原生對象的時候,我們就使用過其構造函數:
var obj = new Object();
在創建原生數組Array類型對象時也使用過其構造函數:
var arr = new Array(10); //構造一個初始長度為10的數組對象
在進行自定義構造函數創建對象之前,我們首先了解一下構造函數
和普通函數
有什么區別。
1、實際上並不存在創建構造函數的特殊語法,其與普通函數唯一的區別在於調用方法。對於任意函數,使用new操作符調用,那么它就是構造函數;不使用new操作符調用,那么它就是普通函數。
2、按照慣例,我們約定構造函數名以大寫字母開頭,普通函數以小寫字母開頭,這樣有利於顯性區分二者。例如上面的new Array(),new Object()。
3、使用new操作符調用構造函數時,會經歷(1)創建一個新對象;(2)將構造函數作用域賦給新對象(使this指向該新對象);(3)執行構造函數代碼;(4)返回新對象;4個階段。
ok,了解了構造函數
和普通函數
的區別之后,我們使用構造函數將工廠模式
的函數重寫,並添加一個方法屬性:
function Student(name, age) { this.name = name; this.age = age; this.alertName = function(){ alert(this.name) }; } var p1 = new Student('qiuma',20); p1.alertName(); function Fruit(name, color) { this.name = name; this.color = color; this.alertName = function(){ alert(this.name) }; }
這樣我們再分別創建Student和Fruit的對象:
var v1 = new Student("easy", 20); var v2 = new Fruit("apple", "green");
這時我們再來用instanceof操作符來檢測以上對象類型就可以區分出Student以及Fruit了:
alert(v1 instanceof Student); //true alert(v2 instanceof Student); //false alert(v1 instanceof Fruit); //false alert(v2 instanceof Fruit); //true alert(v1 instanceof Object); //true 任何對象均繼承自Object alert(v2 instanceof Object); //true 任何對象均繼承自Object
這樣我們就解決了工廠模式
無法區分對象類型的尷尬。那么使用構造方法來創建對象是否已經完美了呢?使用構造器函數通常在js中我們來創建對象。
我們會發現Student和Fruit對象中共有同樣的方法,當我們進行調用的時候這無疑是內存的消耗。
我們完全可以在執行該函數的時候再這樣做,辦法是將對象方法移到構造函數外部:
this指的是當前對象,和python中的self類似。
function Student(name, age) { this.name = name; this.age = age; this.alertName = alertName; } function alertName() { alert(this.name); } var stu1 = new Student("easy1", 20); var stu2 = new Student("easy2", 20);
在調用stu1.alertName()時,this對象才被綁定到stu1上。
我們通過將alertName()函數定義為全局函數,這樣對象中的alertName屬性則被設置為指向該全局函數的指針。由此stu1和stu2共享了該全局函數,解決了內存浪費的問題
但是,通過全局函數的方式解決對象內部共享的問題,終究不像一個好的解決方法。如果這樣定義的全局函數多了,我們想要將自定義對象封裝的初衷便幾乎無法實現了。更好的方案是通過原型對象模式來解決。
④原型的模式創建對象
原型鏈甚至原型繼承,是整個JS中最難的一部分也是最不好理解的一部分,可以去查閱一下相關JS原型的一些知識點。
function Student() { this.name = 'easy'; this.age = 20; } Student.prototype.alertName = function(){ //使用prototype方法調用(原型,屬於對象的父類),繼承 alert(this.name); }; var stu1 = new Student(); var stu2 = new Student(); stu1.alertName(); //easy stu2.alertName(); //easy alert(stu1.alertName == stu2.alertName); //true 二者共享同一函數
12,Date日期對象
創建日期對象只有構造函數一種方式,使用new關鍵字
//創建了一個date對象 var myDate = new Date();
//返回本地時間 console.log(myDate.toLocalString());
//獲取本地時間,月份中的第幾天(1~31)
console.log(myDate.getDate());
13,JSON
①概念簡介
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式,采用完全獨立於語言的文本格式,是理想的數據交換格式。同時,JSON是 JavaScript 原生格式,這意味着在 JavaScript 中處理 JSON數據不須要任何特殊的 API 或工具包。
在JSON中,有兩種結構:對象和數組。
- 對象(對象中的key必須是帶有雙引號)
var packJSON= {"name":"alex", "password":"123"};
一個對象以“{”開始,“}”結束,“key/value”之間運用 “,”分隔。
- 數組
var packJSON = [{"name":"alex", "password":"123"}, {"name":"wusir", "password":"456"}]
數組是值的有序集合。一個數組以“[”開始,“]”結束。值之間運用 “,”分隔。
②JSON對象和JSON字符串轉換
在數據傳輸過程中,JSON是以字符串的形式傳遞的,而JS更喜歡操作JSON對象,所以,JSON對象和JSON字符串之間的相互轉換是關鍵。例如:
1,JSON字符串:
var jsonStr ='{"name":"qiuma", "password":"123"}' ;
2,JSON對象:
var jsonObj = {"name":"qiuma", "password":"123"};
3,JSON字符串 → JSON對象
var jsonobject = JSON.parse(jsonStr); //name:qiuma password:123
var jsonObject = jQuery.parseJSON(jsonstr);
4,JSON對象 → JSON字符串
var jsonstr =JSON.stringify(jsonObject ); //{"name":"qiuma","password":"123"}
③遍歷JSON對象和JSON數組
1,遍歷JSON對象代碼如下:(for in 循環)
var packJSON = {"name":"qiuma", "password":"123"} ; for(var k in packJSON){
//遍歷packJSON 對象的每個key/value隊,k為key,指的是鍵值的索引 console.log(k + " " + packJSON[k]); }
// qiuma 123
2,遍歷JSON數組代碼如下
var packJSON = [{"name":"qiuma", "password":"123"}, {"name":"qiumawu", "password":"456"}]; for(var i in packJSON){
//遍歷packJson 數組時,i為索引 console.log(i+ ' ' + packJSON[i].name + " " + packJSON[i].password); }
3,正則表達式
對象:RegExp
正則表達式:檢索字符串,用來規定文本搜索的內容
1,正則表達式的創建
①構造函數創建
new RegExp(“檢測的文本”,“修飾符”)匹配模式常用g(全局匹配:找到所有匹配,而不是匹配后停止)和i(忽略大小寫),不能有空格。
var str = 'hello world'; var reg1 = new RegExp('l', 'ig'); console.log(reg1);
②字面量創建(常用)
var reg2 = /o/gi;
檢測字符e,不區分大小寫,全局匹配
2,正則對象提供的檢索方式
①test() 測試
var str = 'hello world';
var reg2 = /o/ig;
console.log(reg2.test(str)); //true
test() 檢測字符串中是否包含定義字符模式,返回布爾
要檢索的字符在字符串str中 返回true
②exec()
exec() 方法檢索字符串中的正則表達式的匹配
如果匹配到了那么就返回一個存放有結果的數組,如果沒有匹配到就返回一個null
var str = 'hello World'; var reg3 = /o/ig; console.log(reg3.lastIndex); // 0 保存一次匹配時開始的下標,這里還未有匹配,得到0 console.log(reg3.exec(str)); //["o", index: 4, input: "hello world"] console.log(reg3.lastIndex); //5 上一級index是4,這里得到下一次開始的下標5
lastIndex是保存一次匹配時開始的下標,還沒有匹配就是保存0。
3,常用的方法
①match
使用正則表達式模式對字符執行查找,並將包含查找的結果作為數組返回。
字符串.match(正則)
var str = 'hello world'; var reg = /o/g; console.log(str.match(reg)); //["o", "o"]
②replace 替換
replace(被替換的,替換的)
var str = 'hello world'; var reg = /o/g; console.log(str.replace(reg,"*")); //hell* w*rld
③search() 查找下標
查找字符串再字符串中出現的位置 下標
var str = 'hello world'; var reg = /o/g; console.log(str.search(reg)); //4
④split() 分割
以匹配的規則分割
var str = 'hello world'; var reg = /o/g; console.log(str.split(reg)); //["hell", " w", "rld"]
4,元字符(匹配的規則)
(1)單個字符和數字
① . (匹配除換行符 \a以外的任意字符)
var str = 'hello world'; var reg = /./g; console.log(reg.exec(str)); //h
如果不想讓字符有其他意義,可以使用轉義字符 \ 。比如/www\....\.com/g; 這里 \. 表示匹配 . 。
var str = 'www.baidu.com'; var reg = /www\......\.com/g; console.log(reg.exec(str)); //www.baidu.com
② [ ] (匹配[ ]里面的任意一個字符)
var str1 = 'hello'; var reg1 = /[a-zA-Z0-9]/g; //匹配字母還是數字 console.log(reg1.exec(str1)); //h var str2 = 'a1314'; var reg2 = /[0-9][0-9][0-9]/g; console.log(reg2.exec(str2)); //131
③ [^] (所有不在這個范圍內的字符)
var str3 = 'abd123'; var reg3 = /[^a-z][^A-Z]/g; //匹配除字母意外的任意字符 console.log(reg3.exec(str3)); //12
④ \d和\D (\d:匹配數字,\D:匹配非數字)
var str4 = 'web'; var reg4 = /\d/g; //匹配數字 var reg5 = /\D/g; //匹配非數字 console.log(reg4.exec(str4)); //null console.log(reg5.exec(str4)); //w
⑤ \w和\W (\w:匹配數字,字母下划線 \W:匹配除數字,字母,下划線以外的任意字符)
var str4 = 'web'; var reg6 = /\w/g; //匹配數字,字母,下划線 var reg7 = /\W/g; //匹配除數字,字母,下划線意外的任意字符 console.log(reg6.exec(str4)); //w console.log(reg7.exec(str4)); //null
⑥ \s和\S (\s:匹配空格 \S:匹配非空白空格)
trim() :去除字符串前后空白方法
var str5 = ' qiuma'; var reg8 = /\s/g; //匹配空格 var reg9 = /\S/g; //匹配非空白字符 console.log(reg8.exec(str5)); //" " console.log(reg9.exec(str5)); //q
⑦ ^ ,$ (^:以什么開頭,$:以什么結尾)
var str = 'www.baidu.com'; var reg1 = /^www/g; //以www開頭 var reg2 = /^www\......\.com$/g; //以www開頭,com結尾 console.log(reg1.exec(str)); //www console.log(reg2.exec(str)); //www.baidu.com
(2) 重復多個字符
① ? (匹配前面的字符0個或1個)
② * (匹配0個或任意多個字符,盡可能多的匹配)
③ + (至少匹配一次)
④ {} ({10}:匹配連續的10個字符,{1,4}:匹配最少1個字符,最多4個字符)
⑤ || (或者)
⑥ () (分組)
//1,?:匹配前面的字符0個或者一個 var str = '123webr445jkj'; var reg1 = /[0-9]?/g; console.log(reg1.exec(str)); //1 //2,*:匹配0個或者任意多個字符,盡可能多的匹配 var reg2 = /[a-z]*/g; console.log(reg2.exec(str)); //" " //3,+:至少匹配一次 var reg3 = /\d+/g; console.log(reg3.exec(str)); //123 //4,{10}:匹配連續的十個字符 var str2 = '11274567890'; var reg4 = /^1\d{10}$/g; //匹配連續的10個數字 console.log(reg4.exec(str2)); //11274567890 //5,{min,max} 最少min個,最多max個字符 var str3 = 'edge'; var reg5 = /^[a-zA-Z]{2,3}/g; console.log(reg5.exec(str3)); //edg //6,| :或者 var str4 = 'www.google.com'; var reg6 = /www.baidu|google|sogo/g; console.log(reg6.exec(str4)); //google //7,():分組 var str5 = 'www.google.com'; var reg7 = /(baidu)|(google)|(sogo)/g; console.log(reg7.exec(str5)); //google //獲取匹配的字符串,下面三個分別為空,google,空 console.log(RegExp.$1); console.log(RegExp.$2); console.log(RegExp.$3); var str6 = 'helloworld'; var reg8 = /(hello)(world)/g; console.log(reg8.exec(str6)); console.log(RegExp.$1); //hello //將分組好的匹配調換順序 console.log(str5.replace(reg8,"$2 $1")); //world hello
(3)相關實例
①檢索字符串中是否不包含字母
var str = '12'; var reg1 = /[^a-zA-Z]/g; if (reg1.test(str)){ console.log('不包含'); } else { console.log('包含'); } //不包含
②去除字符串首尾空格
var str = ' hello world! '; var reg = /^\s+/ig; var str1 = str.replace(reg, ''); var reg2 = /\s+$/ig; var str2 = str1.replace(reg2,''); console.log('|' + str2 + '|'); //|hello world!|
③檢查用戶賬號
function checkUser(str){ var re = /^[a-zA-Z]\w{3,15}$/; if(re.test(str)){ console.log('正確'); }else{ console.log('錯誤'); } } checkUser('qiuma_haha'); //調用
④匹配11位手機號碼
function checkMobile(str){ var re = /^1\d{10}$/ if(re.test(str)){ console.log('正確'); }else{ console.log('錯誤'); } } checkMobile('13800138000'); //調用 checkMobile('1398888888889'); //錯誤示例
⑤匹配電話號碼
驗證規則:區號+好嗎,區號以0開頭,3位或者4位
號碼由7位或8位數字組成,區號與好嗎之間可以無連接符,也可以“-”連接
var re = /^0\d{2,3}-?\d{7,8}$/; if(re.test(str)){ console.log('正確'); } else{ console.log('錯誤'); } } checkPhone('095-57777777'); //調用 //正確
⑥驗證郵箱
驗證規則:一個郵箱由兩部分組成,第一部分@第二部分。
第一部分:由字符,數字,下划線,短線“-”,點號“.”組成
第二部分:為一個域名,域名由字母,數字,短線,域名后綴組成,二域名后綴一般為 .***或者***.***,一區的域名后綴一般為2-4位,如cn, con, net, 現在域名有的也會大於4位。
function checkEmail(str){ var re = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/ if(re.test(str)){ console.log('正確'); } else{ console.log('錯誤'); } } checkEmail('wqmcr@foxmail.com'); //調用 //正確
4,DOM(重點)
DOM文檔加載的步驟
- 解析HTML結構。
- 加載外部腳本和樣式表文件。
- 解析並執行腳本代碼。
- DOM樹構建完成。
- 加載圖片等外部文件。
- 頁面加載完畢。
1,DOM初步認識
(1)概念
所謂DOM,全稱 Docuemnt Object Model 文檔對象模型,是一個文檔對象模型。
DOM 為文檔提供了結構化表示,並定義了如何通過腳本來訪問文檔結構。
目的其實就是為了能讓js操作html元素而制定的一個規范。
(2)解析過程
HTML加載完畢,渲染引擎會在內存中把HTML文檔,生成一個DOM樹,getElementById是獲取內中DOM上的元素節點。然后操作的時候修改的是該元素的屬性。
(3)DOM樹(一切皆是節點)
上圖可知,在HTML當中,一切都是節點:(非常重要)
- 元素節點:HMTL標簽。
- 文本節點:標簽中的文字(比如標簽之間的空格、換行)
- 屬性節點::標簽的屬性
整個html文檔就是一個文檔節點。所有的節點都是Object。元素,節點,他表示的就是標簽對象
(4)DOM可以做什么
1,找對象(元素節點,標簽對象)(獲取DOM)
2,設置標簽的屬性值(對於標簽屬性的操作)
3,設置標簽的樣式(對於樣式屬性的操作)
4,設置標簽值的操作
5,動態創建和刪除元素(對於DOM的建增刪改查)
6,事件的觸發響應:找到事件源、事件、事件的驅動程序(js事件,ECMAScript相關知識對DOM進行操作)
用手(事件源)去按開關(事件),其中事件的驅動程序是燈的開和關。
(5)獲取DOM的結構
- 獲取文檔對象:document
- 獲取html:document.documentElement
- 獲取body: document.body
2,獲取DOM(事件源)
//方式一:通過id獲取單個標簽 var oDiv1 = document.getElementById("box1"); //方式二:通過 標簽名 獲得 標簽數組,所以有s var oDivs2 = document.getElementsByTagName("div")[0]; //方式三:通過 類名 獲得 標簽數組,所以有s var oDivs3 = document.getElementsByClassName("box")[0];
注意:
通過方式二和方式三到的HTMLCollection和arguments(實參,偽數組相似),獲取的是一個和偽數組類似的東西,因此不能使用數組的方法,但是可以添加索引來取確定的值。
3,事件
JS是事件驅動為核心的一門語言。
(1)事件的三要素
事件源,事件,驅動程序。
比如:網頁上面彈出一個廣告,我點擊右上角的x,廣告就關閉了。
這件事情里,事件源是:x。事件是:onclick。事件驅動程序是:廣告關閉了。
誰引發的后續事件,誰就是事件源。
總結如下:
- 事件源:引發后續事件的html標簽。
- 事件:js已經定義好了(見下圖)。
-
事件驅動程序:對樣式和html的操作。也就是DOM。
(2)代碼書寫步驟如下(重要)
①獲取事件源:document.getElementById(“box”);
//類似與ios語言的UIButton *adBtn = [UIButtonbuttonWithType:UIButtonTypeCustom];
②綁定事件: 事件源box.事件onclick = function(){ 事件驅動程序 };
③書寫事件驅動程序:關於DOM的操作
(3)常用事件
onclick //鼠標單擊 ondblclick //鼠標雙擊 onkeyup //按下並釋放鍵盤上的一個鍵時觸發 onchange //文本內容或下拉菜單中的選項發生改變 onfocus //獲得焦點,表示文本框等獲得鼠標光標 onblur //失去焦點,表示文本框等失去鼠標光標 onmouseover //鼠標懸停,即鼠標停留再圖片等的上方 onmouseout //鼠標移出,即離開圖片等所在的區域 onload //網頁文檔加載事件 onunload //關閉網頁時 onsubmit //表單提交事件 onreset //重置表單時
(4)綁定事件的方式
①直接綁定匿名函數(最常用)
var oDiv = document.getElementById("box"); oDiv.onclick = function () { alert("我是彈出的內容"); };
②先單獨定義函數,再綁定
var oDiv = document.getElementById("box"); oDiv.onclick = fn; //注意,這里是fn,不是fn()。fn()指的是返回值。 //單獨定義函數 function fn() { alert("我是彈出的內容"); };
注意上方代碼的注釋。綁定的時候,是寫fn,不是寫fn()。fn代表的是整個函數,而fn()代表的是返回值。
③行內綁定
<!--行內綁定--> <div id="box" onclick="fn()"></div> <script type="text/javascript"> function fn() { alert("我是彈出的內容"); } </script>
注意第一行代碼,綁定時,是寫的"fn()"
,不是寫的"fn"
。因為綁定的這段代碼不是寫在js代碼里的,而是被識別成了字符串。
(5)window.onload()
①JavaScript入口函數 window.onload()
此函數調用,是當頁面加載完畢(文檔和圖片)的時候,觸發onload()函數,文檔先加載,圖片資源后加載
<script type="text/javascript"> window.onload = function () { console.log("alex"); //等頁面加載完畢時,打印字符串 } </script>
有一點我們要知道:js的加載是和html同步加載的。因此,如果使用元素在定義元素之前,容易報錯。這個時候,onload事件就能派上用場了,我們可以把使用元素的代碼放在onload里,就能保證這段代碼是最后執行。
②window.onload()方法存在的問題
- 圖片加載完成才調用onload方法,大家想個問題,如果現在用戶訪問JD商城頁面,如果JD商城中的腳本文件在window.onload()方法調用,如果此時用戶網速卡了,然后圖片資源加載失敗了,此時用戶是做不了任何操作的,所以winodw.onload()方法有很大問題。所以等待着文檔和圖片資源加載完成之后,才會觸發onload事件。
- window.onload()方法 如果腳本中書寫兩個這樣的方法,那么會有事件覆蓋現象。會執行后面那個。
window.onload = function(){ //1,獲取事件源 var oDiv = document.getElementById('box'); console.log(oDiv); //2,事件 oDiv.onclick = function(){ //3,事件驅動 alert(1); } };
4,事件驅動(DOM能做的)
(1)樣式屬性操作
所謂樣式屬性,就是style標簽中的屬性進行操作,並且通過js控制盒模型的屬性(width,height等),控制盒子的顯示隱藏(display:none|block),控制盒子的顏色切換(background:red|green)等等
操作文檔對象三步走:
- 獲取事件源
- 事件
- 事件驅動程序
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test</title> <style type="text/css"> .box{ width: 100px; height: 100px; } </style> </head> <body> <div class = 'box' style="background-color: red;"> <!--1,盒子,初始化的時候是紅色的,點擊這個盒子,切換成綠色--> </div> <script type="text/javascript"> //1.獲取事件源(事件對象,在文檔中一切的標簽都是對象) var oDiv = document.getElementsByClassName('box')[0]; //2.事件 oDiv.onclick = function(){ //3.事件驅動程序 CSSStyleDclaration對象 console.log(oDiv.style); //點語法 get和set方法 //獲取值 get方法 獲取的是行內樣式的屬性,與內接外接沒有任何關系 console.log(oDiv.style.backgroundColor); //設置值 set方法 //注意:在style中書寫的比如background-color通過js設置的時候要寫成駝峰標識 oDiv.style.backgroundColor = 'green'; oDiv.style.width = '300px'; oDiv.style.marginLeft = '30px'; } </script> </body> </html>
樣式屬性-顏色切換
//1.獲取事件源(事件對象,在文檔中一切的標簽都是對象) var oDiv = document.getElementsByClassName('box')[0]; var isRed = true; //2.事件 后執行的操作 異步操作 oDiv.onclick = function(){ if(isRed){ oDiv.style.backgroundColor = 'green'; isRed = false; }else{ oDiv.style.backgroundColor = 'red'; isRed = true; } }
(2)標簽值的操作
雙閉合標簽:innerText或者innerHTML
innerText和innerHTML的區別
innerText是對標簽文本內容進行設置
innerHTML則是對文本和標簽進行的渲染
像html中雙閉合的標簽,比如<button></button>, <li>, <a>都是通過上面兩個對其獲取或設置內容的
單閉合標簽:除了img標簽,就剩input了,使用value進行賦值
value使用在對於單閉合如<input>表單控件中。有value屬性的,必須通過value來設置值和賦值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test</title> </head> <body> <button id = 'btn'> 設置值 </button> <div id = 'box'> 哈哈哈 <h3>Qiuma</h3> </div> <input type="text" name = 'user' value="123" id = 'oinput'> <script type="text/javascript"> window.onload = function () { var oBtn = document.getElementById('btn'); var oDiv = document.getElementById('box'); var oInput = document.getElementById('oinput'); oBtn.onclick = function () { //這里只獲取文本 console.log(oDiv.innerText); //innerText 對標簽文本內容設置 // oDiv.innerText = 'qiuma'; // console.log(oDiv.innerHTML.trim()); //獲取的是所有的節點(文本和標簽 換行) console.log(oDiv.innerHTML); oDiv.innerHTML = '<h2>qiuma2</h2>'; //單閉合 //表單控件中有value屬性的,必須通過value來設置值和賦值 //獲取值 console.log(oInput.value); //設置值 oInput.value = '321'; } } </script> </body> </html>
簡潔版(解決冗余的代碼)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test</title> </head> <body> <button id = 'btn'> 設置值 </button> <div id = 'box'> 哈哈哈 <h3>Qiuma</h3> </div> <input type="text" name = 'user' value="123" id = 'oinput'> <script type="text/javascript"> window.onload = function () { function $(id){ return document.getElementById(id); }; $('btn').onclick = function () { //這里只獲取文本 console.log($('box').innerText); //innerText 對標簽文本內容設置 // oDiv.innerText = 'qiuma'; // console.log(oDiv.innerHTML.trim()); //獲取的是所有的節點(文本和標簽 換行) console.log($('box').innerHTML); $('box').innerHTML = '<h2>qiuma2</h2>'; //單閉合 //表單控件中有value屬性的,必須通過value來設置值和賦值 //獲取值 console.log($('oinput').value); //設置值 $("oinput").value = '321'; } } </script> </body> </html>
(3)標簽屬性的操作
如對id,class,title,src,href等等進行肉眼能夠看得到的標簽的屬性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> a{ display: inline-block; } </style> </head> <body> <!-- <img src="" alt=""> <a href=""></a> --> <a href="javascript:void(0);"> // href="javascript:void(0); 阻止a標簽的默認事件 <img src="./images/image.png" alt="上一張" id="prev"> </a> <!-- id class title src href等等 --> <script type="text/javascript"> window.onload = function(){ // 1.獲取事件源 var oImg = document.getElementById('prev'); // 2.事件 onmouseover oImg.onmouseover = function(){ // console.log(oImg); // 好比是python中self 誰調用的事件 this指的就是誰 // console.log(this); // ./images/image.png 相對路徑。getAttribute,進行設置。 console.log(this.getAttribute('src')); console.log(this.getAttribute('id')); console.log(this.getAttribute('alt')); // 獲取的絕對路徑。上面的簡寫 console.log(this.src); console.log(this.id); console.log(this.alt); // 屬性的設置 // this.setAttribute('src', './images/image-hover.png'); this.src = './images/image-hover.png'; }; oImg.onmouseout = function(){ this.setAttribute('src', './images/image.png'); } } </script> </body> </html>
元素顯示隱藏的兩種方式
display和class
①通過控制樣式屬性的display屬性對盒子的顯示和隱藏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box{ width: 100px; height: 200px; background-color: red; } .active{ display: none; } </style> </head> <body> <button id="btn">隱藏</button> <div id="box" class="box"></div> <script type="text/javascript"> window.onload = function(){ function $(id){ return document.getElementById(id); } //方式一:通過控制樣式屬性的display屬性來對盒子的顯示和隱藏 var isShow = true; $('btn').onclick = function(){ if (isShow) { $('box').style.display = 'none'; isShow = false; this.innerText = '顯示'; }else{ $('box').style.display = 'block'; this.innerText = '隱藏'; isShow = true; } } } </script> </body> </html>
②通過控制類來對盒子進行的顯示和隱藏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box{ width: 100px; height: 200px; background-color: red; } .active{ display: none; } </style> </head> <body> <button id="btn">隱藏</button> <div id="box" class="box"></div> <script type="text/javascript"> window.onload = function(){ function $(id){ return document.getElementById(id); } // 方式二:通過控制類來對盒子的顯示和隱藏 // 切換 初始化的時候會有渲染開銷 適用於網頁中頻繁的性切換 var isShow = true; $('btn').onclick = function(){ if (isShow) { // 在js中設置類得通過className標識 $('box').className += ' active'; this.innerText = '顯示'; isShow = false; }else{ // 在js中設置類得通過className $('box').className = 'box'; this.innerText = '隱藏'; isShow = true; //當點擊隱藏的時候,active將box覆蓋掉了 } } } </script> </body> </html>
(4)DOM的節點操作
比如可以對div中的一個p標簽進行自由的刪除和創建,可以使用函數方法完成。
①創建節點
新的標簽(元素節點) = document.createElement("標簽名");
比如,如果我們想創建一個li標簽,或者是創建一個不存在的adbc標簽,可以這樣做:
<script type="text/javascript"> var a1 = document.createElement("li"); //創建一個li標簽 var a2 = document.createElement("adbc"); //創建一個不存在的標簽 console.log(a1); //<li></li> console.log(a2); //<adbc></abdc> console.log(typeof a1); //object console.log(typeof a2); //object </script>
②插入節點:
方式一:
父節點.appendChild(子節點)
//父子之間追加元素。父節點的最后插入一個新的子節點
方式二:
父.insertBefoe(新的子節點,作為參考的節點)
//兄弟之間插入新節點。在參考節點前插入一個新的節點。如果參考節點為null,那么他將在父節點最后插入一個子節點。
③刪除節點
父節點.removeChild(子節點);
解釋:用父節點刪除子節點。必須要指定是刪除哪個子節點。
如果我想刪除自己這個節點,可以這么做:
node1.parentNode.removeChild(node1);
④獲取父節點和子節點
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="box"> <button id="btn"> <span>哈哈 <span>嘿嘿</span> </span> <span>哈哈</span> </button> </div> <script type="text/javascript"> window.onload = function() { function $(id) { return document.getElementById(id); }; // 獲取父節點 親爹 console.log($('btn').parentNode); //一直往上,可以獲取文檔 console.log($('btn').parentNode.parentNode.parentNode.parentNode); // 獲取的是復數 親兒子 console.log($('btn').children); $('btn').onclick = function(){ // 自己刪除自己 this.parentNode.removeChild(this); } //或者可以這樣自己刪除自己 // $('btn').parentNode.removeChild($('btn')); } </script> </body> </html>
⑤綜合實例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>創建節點</title> </head> <body> <button id="create">創建</button> <button id="remove">移除</button> <div id="box"> <!-- <h2>alex</h2> --> <h3 id="haha">哈哈哈哈</h3> </div> <script type="text/javascript"> window.onload = function(){ function $(id){ return document.getElementById(id); } var oP = null; $('create').onclick = function(){ // 創建p節點元素 oP= document.createElement('h2'); // 設置文本內容 oP.innerText = 'Qiuma'; // 方式一:父子之間追加元素 父.appendChild(子) $('box').appendChild(oP); // 方式二:兄弟之間插入新節點,在參考的節點之前加入新的子節點 // 父.insertBefore(新的子節點,做為參考的節點) // $('box').insertBefore(oP,$('haha')); }; // 創建→銷毀 頁面性能是有損耗。 // 如果頁面中出現頻繁性的切換,不要使用這種方式 // 登錄 注冊→生命周期 $('remove').onclick = function(){ // 父.removeChild(子節點) $('box').removeChild(oP); } } </script> </body> </html>
5,DOM案例
①模態框案例
點擊一個按鈕,彈出另一個界面,點擊這個界面的x,可以返回最初界面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模態框</title> <style type="text/css"> * { padding: 0; margin: 0; } html,body{ width: 100%; height: 100%; } #bg{ position: relative; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,.3); } #login{ width: 300px; height: 300px; border-radius: 3px; background-color: #fff; line-height: 300px; text-align: center; margin: 0 auto; position: relative; } #close{ position: absolute; right: 0; top: 0; width: 20px; height: 20px; background-color: red; line-height: 20px; text-align : center; color: green; cursor: pointer; } </style> </head> <body> <button id="btn">登錄</button> <!-- 需求: 打開網頁時,點擊登錄顯示一個背景圖,中心 彈出一個登錄框,登錄框 右上角有關閉按鈕 點擊關閉 關閉登錄框 --> <script type="text/javascript"> function $(id) { return document.getElementById(id); } // 1.點擊登錄按鈕 彈出登錄框 // 背景 var oBg = document.createElement('div'); // 登錄框 var oLogin = document.createElement('p'); // 關閉按鈕 var oClose = document.createElement('span'); oBg.id = 'bg'; oLogin.id = 'login'; oClose.id = 'close'; oClose.innerText = 'X'; oLogin.innerHTML = '登錄框成功彈出'; // 追加 oBg.appendChild(oLogin); oLogin.appendChild(oClose); console.log( $('btn')); $('btn').onclick = function() { alert(1); this.parentNode.appendChild(oBg); this.style.display =' none'; } oClose.onclick = function(){ oBg.parentNode.removeChild(oBg); $('btn').style.display = 'inline-block'; } </script> </body> </html>
②模擬hover選擇器效果
有一排的按鈕,懸浮在這個按鈕上面可以改變字體顏色,且可以改變鼠標的狀態

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> button{ margin: 10px; width: 100px; height: 40px; cursor: pointer; } button.active{ background-color: green; } </style> </head> <body> <button class="active">按鈕1</button> <button>按鈕2</button> <button>按鈕3</button> <button>按鈕4</button> <button>按鈕5</button> <script type="text/javascript"> // 需求: 鼠標懸浮 哪個button上,該button變成綠色的背景(添加類 active) var oBtns = document.getElementsByTagName('button'); for(var i = 0; i < oBtns.length; i++){ oBtns[i].onmouseover = function(){ // 重要: 排他思想: 先把所有按鈕的className設置為空,然后把(this)當前這個按鈕的className設置active for(var j = 0;j < oBtns.length; j++){ oBtns[j].className = ''; } this.className = 'active'; } } for(var i = 0;i < oBtns.length; i++){ oBtns[i].onmouseout = function(){ this.className = ''; } } </script> </body> </html>
③tab選項卡

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> * { padding: 0; margin: 0; } ul { list-style: none; } #tab { width: 480px; margin: 20px auto; border: 1px solid red; } ul { width: 100%; overflow: hidden; } #tab ul li { float: left; width: 160px; height: 60px; line-height: 60px; text-align: center; background-color: #ccc; } #tab ul li a { color: black; display: block; width: 100%; height: 100%; text-decoration: none; } #tab ul li.active { background-color: red; } #tab p { display: none; height: 200px; text-align: center; line-height: 200px; background-color: red; } #tab p.active { display: block; } </style> </head> <body> <div id="tab"> <ul> <li class="active"> <a href="javascript:void(0);">首頁</a> </li> <li> <a href="javascript:void(0);">新聞</a> </li> <li> <a href="javascript:void(0);">圖片</a> </li> </ul> <p class="active">首頁內容</p> <p>新聞內容</p> <p>圖片</p> </div> <script type="text/javascript"> // 需求: 鼠標放在上面,li上 li本身變色(添加類) 對應下面p也顯示出來(添加類) // 思路: 1.點亮上面的盒子 2 利用索引值來顯示下面的盒子 /* // 變量提升 var a; console.log(a);//undefined a = 10; console.log(a); */ var tabLi = document.getElementsByTagName('li'); var tabP = document.getElementsByTagName('p'); for(var i = 0; i < tabLi.length; i++){ // 將 i保存到 li標簽對象中 tabLi[i].index = i; // for循環和點擊事件 誰快 i 全局作用域(塊級作用域) 3 tabLi[i].onclick = function(){ for(var j = 0;j < tabLi.length;j++){ tabLi[j].className = ''; tabP[j].className = ''; } this.className = 'active'; // Cannot set property 'className' of undefined console.log(i); tabP[this.index].className = 'active'; } } </script> </body> </html>
使用ES6的語法來解決tab欄選項卡:
設計到解決變量提升的問題
主要是使用let可以聲明塊作用域中的變量,其他地方不可以使用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> * { padding: 0; margin: 0; } ul { list-style: none; } #tab { width: 480px; margin: 20px auto; border: 1px solid red; } ul { width: 100%; overflow: hidden; } #tab ul li { float: left; width: 160px; height: 60px; line-height: 60px; text-align: center; background-color: #ccc; } #tab ul li a { color: black; display: block; width: 100%; height: 100%; text-decoration: none; } #tab ul li.active { background-color: red; } #tab p { display: none; height: 200px; text-align: center; line-height: 200px; background-color: red; } #tab p.active { display: block; } </style> </head> <body> <div id="tab"> <ul> <li class="active"> <a href="javascript:void(0);">首頁</a> </li> <li> <a href="javascript:void(0);">新聞</a> </li> <li> <a href="javascript:void(0);">圖片</a> </li> </ul> <p class="active">首頁內容</p> <p>新聞內容</p> <p>圖片</p> </div> <script type="text/javascript"> // 需求: 鼠標放在上面,li上 li本身變色(添加類) 對應下面p也顯示出來(添加類) // 思路: 1.點亮上面的盒子 2 利用索引值來顯示下面的盒子 /* // 變量提升 var a; console.log(a);//undefined a = 10; console.log(a); */ /* var a console.log(a); { a = 10; } console.log(a); */ // es6中 我們使用let聲明塊級作用域 /* { let a = 10; console.log(a); } console.log(a); */ var tabLi = document.getElementsByTagName('li'); var tabP = document.getElementsByTagName('p'); for(let i = 0; i < tabLi.length; i++){ // for循環和點擊事件 誰快 i 全局作用域(塊級作用域) 3 tabLi[i].onclick = function(){ for(var j = 0;j < tabLi.length;j++){ tabLi[j].className = ''; tabP[j].className = ''; } this.className = 'active'; // Cannot set property 'className' of undefined console.log(i); tabP[i].className = 'active'; } } </script> </body> </html>
6,client, offset, scroll系列
①client系列
clientTop 內容區域到邊框頂部的距離 ,說白了,就是邊框的高度
clientLeft 內容區域到邊框左部的距離,說白了就是邊框的亂度
clientWidth 內容區域+左右padding 可視寬度
clientHeight 內容區域+ 上下padding 可視高度

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> .box{ width: 200px; height: 200px; position: absolute; border: 10px solid red; /*margin: 10px 0px 0px 0px;*/ padding: 80px; } </style> </head> <body> <div class="box"> Google Chrome 瀏覽器,中文名"谷歌瀏覽器",是一款免費的開源 web 瀏覽器,它由 Google 開發,發布於 2008 年。 </div> </body> <script type="text/javascript"> /* * clientTop 內容區域到邊框頂部的距離 ,說白了,就是邊框的高度 * clientLeft 內容區域到邊框左部的距離,說白了就是邊框的亂度 * clientWidth 內容區域+左右padding 可視寬度 * clientHeight 內容區域+ 上下padding 可視高度 * */ var oBox = document.getElementsByClassName('box')[0]; console.log(oBox.clientTop); //10 console.log(oBox.clientLeft); //10 console.log(oBox.clientWidth); //360 console.log(oBox.clientHeight); //360 </script> </html>
②屏幕的可視寬度
通過onresize方法來獲知屏幕可視區域的寬高,窗口大小發生變化時,會觸發此方法。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> <script type="text/javascript"> // 屏幕的可視區域 window.onload = function(){ // document.documentElement 獲取的是html標簽 // console.log(document.documentElement.clientWidth); // console.log(document.documentElement.clientHeight); // // 窗口大小發生變化時,會觸發此方法 window.onresize = function(){ console.log(document.documentElement.clientWidth); console.log(document.documentElement.clientHeight); } } </script> </html>
③offset系列
offsetWidth占位寬 內容+padding+border
offsetHeight占位高
offsetTop: 如果盒子沒有設置定位 到body的頂部的距離,如果盒子設置定位,那么是以父輩為基准的top值
offsetLeft: 如果盒子沒有設置定位 到body的左部的距離,如果盒子設置定位,那么是以父輩為基准的left值

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ padding: 0; margin: 0; } </style> </head> <body style="height: 2000px"> <div> <div class="wrap" style=" width: 300px;height: 300px;background-color: green;position:relative;top: 30px;"> <div id="box" style="width: 200px;height: 200px;border: 5px solid red; position: absolute; top: 70px;left: 50px"> </div> </div> </div> </body> <script type="text/javascript"> window.onload = function(){ var box = document.getElementById('box') /* offsetWidth占位寬 內容+padding+border offsetHeight占位高 offsetTop: 如果盒子沒有設置定位 到body的頂部的距離,如果盒子設置定位,那么是以父輩為基准的top值 offsetLeft: 如果盒子沒有設置定位 到body的左部的距離,如果盒子設置定位,那么是以父輩為基准的left值 * */ console.log(box.offsetTop); console.log(box.offsetLeft); // console.log(box.offsetWidth); // console.log(box.offsetHeight); } </script> </html>
④scroll系列
監聽滾動事件,可觸發此方法

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> * { padding: 0; margin: 0; } </style> </head> <body style="width: 2000px;height: 2000px;padding:10px;border:1px solid red;"> <div style="height: 200px;background-color: red;"></div> <div style="height: 200px;background-color: green;"></div> <div style="height: 200px;background-color: yellow;"></div> <div style="height: 200px;background-color: blue;"></div> <div style="height: 200px;background-color: gray;"></div> <div id='scroll' style="width: 200px;height: 200px;border: 1px solid red;overflow: auto;padding: 10px;margin: 5px 0px 0px 0px;"> <p>學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界學習新技能,達成人生目標,開始用自己的力量影響世界 </p> </div> </body> <script type="text/javascript"> window.onload = function() { //實施監聽滾動事件 觸發此方法 window.onscroll = function() { // 上1 // 左0 // 寬2000 // 高2000 // 頁面卷起的高度 console.log('上' + document.documentElement.scrollTop); // console.log('左' + document.documentElement.scrollLeft); // 包含 border + width + padding console.log('寬' + document.documentElement.scrollWidth); // console.log('高' + document.documentElement.scrollHeight); } // var s = document.getElementById('scroll'); // s.onscroll = function(){ // // scrollHeight : 內容的高度+padding // console.log('上'+s.scrollTop) // console.log('左'+s.scrollLeft) // console.log('寬'+s.scrollWidth) // console.log('高'+s.scrollHeight) // } } </script> </html>
5,定時器
一次性定時器:setTimeout(fn, 2000)
周期性循環定時器:setInterval(fn, 1000)
里面有兩個參數,第一個函數是回調函數(匿名函數),第二個參數是時間(毫秒級)。
1, setTimeout()
只在指定時間后執行一次
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script type="text/javascript"> console.log('開始'); // 一次性定時器 2秒之后會執行回調函數 console.log(22222); 如果它先調用了,證明 setTimeout()可以做異步操作 // 如果對於數據的請求 出現數據阻塞的問題,那么可以考慮使用setTimeout()來執行異步操作 setTimeout(function(){ console.log('走到盡頭了'); }, 2000); console.log(22222); </script> </body> </html> //結果顯示,走到盡頭是最后才打印出來的,說明進行了異步操作。
2,setInterval()
在指定時間為周期循環執行
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <script type="text/javascript"> var num = 0; setInterval(function(){ num++; console.log(num); },1000) </script> </body> </html> //結果會一直輸出1,2,3,4...
3,清除定時器
clearInterval(); 清除一次性定時器
cleatTimeout(); 清除周期性定時器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <button id="clear">清除定時器</button> <script type="text/javascript"> var num = 0; var timer =setInterval(function () { num++; console.log(num); },100); // clearInterval(handle?: long) // clearTimeout(handle?: long) var oClear = document.getElementById('clear'); oClear.onclick = function(){ clearInterval(timer); } </script> </body> </html>
定時器代碼示例

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box{ width: 100px; height: 100px; background-color: yellow; } </style> </head> <body> <div id="box">我的盒子</div> <button id="animate">動畫吧</button> <button id="clear">清除定時器</button> <script type="text/javascript"> /* console.log('開始'); // 一次性定時器 2秒之后會執行回調函數 console.log(22222); 如果它先調用了,證明 setTimeout()可以做異步操作 // 未來 如果對於數據的請求 出現數據阻塞的問題,那么可以考慮使用setTimeout()來執行異步操作 setTimeout(function(){ console.log('走到盡頭了'); }, 2000); console.log(22222); */ var oDiv = document.getElementById('box'); var oAnimate = document.getElementById('animate'); var num = 0; let timer; oAnimate.onclick = function(){ // 用定時器的時候 要先清定時器 再開定時器 頁面不會出現問題 clearInterval(timer); timer = setInterval(function(){ // 控制盒子的步伐 num+=3; console.log(num); oDiv.style.marginLeft = num +'px'; },100); }; // clearInterval(handle?: long) // clearTimeout(handle?: long) var oClear = document.getElementById('clear'); oClear.onclick = function(){ clearInterval(timer); } </script> </body> </html>
使用定時器前需要先清定時器,再開定時器,頁面不會出現問題。
6,BOM
瀏覽器對象模型
主要用於操作瀏覽器部分功能的API。比如讓瀏覽器自動滾動,刷新,前進后退。
1,BOM的結構圖
- window對象是BOM的頂層(核心)對象,所有對象都是通過它延伸出來的,也可以稱為window的子對象。
- DOM是BOM的一部分。
window對象:
- window對象是JavaScript中的頂級對象。
- 全局變量、自定義函數也是window對象的屬性和方法。
- window對象下的屬性和方法調用時,可以省略window。
2,彈出系統對話框
比如說,alert(1)
是window.alert(1)
的簡寫,因為它是window的子方法。
window.alert(); //不同瀏覽器中的外觀不一樣,這里window可以省略不寫
3,打開窗口,關閉窗口
①打開窗口
window.open(url,targer);
url: 要打開的地址
target: 新窗口的位置,可以是:_blank
、_self
、 _parent
父框架。
②關閉窗口
window.close();
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> a{ text-decoration:none; } </style> </head> <body> <!-- 需求: 點擊按鈕 打開新的窗口 百度 --> <!-- a標簽默認是在當前窗口打開新的網址 --> <a href="http://www.baidu.com" target="_blank" >百度</a> <button>baidu</button> <script type="text/javascript"> var oBtn = document.getElementsByTagName('button')[0]; oBtn.onclick = function(){ // 默認在新的窗口打開 網址 _blank // window.open('http://www.luffycity.com','_self'); // window可以省略不寫 open('http://www.baidu.com','_self'); // 關閉窗口,點擊某個按鈕在某個時機關閉 // window.close(); } </script> </body> </html>
4,location對象
window.location
可以簡寫成location。location相當於瀏覽器地址欄,可以將url解析成獨立的片段。
location對象的屬性
- href:跳轉
- hash:返回url中#后面的內容,包含#
- host:主機名,包括端口號
- hostname:主機名
- pathname:url中的路徑部分,路徑名,端口號之后的路徑
- protocol:協議 一般是http、https
- search:查詢字符串
- origin:原始地址
- href:地址
location對象的方法;
window.location.reload(); //全局刷新頁面,相當於瀏覽器導航欄上 刷新按鈕
案例:模擬a標簽跳轉:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <!-- <form action="https://www.baidu.com/s" target = '_blank'> <input type="text" name="wd" placeholder="請輸入城市"> <input type="submit" value="搜索"> </form> --> <script type="text/javascript"> console.log(window.location); setTimeout(function(){ location.href = 'https://www.baidu.com'; }, 5000) </script> </body> </html>
5,history對象
網頁中的后退,前進,刷新
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <a href="./index.html">新網頁</a> <button id="forward">前進</button> <button id="refresh">刷新</button> <script type="text/javascript"> alert(1); function $(id){ return document.getElementById(id); } $('forward').onclick = function(){ // 表示前進 window.history.go(1); }; $('refresh').onclick = function(){ // 表示刷新 不常用 因為全局刷新 // window.history.go(0); // 局部作用域刷新 使用的技術 ajax window.location.reload(); }; </script> </body> </html>
7,ToDoList案例
①index.css

body { margin: 0; padding: 0; font-size: 16px; background: #CDCDCD; } .header { height: 50px; background: #333; background: rgba(47,47,47,0.98); } .header .box,.content{ width: 600px; padding: 0 10px; margin: 0 auto; } .content{ margin: 0 auto; } label { float: left; width: 100px; line-height: 50px; color: #DDD; font-size: 24px; cursor: pointer; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; } .header input { float: right; width: 60%; height: 24px; margin-top: 12px; text-indent: 10px; border-radius: 5px; box-shadow: 0 1px 0 rgba(255,255,255,0.24), 0 1px 6px rgba(0,0,0,0.45) inset; border: none } input:focus { outline-width: 0 } h2 { position: relative; } span { position: absolute; top: 2px; right: 5px; display: inline-block; padding: 0 5px; height: 20px; border-radius: 20px; background: #E6E6FA; line-height: 22px; text-align: center; color: #666; font-size: 14px; } ol,ul { padding: 0; list-style: none; } li input { position: absolute; top: 2px; left: 10px; width: 22px; height: 22px; cursor: pointer; } p { margin: 0; } li p input { top: 3px; left: 40px; width: 70%; height: 20px; line-height: 14px; text-indent: 5px; font-size: 14px; } li { height: 32px; line-height: 32px; background: #fff; position: relative; margin-bottom: 10px; padding: 0 45px; border-radius: 3px; border-left: 5px solid #629A9C; box-shadow: 0 1px 2px rgba(0,0,0,0.07); } ol li { cursor: move; } ul li { border-left: 5px solid #999; opacity: 0.5; } li a { position: absolute; top: 2px; right: 5px; display: inline-block; width: 14px; height: 12px; border-radius: 14px; border: 6px double #FFF; background: #CCC; line-height: 14px; text-align: center; color: #FFF; font-weight: bold; font-size: 14px; cursor: pointer; } .footer { color: #666; font-size: 14px; text-align: center; } .footer a { color: #666; text-decoration: none; color: #999;
②index.html

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title>ToDoList—最簡單的待辦事項列表</title> <meta name="description" content="ToDoList無須注冊即可使用,數據存儲在用戶瀏覽器的html5本地數據庫里,是最簡單最安全的待辦事項列表應用!" /> <link rel="stylesheet" href="index.css"> </head> <body> <div class="header"> <div class="box"> <form action="javascript:postaction()" id="form"> <label for="title">ToDoList</label> <input type="text" id="title" name="title" placeholder="添加ToDo" required="required" autocomplete="off" /> </form> </div> </div> <div class="content"> <h2 onclick="save()">正在進行 <span id="todocount"></span></h2> <ol id="todolist" class="demo-box"> </ol> <h2>已經完成 <span id="donecount"></span></h2> <ul id="donelist"> </ul> </div> <div class="footer"> Copyright © 2018 todolist.cn <a href="javascript:clear();">clear</a> </div> <script type="text/javascript" src="index.js"></script> </body> </html>
③index.js

function clear() { localStorage.clear(); load(); } function postaction() { var title = document.getElementById("title"); if (title.value == "") { alert("內容不能為空"); } else { var data = loadData(); var todo = { "title": title.value, "done": false }; data.push(todo); saveData(data); var form = document.getElementById("form"); form.reset(); load(); } } function loadData() { var collection = localStorage.getItem("todo"); if (collection != null) { return JSON.parse(collection); } else return []; } function saveSort() { var todolist = document.getElementById("todolist"); var donelist = document.getElementById("donelist"); var ts = todolist.getElementsByTagName("p"); var ds = donelist.getElementsByTagName("p"); var data = []; for (i = 0; i < ts.length; i++) { var todo = { "title": ts[i].innerHTML, "done": false }; data.unshift(todo); } for (i = 0; i < ds.length; i++) { var todo = { "title": ds[i].innerHTML, "done": true }; data.unshift(todo); } saveData(data); } function saveData(data) { localStorage.setItem("todo", JSON.stringify(data)); } function remove(i) { var data = loadData(); var todo = data.splice(i, 1)[0]; saveData(data); load(); } function update(i, field, value) { var data = loadData(); var todo = data.splice(i, 1)[0]; todo[field] = value; data.splice(i, 0, todo); saveData(data); load(); } function edit(i) { load(); var p = document.getElementById("p-" + i); title = p.innerHTML; p.innerHTML = "<input id='input-" + i + "' value='" + title + "' />"; var input = document.getElementById("input-" + i); input.setSelectionRange(0, input.value.length); input.focus(); input.onblur = function() { if (input.value.length == 0) { p.innerHTML = title; alert("內容不能為空"); } else { update(i, "title", input.value); } }; } function load() { var todolist = document.getElementById("todolist"); var donelist = document.getElementById("donelist"); var collection = localStorage.getItem("todo"); if (collection != null) { var data = JSON.parse(collection); var todoCount = 0; var doneCount = 0; var todoString = ""; var doneString = ""; for (var i = data.length - 1; i >= 0; i--) { if (data[i].done) { doneString += "<li draggable='true'><input type='checkbox' onchange='update(" + i + ",\"done\",false)' checked='checked' />" + "<p id='p-" + i + "' onclick='edit(" + i + ")'>" + data[i].title + "</p>" + "<a href='javascript:remove(" + i + ")'>-</a></li>"; doneCount++; } else { todoString += "<li draggable='true'><input type='checkbox' onchange='update(" + i + ",\"done\",true)' />" + "<p id='p-" + i + "' onclick='edit(" + i + ")'>" + data[i].title + "</p>" + "<a href='javascript:remove(" + i + ")'>-</a></li>"; todoCount++; } }; todocount.innerHTML = todoCount; todolist.innerHTML = todoString; donecount.innerHTML = doneCount; donelist.innerHTML = doneString; } else { todocount.innerHTML = 0; todolist.innerHTML = ""; donecount.innerHTML = 0; donelist.innerHTML = ""; } } window.onload = load; // window.addEventListener("storage", load, false);
over.