参考资料
零、Introduce
-
WebSocket 规范定义了一种 API,可在网络浏览器和服务器之间建立“套接字”连接。简单地说:客户端和服务器之间存在持久的连接,而且双方都可以随时开始发送数据。
- 对于我们来说,用来做即时通讯跟H5交互游戏都是不错的选择。
- 注意事项:目前有部分浏览器不支持websocket,同时,使用websocket也必须服务器支持websocket,有些代理服务器也不支持websocket。检验方法可参考 阮一峰教程。
一、Example
- 其中,时间轴的主题内容便是使用websocket从服务器获取json格式数据,使用
onmessage
监听事件实时响应渲染内容。相比Ajax,响应速度更好;劣势是websocket是多个用户在一个会话层,用户量过高时会影响性能。
二、Syntax
1. 连接&断开
if(window.WebSocket != undefined) { // 检测是否支持websocket
var connection = new WebSocket(socketUrl);
// readyState为open时触发
connection.onopen = function wsOpen(event) {
console.log("Connected to localhost:8080");
};
// readyState为close时触发
connection.onclose = function wsClose() {
console.log("WebSocket is closed")
};
// 客户端收到服务端信息触发
connection.onmessage = function wsMessage(event) {
var msg = JSON.parse(event.data);
myRender(msg.info);
gotoPage();
};
}
2. 信息处理
connection.send( message ); // 发送信息
connection.onmessage = wsMessage; // 接收信息
function wsMessage( event ) {
console.log( event.data );
}
connection.onerror = wsError; // 处理错误信息
- 上面代码的回调函数wsMessage的参数为事件对象
event
,该对象的 data
属性包含了服务器返回的数据。
三、代码介绍
/*
* author: Stngle
* e-mail: 1113591198@qq.com
*/
// 获取一个websocket server对象
var WebSocketServer = require('ws').Server;
// 创建ws服务器
var ws = new WebSocketServer({
port: 1234 // 监听的端口
});
// 设置发送给客户端的数据
var sendData = {
info:[
{
id: "00000000",
time: "0:00--0:27",
imgSrc: "../images/00000001.png",
sort: "movie",
title:"微微一笑很倾城",
brief: "导演:赵天宇<br/>主演:Angelababy/井柏然/李沁/谭松韵/李现",
locationUrl: "http://www.baidu.com",
collection: "favorite_border"
},
{
id: "00000001",
time: "0:00--0:27",
imgSrc: "../images/00000001.png",
sort: "movie",
title:"微微一笑很倾城",
brief: "导演:赵天宇<br/>主演:Angelababy/井柏然/李沁/谭松韵/李现",
locationUrl: "http://www.baidu.com",
collection: "favorite"
}
]
};
// 将发送数据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(){
// 会话关闭做什么
console.log("socket closed");
}
function open(){
// 会话打开时
console.log("socket opened");
}
node websocket.js // 运行该文件作为本地服务端
/*
* author: Stngle
* e-mail: 1113591198@qq.com
*/
/*
* 全局配置参数
*/
var socketUrl = "ws://localhost:1234"; // 配置websocket URL
/*
* 主函数入口
*/
$(document).ready(function() {
sideBar();
webSocket();
});
/*
* sidebar:用于侧边栏菜单交互
*/
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/>有效,若要限制字数可以在以下函数使用slice()方法
* 二级跳转链接放在.title的gotoUrl属性中,供监听器gotoPage()回调时读取
*/
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 分类,根据websock传来的info.sort渲染icon
*/
function iconSort(info) {
if(info.sort === "movie") {
return "movie";
}else if(info.sort === "") {
return "";
}else {
return "";
}
}
/*
* websocket部分:
*/
function webSocket() {
// 与本机的8080端口建立连接
if(window.WebSocket != undefined) {
var connection = new WebSocket(socketUrl);
// readyState为open时触发
connection.onopen = function wsOpen(event) {
console.log("Connected to localhost:8080");
};
// readyState为close时触发
connection.onclose = function wsClose() {
console.log("WebSocket is closed")
};
// 客户端收到服务端信息触发
connection.onmessage = function wsMessage(event) {
var msg = JSON.parse(event.data);
myRender(msg.info);
gotoPage();
};
}
}
/*
* 跳转二级页面的渲染示例
* 先获取gotoUrl属性存储的地址,再移除原有info-list中的内容,再生成新的二级页面
*/
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 href="http://cdn.bootcss.com/material-design-icons/3.0.1/iconfont/material-icons.css" 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 href="https://baidu.com">
<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">设置</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%;
}