程序員花0.5小時分享:Html+CSS+JS 中JS總結

總結

本書的JS

  1. 第一章有講語法有挺多常見的坑點和原理解釋很不錯

  2. 第二章DOM編程講述了挺多API

  3. 第三章事件處理機制其實對事件中的this關鍵字和事件傳播順序講4. 解還不錯

  4. 第四章WebStorage本地存儲例子鮮明

  5. 第五章Worker應付複雜的js操作

  6. 第六章客戶端通信WebSocket挺有用,可以實現用戶與用戶在瀏覽器中互動

這篇文章共享之前我仍是要引薦下我自個的前端群:657137906,不論你是小白仍是大牛,小編我都挺期待,不定期共享乾貨,包含我自個整理的一份2017最新的前端材料和零根底入門教程,期待初學和進階中的小夥伴。

1. JavaScript語法

1.1 執行js代碼

javascript:alert(‘執行js’);//一般放在超鏈接中,用戶點擊即執行,

<script>alert("執行js")</script>

1.2 變量賦值

var a = 1;//顯式a =1; //隱式

1.3 全局變量與局部變量

...var scope = "全局變量";function test(){ alert(scope); // undefiend var scope = "局部變量"; alert(scope); // 局部變量}

因為全局變量被局部變量覆蓋了.雖然局部變量的scope還沒賦值,但是已經在方法裡”佔”上位置了.

但如果把局部變量的var刪了,就會先輸出全局變量後輸出局部變量,因為沒有var在方法裡給局部變量”佔”位置;

1.4 浮點數

var a =.333var b = a * 5;alert(b);

得出的結果是 1.66499999999999999

所以在js中判斷浮點數是否相等 建議判斷兩者的差值是否小於一個足夠的數(例如0.0000000000001)

1.5 字符串

js中沒有字符類型變量 “”與’‘一致

var s ="abcdefg"//b = "def"b = s.slice(3, -1);

1.6 字符串的正則表達式方法中

  1. match()返回匹配的字符串(數組或null),可加/g進行全局匹配多個

  2. search()返回匹配的索引值 單個

1.7 undefined和null

null == undefined //truenull === undefined //false

undefined 是沒設值

null則是設定了為null值

1.8 運算符

//逗號運算符 取最右返回值a = (b =5 , c = 7 , d =56) //a =56a = void(b =5 , c = 7 , d =56) //a = undefined

1.9 typeof和instanceof

typeof 用來獲得 實例類型 :

typeof("123"); //string

instanceof 判斷變量是否為某類的實例

var a = [4,5];alert(a instanceof Array); //true

1.10 語句

拋出異常

throw new Error("用戶自定義異常"); //一般用於終止程序和返回錯誤提示是個不錯的選擇;try{}catch(e){ alert(e.message); // "用戶自定義異常"}

for in

//這回輸出瀏覽器的所有屬性,做瀏覽器兼容之前可以考慮看看.for( prop_name in navigator){ document.wrti(prop_name + " : " + navigator[propname]);}

跳出命名for

outer:for(...){ for(...){ ... continue outer; }}

1.11 函數

js 允許先調用函數 再定義函數

1.11.1 定義匿名函數

var show_name = function(name){ alert(name);}show_name("K"); //K

這樣的好處是什麼,如果直接定義function 它實際上也是創建了一個對象

1.11.2 函數既對象

var hello = function(){...};hello instanceof Function //true;hello instanceof Object //true;alert(heelo) //輸出函數源代碼

1.11.3 調用函數方式的不同

  1. 直接調用函數 返回return的值或void

  2. new 函數 得到的都是對象 - -…….

1.11.4 this關鍵字.

  1. 在函數中使用this.變量 該變量就是函數的實例變量,而非局部變量,無論它在哪裡.

  2. 函數可依附在類中.如沒指定 則依附在winodw對象中

var hello =function(){...}window.hello();var p = { wark: function(){...}}p.wark();

1.11.5 函數中的變量有三種

function Person(){ //局部變量 只能在函數裡訪問 var id ; //實例屬性 通過對象.訪問 this.age ; //類屬性 通過Patient.name訪問 與static類似 Person.name ;}

1.11.6 js是一種動態語言,能隨時給對象增加屬性和方法

function Student(){ };var student =new Student();//動態增加name屬性student.name = 'K';alert(sutdent.name) //KStudent.age =22 ;alert(Student.age); //22 類屬性也是可以動態添加的

1.11.7 調用函數的三種方式

  1. 直接調用

windows.alert();//oralert();
  1. call()調用

    作用:動態地傳入一個函數引用

var each = function(array,fn){ for(var index in arrary){ //null表示以window為調用者fn函數 fn.call(null,index,arrary[index]); }}each([4,20,3] , function(index ,ele){ alert("第 " + index "個元素是 : " + ele);});

call()調用函數語法為:函數引用.call(調用者,參數1,參數2...)

直接調用函數語法為:調用者.函數(參數1,參數2 ...) = 函數.call(調用者,參數1,參數2 ...)

  1. apply()調用

    apply和()call()基本相似,區別如下:

  2. 通過call()調用函數時,括號必須詳細列出每個參數

  3. 通過apply()動態地調用函數時,可以在括號中以arguments來代表所有參數

var myfun = function (a , b){ alert(a + " " +b);}myfun.call(window ,12 ,23); //12 23;myfun.apply(window ,[20 , 39]); //20 39var example = function (num1 ,num2){ //直接調用arguments代表調用者(example,this代表example)時的傳入的所有參數 myfun.apply(this,arguments);}example(20,40) //20 40

1.11.8 函數的獨立性

在函數A中可以定義函數B,但是函數B還是獨立於函數A

function Person(name){ this.name = name; this.info = function(){ alert(this.name); }} var person =new Person('K');person.info(); //Kvar name = 'K_window';//由於window為調用者 ,this.name訪問的是window.namep.info.call(window); //K_window

來爽一發貓學狗叫?.

function Dog(name,bark){ this.name = name; this.bark = bark; this.info =function(){ alert(this.name + " " + this.bark); }}function Cat(name){ this.name =name;} var dog = new Dog("K","汪汪!");var cat = new Cat("K_2");dog.info.call(cat); //K_2 undefined

1.11.9 參數傳遞方式

和JAVA一樣 都是值傳遞拉~.

基本類型

function change(arg){ arg =10 ; alert(arg);}var x = 5;alert(x); //5change(x); //10alert(x); //5

複合類型

function change(person){ person.age = 10; alert(person.age); person = null;}var person = {age : 5};alert(person.age); //5change(person); //10alert(person.age); // 10alert(person); // []object Object]

複合類型的傳遞為值傳遞,原person和參數person指向同一javascript對象,所以當改變age的時候,是在改變javascript對象的age,但是參數person賦值為null,原person並無改變.

1.11.10 空參數

function text(person){ alert( typeof parson);}text(); //undefined

所以對於弱類型,方法重載是無作用的,因為js會把空參數當做undefined傳遞進去;

同名函數,後面出現的會覆蓋前面的,無論參數個數是多少.

1.11.11 對象和關聯數組

javascript和Map有點類似,當key為對象,value為函數,該該函數就是對象的方法,當key為對象,value為基本類型,則該基本類型為對象的屬性.(以上為便於理解,切勿細琢)所以訪問屬性時,可以obj.propName也可以obj[propName].

但有時候我們只能用obj[propName],因為.propName不能把propName當做變量處理,而是把他當成’propName’字符串

function Person(name){ this.name =name; this.info = function(){ alert(K); }}var person = new Person("K");//遍歷person屬性for (propName in person){ alert(p[propName]);//alet K info源代碼 假如此處用p.propName則undefined,因為Person無'propName'變量.}

1.11.12 繼承和prototype

在一個類(函數)中定義一個函數會導致

  1. 性能低下:每次new一個類 都會生成一個函數

  2. 函數中若引用類的局部變量會產生閉包 導致局部變量一直存在

function Person(){ var local = "局部變量" this.info = function(){ //產生閉包 alert(local); }}var person = new Person();person.ifno(); // 局部變量

解決方案:prototype

增加了prototype屬性的類可視為繼承了原先的類(偽繼承)

function Person(){...}var person = new Person();//person.wark(); 程序報錯wark不存在Person.prototype.wark = function(){...}person.wark(); //ok

在prototype之前實例化的類會具有wark方法嗎? 有的,因為prototype這樣並不會產生一個新的類,而是直接動態的往Person里加函數.

判斷某方法是否繼承了該對象

該對象.prototype['某方法'] != undefined;var test = new 該對象();test.某方法 !=undefined ;

1.12 創建對象三種方式

//(單身汪別說我不教你)

  1. new關鍵字調用構造器創建對象

function Person(name){...}var person_1 = new Person();var person_2 = new Person('K'); //js不存在方法重載,空參數undefined頂替
  1. 使用Object直接創建對象

var my_obj = new Object();my_ojb.name = 'K';my_obj.handsome = function(){...}function text(){...}my_obj.text = text;//不要添加(),不然會認為是調用方法
  1. JSON創建對象

ver person = { name : 'K', school : ['ChangAn','TianJin'], girl_friends :[ { name : 'Haski', age : 11 }, { name : 'Samoyed', age : '8' } ]}alert(person.girl_friends[0].name); //Haski

2 DOM編程

DOM操作其實JQuery已經做得很好了,這裡簡單補充一下原生JS的知識

HTML文檔中只有一個根節點

2.1 訪問HTML元素

  1. id getElementById(‘id’); or getElementsByName(‘name’);

  2. 根據節點關係

Node parentNode: 返回父節點Node previousSibling: 返回前一個兄弟節點Node nextSibling: 飯後後一個兄弟節點Node[] childNodes 返回當前節點的所有節點Node[] getElementsByTagName('標籤名稱'): 返回當前節點具有制定標籤的子節點//注意ol標籤的子標籤IE8和其他瀏覽器不一樣(其他瀏覽器會把ol下的li和其後面的空白分別當成2個節點,IE8則不會)

2.2 增加HTML函數

  1. document.createElement(“標籤名”);

  2. 複製節點 var node =ul.firstChild.nextSibling.cloneNode(boolean),boolean為true時,複製所有所有後代節點.false則僅複製當前節點.clone了節點以後還要找一個節點添加進去.

2.3 添加節點

  1. appendChild(Node);添加為當前節點的最後一個子節點

  2. inserBefore(newNode,refNode);在refNode前添加newNode

  3. replaceChild(newChild,oldChild);替換節點

  4. 增加select選項 new Option(text,value,defaultSelected,selected);

2.4 刪除節點

  1. removeChild(oldNode);

2.5 window對象

  1. 返回上一個頁面: back()

  2. window.href: 當前url

  3. window.width: 屏幕橫向分辨率

  4. window.height: 屏幕縱向分辨率

  5. 遍歷window.screen,包含所以屏幕屬性

for(var propName in window.screen){ alert(propName+":" +screent[propname]);}
  1. cofrim(‘標題’); 能彈出是否確認的提示框

  2. prompt(‘標題’); 能彈出一個文本輸入框輸入.

  3. 定時器:setInterVal,clearInterval()

var timer;var cur = new Date().getTime();var setTime = function(){ document.getElementById("tm").innerHTML = new Date().toLocationString(); if(new Date().getTime- cur > 60 *1000){ clearInterval(timer); }}//每1S執行一次,執行了60次就暫停timer = window.setInterval("setTime()",1000);

2.6 navigator和地理位置

navigator漢堡瀏覽器所有信息,遍歷循環獲取信息

for(var propName in window.navigator){ alert(propName + ":" + window.navigator[propName]);}

HTML5新增geolocation屬性

Geolocation提供的方法

  1. getCurrentPosition(onSuccess,onError,options)

  2. int watchCurrentPostion(OnSuccess,onError,options),週期性調用getCurrentPosition,返回的int代表這個”監聽器”的ID,用來clearWatch(watchID)取消監聽

  3. clearWatch(watchID),用於取消watchCurrentPosition

上面的前兩個方法的options參數是一個對象,可包含3個變量

  1. enabelHighAccuracy(是否制定高精度地理位置)

  2. tiemout 設置超時時長

  3. maximumAge,設置緩存時間

    例子:

var geoHandler = function(position){ var geoMsg = "用戶地址位置是 : <br/>" geoMsg += "timestamp屬性為 :" + position.timestamp + "<br/>"//獲取位置的時間 var cords =position.coords; for(var prop in coords ){ geoMsg += prop + ": " + coords[prop] +"<br/>"//經緯度,移動速度等 } document.writeln(geoMsg);}var errorHandler = function(error){ var errMsg = { 1: '用戶拒絕了位置服務' 2: '無法獲取地址位置信息' 3: '獲取地理位置信息超時' }; alert(error[error.code]);}navigator.geolocation.getCurrentPosition(geoHandler, errorHandler, { enableHighAccuracy:true, maximuAge:1000});

2.7 HTML5新增瀏覽器分析

實現該功能主要通過performance對象

其中的(PerformanceTiming)timing屬性包含加載時間相關的屬性

另外(PerformanceNavigation)navigation,主要屬性有

type :

TYPE_NAVIGATE(數值為0): 超鏈接/輸入urlTYPE_RELOAD(1): 重新加載方式,diaoyonglocation.reload()等TYPE_BACK_FORWARD(2): 通過瀏覽器的前進方式TYPE_RESERVED(255): 未知方式

3 事件處理機制

3.1 常見事件

  1. onabort: 圖片加載終端

  2. onblur: 失去焦點

  3. onchange: 表單域更改

  4. onclick: 點擊

  5. onerror: 圖片加載出錯

  6. onfocus: 獲得焦點

  7. onkeydown: 按下鼠標

  8. onkeypress: 當焦點在當前元素上,單擊鍵盤某個鍵觸發

  9. onkeyup: 當焦點在當前元素上,鬆開某個鍵觸發

  10. onload: 某個對象加載完畢,適用於img,oframe,body

  11. onunload: 當某個對象從窗口下卸載觸發,適用於img,oframe,body

  12. onmousedown: 焦點停留在當前元素上,按下鼠標觸發

  13. onmousemore: 當焦點在當前元素上,鼠標移動到該元素

  14. onmouseout: 鼠標移出當前元素觸發

  15. onmouseover: 鼠標移動到該元素觸發

  16. onmouseup: 焦點在當前元素,鬆開鼠標時觸發

  17. onreset: 重置表單時觸發

  18. onsubmit: 表單提交觸發

3.2 事件處理和this

p.info = function(){ alert(this.name);}document.getElementById("bt").onclick = p.info//this指向'bt'控件document.getElementById("bt").onclick = new function (){ p.info();} //this總是指向p

注意表單設置id為x和name為y時候,相當於表單創建了x屬性和y屬性,所以id和name不能是關鍵字submit等

3.3 DOM

創建監聽事件

objectTarget.addEventListener(“eventType”,handler,capture),第一個參數表示綁定的事件,如click、keypress之類的,第二個制定綁定的函數,第3個位boolean,true表示監聽捕獲階段,false表示監聽冒泡階段

objectTarget.removeEventListener(“eventType”,handler,captureFlag): 刪除綁定事件

捕獲狀態階段的綁定事件先執行,事件冒泡狀態階段的綁定事件後執行. 捕獲狀態階段從外往內觸發,事件冒泡狀態階段從內往外觸發.

綁定例子

var got_click = function (event){ for ( event_one in event){ alert(event_one + " : " + event[event_one]); }} document.getElementByID("test").addEventListener("cilck",got_click,true);

阻止事件傳播

event.stopPropagation();

取消事件的默認行為,如跳轉頁面等,但不會阻止事件傳播.

event.preventDefault();

3.3.1轉發事件

DOM提供了dispathEvent方法用於事件轉發,該方法屬於Node

target.dispathEvent(Event event),將event轉發到target上

DOM的dispath()必須轉發人工合成的Event事件

document.createEvent(String type),tpy參數用於指定事件類型,eg:普通事件Events,UI事件UIEvents,鼠標事件:MouseEvents

初始化事件

initEvent(具體參數...)initUIEvent(具體參數...)intMouseEvent(具體參數...)//例子<input id="bt1"><input id="bt2">...var rd =function(evt){ alert("事件冒泡階段: " + evt.currentTarget.value +"被點擊了"); var e =document.createEvent("Evnets"); e.initEvent("click",true,false);//true表示是否支持冒泡,false表示是否有默認行為 document.getElementById("bn2").dispathEvent(e);}var go_click = function (evt){ alert("事件冒泡階段: " + evt.currentTarget.value);}document.getElementById("bn1").addEventListener("click",rd,false);document.getElementById("bn2").addEventListener("click",go_click,false);;//點解按鈕一結果alert(事件冒泡階段: 按鈕一被點擊了);alert(事件冒泡階段:按鈕2);

點擊按鈕1,按鈕執行了前面按鈕一被點擊了提示語句後,將點擊事件轉給了按鈕2,按鈕2執行自身的點擊事件.

4 本地存儲與離線應用

4.1 Web Storage

使用理由之一Cookie的侷限性:

  1. Cookie大小被限制為4KB

  2. Cookie會包含在每次HTTP請求中

  3. Cookie網絡傳輸未加密(除非整個應用都使用SSL)

    Web Storage分兩種

    Session Storage: 生命週期與用戶Session一致(用戶Session是指:用戶從訪問網址到離開網址/關閉瀏覽器)

    Local Storage: 保存在用戶的磁盤中,失效的方式為用戶/程序顯示刪除.

    Web Storage的方法有

  4. length: 返回key-value對數

  5. key(index): 返回第index個key

  6. getItem(key): 獲取key對應的value

  7. set(key,value): 設置key-value

  8. removeItem(key): 刪除key-value

  9. clear(): 清除所有key-value

Web Storage包含在window對象中

當value為對象時,建議用JSON存儲

4.2 構建離線應用

  1. 在html標籤中修改

//表明該頁使用index.manifest文件<html manifest="index.manifest">
  1. index.mainfest文件

CACHE MANIFEST//第一行必須為上述字符//指定版本號#version 1//本地緩存資源CACHEinedx.htmllogo.jpg//不緩存的資源NETWORK*//前者表示在線狀態使用的資源,後者代表離線狀態使用的資源FALLBACKtest.js offline.js
  1. Tomcat為例,天津映射文件

<!--conf的web.xml根元素中增加MIME映射--><mine-mapping> <extension>manifest</extension> <mine-type>text/cache-mainfest</mime-type></mime-mapping>

啟動應用後,頁面可刷新(即使離線狀態),並使用離線時候的資源

4.2.1 判斷在線狀態

navigator.onLine屬性: true表示在線

online/offline事件: 當在線/離線狀態切換時,body上的online/offine事件會被觸發,沿著document.body、document和window冒泡

window.addEventListener("offline",function(){ alert("離線狀態")},true);if(navigator.onLine){ alert("在線");}

4.2.2 applicationCache對象

js可通過applicationCache控制離線緩存.

status屬性:

  • UNCACHE: 主機沒開啟離線功能.

  • IDLE: 空閒狀態.

  • CHECKING: 正在檢查本地manifest和服務器中manifest的差異

  • DOWNLOADING: 正在下載需要的緩存數據

  • OBSOLETE: 緩存已經過期

常用方法
  • void update(): 強制檢查服務器的mainfest文件是否有更新

  • void swapCache(): 更新緩存,只能在applicationCache的updateReady事件被觸發時調用.

setInterval(function(){ applicationCache.update()},2000);applicationCache.onupdateready = function(){ if(confirm("已從遠程服務器下載了需要的緩存,是否更新?")){ applicationCache.swapCache(); location.reload(); }}4.2.3 離線應用的事件與監聽訪問html頁面過程
  • 瀏覽器請求index.html

  • 服務器返回index.html

  • 瀏覽器頁面是否制定manifest屬性,若制定,觸發checking事件,檢查服務器中的manifest文件是否存在,不存在則觸發error事件,不會制定第六部及其後續步驟

  • 瀏覽器解析index.html,請求該頁其他資源.

  • 服務器返回所以請求

  • 瀏覽器處理mainfest文件,重新請求manifest文件中的所以頁面,包括index.html頁面,前面下載過的資源,扔會再下一遍.

  • 服務器返回所以要求被要求緩存的資源

  • 瀏覽器開始下載需要在本地緩存的資源,開始下載時觸發ondownloading事件,在下載過程中不斷觸發onprogress事件.以便開發人員瞭解下載進度.

  • 下載完成後觸發oncache事件.緩存完成

當用戶再訪問index.html時,前面1~5完全相同,接下來檢測mainfest文件是否有改變.
  • 沒有改變觸發onnoupdate事件,結束.

  • mainfest改變,執行第7,8部,當所以文件本地緩存下載完畢後,瀏覽器- 觸發onupdateready事件,而不會觸發oncached事件.

5 使用worker創建多線程worker中無法使用DOM、alert等與界面有關的操作.使用理由:防止js阻塞主線程的js運行WorkerAPI
  • onmessage: 獲取前臺js提交過來的數據

  • postMessage(data): 前臺js通過postMessage觸發Worker對象的onmessage事件.

  • importScripts(urls),導入多個js,importScripts(“a.js”,“b.js”);

  • sessionStorge/localStorage: 使用Worker操作Storage本地存儲

  • Worker: 創建新的Worker對象啟動嵌套線程

  • XMLHttpRequest: Worker使用XMLHttpRequest發送異步請求.

  • navigator: 與window的location屬性類似

  • location: 與window的location屬性相似

  • self: WorkerGlobalScope對象,代表當前Worker線程自身作用域.調用self的close()結束線程

  • setTimeout()/seInterval()/eval()/inNaN()/parseInt,等與界面無關的js核心函數,包括Array/Data/Math/Number/Object/String等.

  • 寫一段找出輸入start和end之間素數的線程.

    worker.js代碼

onmessage =function(event){
var data =JSON.parse(event.data);
var start =data.start;
var end =data.end;
var result ="";
search:
for (var n =start; n <= end :n++){
if(n%i==0){
continue search;
}
result +=(n+",");
}
}
postMessage(result);

網頁代碼

<input name="start" ...>
<input name="end" ...>
<input type=button inclick="cal();" ...>
...
var car =function(){
var start = parseInt(document.getElementById("start").value);
var end = parseInt(document.getElementById("end").value);
//創建線程
var cal = new Worker("worker.js");
var data ={
"start" : srart,
"end" : end
};
//發送數據
cal.postMessage(JSON.stringify(data));
cal.onmessage = function (evnet){
alert(event);
}
}

並行的兩條Worker不能互相通信,但Wroker可嵌套.

6 客戶端通信

WebSocket: 服務器主動推送信息/客戶端實時推送數據到服務器

6.1 跨文檔通信

window對象新增方法

  1. targetWindow.postMessage(message,targetOrigin): 該方法用戶向targetWindow中狀態的HTML發送信息,targetOrigin表示接收html的域名.

  2. onmessage: 調用方法:windows.onmessage =function(event){…}

    event中的屬性:

  • data: 數據

  • orgin: 發送消息window的源域名

  • lastEventID: 返回發送消失時間的ID

  • source: 返回發送消息的窗口

html想發送要做
  1. 獲取接收消息的window對象

  2. 調用接收消息的window對象的postMessage(any message)方法

html想接收要做
  1. 本html綁定事件window.message = function(event){…};

    跨文檔消息傳遞

//source.htmlvar targetWin = window.open("接收方url",'_blank','windth=400,height=300');targetWin.onload =function(){ targetWin.postMessage("傳輸消息","接收方域名");}window.onmessage =function(event){ //忽略其他域名發送的消息 if(event.orgin !="指定域名"){ return ; } alert(event.data);}//接收頁面.htmlwindow.onmessage = function(event){ //忽略其他域名發送的消息 if(event.orgin !="指定域名"){ return ; } alert("接收到消息拉!"+event.data); event.source.postMessage("回傳消息",event.origin);}結果:alert(接收到消息拉!傳輸消息);alert(回傳消息);注意!一定要判斷髮送方的域名!!!!!一定要判斷髮送方的域名!!!!!一定要判斷髮送方的域名!!!!!6.2 WebSocket與服務器通信以前方案:
  1. 週期發送請求

  2. 頁面使用隱藏窗口與服務器長連接

WebSocket方法
  1. send(“數據”);向服務器發送數據.

  2. close();關閉該WebSocket.

WebSocket監聽事件
  1. onopen: 當WebSocket建立網絡連接觸發該.

  2. onerror: 網絡連接錯誤

  3. onclose: WebScokt被關閉觸發

  4. onmessage: WebSocket接收到服務器數據時

WebSocket屬性
  1. readyState

    1.1 CONNECTING(0): WebSocket正在嘗試連接

    1.2 OPEN(1): 已經連接

    1.3 CLOSING(2): 正在關閉連接

    1.4 CLOSED(3): 已經關閉連接

WebSocket與服務器通信步驟
  1. WebSocket.Constructor(url,[DOMString protocols]);創建WebSocket對象

  2. 發送信息: WebSocket對象的send()

  3. 接收信息: WebSocket對象的onmessage屬性綁定函數;

    實現客戶端多人聊天,JAVA為例

客戶端代碼:var web_socket =new WebSocket("ws://域名:端口");web_socket.onopen =function(){ web_socket.onmessage =function(event){ document.getElementById('show').innerHTML += event.data +"</br>" }};var sendMsg =function(val){ var inputElement = document.getElementByID('msg'); webSocket.send(inputElement.value); inputElement.value="";}...服務端代碼<article class="post" style="margin: 0px; padding: 30px 0px; border-bottom: 1px solid rgb(221, 221, 221); border-top: 1px solid rgb(255, 255, 255); position: relative; color: rgb(102, 102, 102); font-family: HelveticaNeue-Light, &quot;Helvetica Neue Light&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 300; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(238, 238, 238);">import java.io.*;import java.net.*;import java.nio.charset.Charset;import java.security.MessageDigest;import java.util.regex.*;import java.util.*;import sun.misc.BASE64Encoder;public class ChatServer{ // 記錄所有的客戶端Soccket public static List<Socket> clientSockets = new ArrayList<Socket>();public ChatServer()throws IOException{ // 創建ServerSocket,準備接受客戶端連接 ServerSocket ss = new ServerSocket(30000); while(true) { // 接收到客戶端連接 Socket socket = ss.accept(); // 將客戶端Socket添加到clientSockets集合中 clientSockets.add(socket); // 啟動線程 new ServerThread(socket).start(); }}public static void main(String[] args) throws Exception{ new ChatServer();}}class ServerThread extends Thread{ private Socket socket; public ServerThread(Socket socket) { this.socket = socket; } public void run() { try { // 得到Socket對應的輸入流 InputStream in = socket.getInputStream(); // 得到Socket對應的輸出流 OutputStream out = socket.getOutputStream(); byte[] buff = new byte[1024]; String req = ""; // 讀取數據,此時建立與WebSocket的"握手"。 int count = in.read(buff); // 如果讀取的數據長度大於0 if(count > 0) { // 將讀取的數據轉化為字符串 req = new String(buff , 0 , count); System.out.println("握手請求:" + req); // 獲取WebSocket的key String secKey = getSecWebSocketKey(req); System.out.println("secKey = " + secKey); String response = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: " + "websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: " + getSecWebSocketAccept(secKey) + "\r\n\r\n"; System.out.println("secAccept = " + getSecWebSocketAccept(secKey)); out.write(response.getBytes()); } int hasRead = 0; // 不斷讀取WebSocket發送過來的數據 while((hasRead = in.read(buff)) > 0){ System.out.println("接收的字節數:" + hasRead); /* 因為WebSocket發送過來的數據遵循了一定的協議格式, 其中第3個〜第6個字節是數據掩碼。 從第7個字節開始才是真正的有效數據。 因此程序使用第3個〜第6個字節對後面的數據進行了處理 */ for (int i = 0 ; i < hasRead - 6 ; i++ ){ buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]); } // 獲得從瀏覽器發送過來的數據 String pushMsg = new String(buff , 6 , hasRead - 6 , "UTF-8"); // 遍歷Socket集合,依次向每個Socket發送數據 for (Iterator<Socket> it = ChatServer.clientSockets.iterator() ; it.hasNext() ;) { try { Socket s = it.next(); // 發送數據時,第一個字節必須與讀到的第一個字節相同 byte[] pushHead = new byte[2]; pushHead[0] = buff[0]; // 發送數據時,第二個字節記錄發送數據的長度 pushHead[1] = (byte) pushMsg.getBytes("UTF-8").length; // 發送前兩個字節 s.getOutputStream().write(pushHead); // 發送有效數據 s.getOutputStream().write(pushMsg.getBytes("UTF-8")); } catch (SocketException ex) { // 如果捕捉到異常,表明該Socket已經關閉 // 將該Socket從Socket集合中刪除 it.remove(); } } } } catch (Exception e) { e.printStackTrace(); } finally { try { // 關閉Socket socket.close(); } catch (IOException ex) { ex.printStackTrace(); } }}// 獲取WebSocket請求的SecKeyprivate String getSecWebSocketKey(String req){ //構建正則表達式,獲取Sec-WebSocket-Key: 後面的內容 Pattern p = Pattern.compile("^(Sec-WebSocket-Key:).+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); Matcher m = p.matcher(req); if (m.find()) { // 提取Sec-WebSocket-Key String foundstring = m.group(); return foundstring.split(":")[1].trim(); } else { return null; }}// 根據WebSocket請求的SecKey計算SecAcceptprivate String getSecWebSocketAccept(String key) throws Exception{ String guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; key += guid; MessageDigest md = MessageDigest.getInstance("SHA-1"); md.update(key.getBytes("ISO-8859-1") , 0 , key.length()); byte[] sha1Hash = md.digest(); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(sha1Hash);}}[javascript](//mzkmzk.github.io/blog/categories/javascript/)</article><a class="addthis_button_facebook_like" fb:like:layout="button_count" style="margin: 0px; padding: 0px; text-decoration: none; outline-width: 0px; color: rgb(37, 143, 184);"></a><a class="addthis_button_tweet" style="margin: 0px; padding: 0px; text-decoration: none; outline-width: 0px; color: rgb(37, 143, 184);"></a>

最後在說幾句:

  1. 厲害程序員相對於普通程序員的優勢在於:

  2. 寫出的代碼更容易排錯,不是高手的代碼就不會錯,而是高手的代碼出了錯容易找。高手的代碼可讀性一定很好,模塊清晰,命名規範,格式工整,關鍵的地方有註釋,出了異常有log,自然容易排錯,即使交給別人去debug也是比較容易的。

  3. 今天這個圖片彈窗特效到這裡寫完了,學習web前端的可以加我的群,每天分享對應的學習資料:657137906,歡迎初學和進階中的小夥伴。多寫多練。

相關推薦

推薦中...