參考資料
零、Introduce
- WebSocket 規(guī)范定義了一種 API唧垦,可在網(wǎng)絡(luò)瀏覽器和服務(wù)器之間建立“套接字”連接旷痕。簡單地說:客戶端和服務(wù)器之間存在持久的連接,而且雙方都可以隨時開始發(fā)送數(shù)據(jù)。
- 對于我們來說贯被,用來做即時通訊跟H5交互游戲都是不錯的選擇鞭光。
- 注意事項:目前有部分瀏覽器不支持websocket,同時笋庄,使用websocket也必須服務(wù)器支持websocket效扫,有些代理服務(wù)器也不支持websocket。檢驗方法可參考 阮一峰教程直砂。
一菌仁、Example
時間軸側(cè)邊欄
時間軸主頁
- 其中,時間軸的主題內(nèi)容便是使用websocket從服務(wù)器獲取json格式數(shù)據(jù)静暂,使用
onmessage
監(jiān)聽事件實(shí)時響應(yīng)渲染內(nèi)容济丘。相比Ajax,響應(yīng)速度更好;劣勢是websocket是多個用戶在一個會話層摹迷,用戶量過高時會影響性能疟赊。
二、Syntax
1. 連接&斷開
if(window.WebSocket != undefined) { // 檢測是否支持websocket
var connection = new WebSocket(socketUrl);
// readyState為open時觸發(fā)
connection.onopen = function wsOpen(event) {
console.log("Connected to localhost:8080");
};
// readyState為close時觸發(fā)
connection.onclose = function wsClose() {
console.log("WebSocket is closed")
};
// 客戶端收到服務(wù)端信息觸發(fā)
connection.onmessage = function wsMessage(event) {
var msg = JSON.parse(event.data);
myRender(msg.info);
gotoPage();
};
}
2. 信息處理
connection.send( message ); // 發(fā)送信息
connection.onmessage = wsMessage; // 接收信息
function wsMessage( event ) {
console.log( event.data );
}
connection.onerror = wsError; // 處理錯誤信息
- 上面代碼的回調(diào)函數(shù)wsMessage的參數(shù)為事件對象
event
峡碉,該對象的data
屬性包含了服務(wù)器返回的數(shù)據(jù)近哟。
三、代碼介紹
- websocket.js:需要引入
ws
模塊
/*
* author: Stngle
* e-mail: 1113591198@qq.com
*/
// 獲取一個websocket server對象
var WebSocketServer = require('ws').Server;
// 創(chuàng)建ws服務(wù)器
var ws = new WebSocketServer({
port: 1234 // 監(jiān)聽的端口
});
// 設(shè)置發(fā)送給客戶端的數(shù)據(jù)
var sendData = {
info:[
{
id: "00000000",
time: "0:00--0:27",
imgSrc: "../images/00000001.png",
sort: "movie",
title:"微微一笑很傾城",
brief: "導(dǎo)演:趙天宇<br/>主演:Angelababy/井柏然/李沁/譚松韻/李現(xiàn)",
locationUrl: "http://www.baidu.com",
collection: "favorite_border"
},
{
id: "00000001",
time: "0:00--0:27",
imgSrc: "../images/00000001.png",
sort: "movie",
title:"微微一笑很傾城",
brief: "導(dǎo)演:趙天宇<br/>主演:Angelababy/井柏然/李沁/譚松韻/李現(xiàn)",
locationUrl: "http://www.baidu.com",
collection: "favorite"
}
]
};
// 將發(fā)送數(shù)據(jù)decode為JSON格式
var sendDataDecode = JSON.stringify(sendData);
// 處理連接
ws.on('connection',
function(socket) {
socket.onmessage = message;
socket.onclose = close;
socket.onerror = error;
socket.onopen = open;
socket.send(sendDataDecode, function() {
console.log("data has send");
})
});
function message(msg){
//對接收到的消息做些什么
}
function error(err){
// 消息出錯做什么
console.log(err);
}
function close(){
// 會話關(guān)閉做什么
console.log("socket closed");
}
function open(){
// 會話打開時
console.log("socket opened");
}
node websocket.js // 運(yùn)行該文件作為本地服務(wù)端
- main.js:直接運(yùn)行即可
/*
* author: Stngle
* e-mail: 1113591198@qq.com
*/
/*
* 全局配置參數(shù)
*/
var socketUrl = "ws://localhost:1234"; // 配置websocket URL
/*
* 主函數(shù)入口
*/
$(document).ready(function() {
sideBar();
webSocket();
});
/*
* sidebar:用于側(cè)邊欄菜單交互
*/
function sideBar() {
// nav-left
$("#menu").on("click",function(ev){
$(".sidebar").animate({"left":0},500);
ev.preventDefault();
$("body").after("<div class='shade-layer'></div>");
// shade-layer:hide
$(".shade-layer").on("click",function(ev){
$(".sidebar").animate({"left":"-100%"},500);
$(".shade-layer").remove();
})
});
// close -> shade-layer:hide
$("#close").on("click",function(ev){
ev.preventDefault();
$(".sidebar").animate({"left":"-100%"},500);
$(".shade-layer").remove();
});
$("body").on("touchstart",function(ev){
startx = ev.originalEvent.targetTouches[0].pageX;
});
$("body").on("touchend",function(ev){
endx = ev.originalEvent.changedTouches[0].pageX;
if (endx - startx > 20) {
$(".sidebar").animate({"left":0},500);
$("body").after("<div class='shade-layer'></div>");
// shade-layer:hide
$(".shade-layer").on("click",function(ev){
$(".sidebar").animate({"left":"-100%"},500);
$(".shade-layer").remove();
})
}else if (endx - startx < -20) {
$(".sidebar").animate({"left":"-100%"},500)
$(".shade-layer").remove();
}
});
}
/*
* 渲染info list的模板鲫寄,文本<br/>有效吉执,若要限制字?jǐn)?shù)可以在以下函數(shù)使用slice()方法
* 二級跳轉(zhuǎn)鏈接放在.title的gotoUrl屬性中,供監(jiān)聽器gotoPage()回調(diào)時讀取
*/
function myRender(infos) {
$(infos).map(function(index,info) {
$(".info-list").append(
'<div class="info">'+
'<img src="' + info.imgSrc + '"/>' +
'<div class="text">' +
'<a class="title" gotoUrl="' + info.locationUrl + '"><span>' + info.title + '</span></a>' +
'<i class="material-icons">' + iconSort(info) + '</i>' +
'<p class="brief">' + info.brief + '</p>' +
'<p><i class="material-icons">' + info.collection + '</i><i class="material-icons">share</i></p>' +
'</div>' +
'</div>'
);
})
}
/*
* icon 分類地来,根據(jù)websock傳來的info.sort渲染icon
*/
function iconSort(info) {
if(info.sort === "movie") {
return "movie";
}else if(info.sort === "") {
return "";
}else {
return "";
}
}
/*
* websocket部分:
*/
function webSocket() {
// 與本機(jī)的8080端口建立連接
if(window.WebSocket != undefined) {
var connection = new WebSocket(socketUrl);
// readyState為open時觸發(fā)
connection.onopen = function wsOpen(event) {
console.log("Connected to localhost:8080");
};
// readyState為close時觸發(fā)
connection.onclose = function wsClose() {
console.log("WebSocket is closed")
};
// 客戶端收到服務(wù)端信息觸發(fā)
connection.onmessage = function wsMessage(event) {
var msg = JSON.parse(event.data);
myRender(msg.info);
gotoPage();
};
}
}
/*
* 跳轉(zhuǎn)二級頁面的渲染示例
* 先獲取gotoUrl屬性存儲的地址戳玫,再移除原有info-list中的內(nèi)容,再生成新的二級頁面
*/
function gotoPage() {
$(".title").on("click", function() {
var gotoUrl = $(this).attr("gotoUrl");
$(".info-list").empty();
$(".info-list").append(
"<div class='pageSecondary'><a href='" + gotoUrl + "'><button>閱讀原文</button></a></div>"
)
})
}
- index.html:作為本project的入口文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>時間軸</title>
<link rel="stylesheet">
<link rel="stylesheet" href="main.css">
</head>
<body>
<!-- topbar -->
<nav>
<a id="menu"><span class="nav-left"><i class="material-icons">menu</i></span></a>
<span class="nav-right"><i class="material-icons">collections</i></span>
</nav>
<!-- sidebar -->
<div class="sidebar">
<ul>
<a >
<li class="sidebar-li sidebar-first"><i class="material-icons">find_in_page</i><span class="font">登錄</span><i class="material-icons sidebar-right" id="close">menu</i></li></a>
<a href="#">
<li class="sidebar-li"><i class="material-icons">autorenew</i><span class="font">刷新</span></li>
</a>
<a href="#">
<li class="sidebar-li"><i class="material-icons">find_in_page</i><span class="font">幫助&反饋</span></li>
</a>
<a href="#">
<li class="sidebar-li"><i class="material-icons">settings</i><span class="font">設(shè)置</span></li>
</a>
<a href="#">
<li class="sidebar-li"><i class="material-icons">highlight_off</i><span class="font">注銷</span></li>
</a>
</ul>
</div>
<!-- 橫幅封面圖 -->
<div class="cover">
<img src="../images/cover.png" alt="封面圖片">
</div>
<!-- info list -->
<div class="info-list">
</div>
<!-- <i class="material-icons">favorite</i> -->
<script src="../jquery-3.1.1.js"></script>
<script src="main.js"></script>
</body>
</html>
- main.css:作為index.html的樣式表
*{
margin: 0;
}
nav{
background-color: rgb(2,168,243);
padding-left: 5%;
padding-right: 5%;
padding-bottom: 6px;
padding-top: 6px;
}
i{
padding-top: 5px;
padding-bottom: 5px;
}
.nav-left{
color: #FFFFFF;
}
.nav-right{
color: #FFFFFF;
float: right;
}
.cover img{
width: 100%;
height:
}
/* sidebar */
.shade-layer{
position: absolute;
left: 0%;
top: 0%;
background-color: rgba(0,0,0,0.7);
width: 100%;
height: 100%;
z-index: 99;
}
.sidebar{
position: absolute;
left: -100%;
top: 0;
height: 100%;
width: 70%;
background-color: #fff;
z-index: 999;
}
.sidebar ul{
padding: 0;
}
.sidebar a{
color: #000;
text-decoration: none;
height: auto;
}
.sidebar-li{
padding: 6px 5%;
border-bottom: solid 1px #eee;
list-style: none;
background-color: #ffffff;
}
.sidebar-first{
background-color: rgb(2,168,243);
padding: 6px 5%;
font-size: 0.9em;
}
.sidebar-right{
float: right;
}
.font{
padding-left: 5px;
vertical-align: 3px;
}
#menu{
display: inline-block;
}
/*info list*/
.info img{
padding: 8px 2%;
display: inline-block;
border-radius: 40px;
width: 18%;
height: 18%;
vertical-align: top;
}
.text{
width: 70%;
display: inline-block;
}
.text a{
color: rgb(12,140,243);
font-weight: bold;
line-height: 20px;
margin-left: 5%;
padding-left: 20px;
border-left: solid 2px rgb(64,148,199);
}
.text span{
position: relative;
top: 25px;
}
.text >i:first-of-type{
display: block;
}
.text p{
color: #333;
margin-left: 5%;
padding-left: 20px;
border-left: solid 2px rgb(2,168,243);
}
p i:first-of-type{
margin-left: 60%;
color: #999;
}
p i{
color: #999;
margin-left: 5%;
}