大家好我是测不准,目前从事前端开发,第一次在掘金写文章,分享下项目开发中学习使用的web端实时协作工具togetherjs库。项目需要多端实现数据同步:A在自己的页面操作,也要相应的在B、C的页面中有变化;togetherjs在web端引用也相对容易,还有自己的服务端后台,通过websocket分发数据。如果写的有不对,请大佬指正。
togetherjs简介
TogetherJS是由Mozilla打造的一款可以给网站添加实时协作功能的JavaScript库,功能有:数据同步,数据分发,文本聊天,音视频,github地址。(虽然库好久没更新了,但是还是很好用的😂)
直接上手
新建test.html, 引入最简单代码
<!--<script src="https://togetherjs.com/togetherjs-min.js"></script>-->
<script src="https://togetherjs.com/togetherjs.js"></script>// 稍后使用本地文件,所以使用这个引用
<button onclick="TogetherJS(this); return false;">Start TogetherJS</button>
点击按钮效果如下图 (如果网络不好响应会很慢)

如果你不想使用网络链接,可以把togetherjs文件下载到本地,下载的地址要使用https://togetherjs.com/togetherjs.js,min的js文件不足,内部有处理所以不能直接下载使用
点击按钮做了哪些操作
让我们打开控制台,看到没有点击按钮时候html头部head的结构

点击按钮后的head结构 (使用min.js的朋友可以自行查看不同) (网慢的朋友请等待)

这时很多人就会像我一样丈二的尼姑摸不到头脑。为什么突然增加了这么多的文件,都是做什么用的。其实对着data-requiremodule变量和togetherjs的功能,大概能猜出各个文件的用途。包括日志,聊天,webrtc,样式,存储等等(其实我也还没全了解😁)。但是就是这些文件,实现了togetherjs的功能。咱们继续往下看。
下载github库
从新增加的script标签中我们看到文件基本都来自togetherjs文件夹下,从github目录结构中我们看到有togetherjs文件夹,里面正好有这些js文件,所以克隆下来方便我们查看。
- git clone github.com/jsfiddle/to…, 默认是develop分支。文件目录结构如下,主要是下面两个文件夹,一个是togetherjs,需要引入的文件夹,一个是hub,ws服务端的文件夹。

到这里大家可以按照github的步骤启动他们的项目。这里我就把代码单独提取出来,起个自己的简单的togetherjs项目。
创建自己的demo
新建together目录,内部新建togetherjs文件夹(把线上文件本地化,加快访问),按照head中新增的标签,大家应该能看到需要导入什么文件,稍后再说怎么改请求的地址; 创建server文件夹,存放服务端文件,对应hub文件夹,服务端依赖如下:
"dependencies": {
"websocket": "~1.0.7",
"websocket-server": "github:miksago/node-websocket-server#master"
},
"devDependencies": {
"optimist": "~0.6.0"
},
修改服务端地址,在server.js中的地址为本地;启动服务


接下来我们启动客户端
新建index.html, 引入togetherjs,引入togetherjs 和 butotn启动按钮
<script src="./togetherjs/together.js"></script>
<button id="start-togetherjs" onclick="TogetherJS(this); return false;" data-end-togetherjs-html='结束'>Start TogetherJS</button>
我们会发现新增的域名地址都是https://togetherjs.com,怎么改成本地呢,需要查看下togetherjs内部代码,在77行位置,我们可以看到
var baseUrl = "https://togetherjs.com";, 把地址改为"http://127.0.0.1:8848/together"(大家根据自己的服务地址修改,后面的together是我的文件夹),大家要记得把75行的css文件,对应的fonts和images文件夹也要和togetherjs放一起。这时我们再点击开始按钮,这是飞翔的感觉~~。这波操作很帅😎
地址都变成了本地

点击按钮我们会发现控制台有错,这是为什么呢

defaultHubBase,修改这个值为自己的地址http://127.0.0.1:8080; 还有一种方法是在引入togetherjs之前,定义配置变量TogetherJSConfig_hubBase ="http://127.0.0.1:8080",定义变量的时候不用加var。从源码里可以看到它会循环查找一下全局变量,格式如果是TogetherJSConfig_hubBase, 会做一个默认配置的替换(看源码长知识啊),所以变量的定义要放在引入togetherjs之前。
浏览器打开两个地址, 两边同步了!!!

一个里面输入聊天,另一个会得到通知


修改配置
如果我们想修改名字,头像,颜色这些配置,透过官网我们能找到答案。透过togetherjs文件的defaultConfiguration字段我们也能找到配置,注意 这三个字段都是函数

添加配置内容, 我们即可在页面看到不同的显示
<script type="text/javascript">
TogetherJSConfig_hubBase ="http://127.0.0.1:8080"
// random 为了区分不同的用户
TogetherJSConfig_getUserName = function () {return ('测不准' + Math.random()).substring(0,8);};
TogetherJSConfig_getUserAvatar = function () {return 'https://togetherjs.com/images/site-features-user-presence@2x.png';};
TogetherJSConfig_getUserColor = function () {return 'pink';};
</script>
<script src="./togetherjs/together.js"></script>
- 要根据不同房间区分,定义配置
// prefix 是房间名, max是最多人数。 后面看服务端代码即可知道怎么分发数据
TogetherJSConfig_findRoom = {prefix: "uncertainty", max: 6};
触发事件与监听
由于每个人对着不同的界面,通过togetherjs可以看到别人的操作,但是别人在自己页面如果有事件改变, 别人的界面无法触发(例如一个js 的alert)。togetherjs为我们定义了数据的发送与监听
TogetherJS.send 发送事件
TogetherJS.hub.on 事件监听
- 下面我们写个简单地切换图片的例子, 使用vue实现(如果不用事件会发现只能一个界面改变,其他的不会变)

引入vue的cdn,简单的实现点击切换
new Vue({
el:'#app',
data: {
imgList: ['./img/1.jpg','./img/2.jpg','./img/3.jpg','./img/4.jpg'],
index:0
},
mounted() {
let _this = this
TogetherJS.hub.on("reuvenTest", function (msg) {
console.log("我收到了: " , msg)
_this.index = msg.index
});
},
methods: {
changeIndex() {
this.index++
if (this.index > 3) {
this.index = 0
}
TogetherJS.send({
type: "reuvenTest",
index: this.index,
});
}
}
})

可以发现,两边的数据实现同步。同时可以看到两页面布局不同,按钮位置不一样,但是点击的时候,按钮还会找到对应的位置,从控制台的日志中可以看到如下(具体打印在session文件中,具体怎么实现的我还没深入研究)


ws服务端的实现
主要内容在server.js文件中, 从http.createServer 方法可以看出,服务端的几个状态,/status,页面显示ok,表示服务成功,/load显示当前客户端链接数,页面active的数量等。

服务端实现了接收到信息,connection.on('message', function(message) {, 立即发出消息
// 房间号会有相应的**id**, 不会给其他房间的发信息
for (var i=0; i<allConnections[id].length; i++) {
var c = allConnections[id][i];
if (c == connection && !parsed["server-echo"]) {
continue;
}
if (message.type === 'utf8') {
// **sendUTF 发送信息在compact文件中与 send方法对应**
c.sendUTF(message.utf8Data);
} else if (message.type === 'binary') {
c.sendBytes(message.binaryData); // 暂未定义
}
}
在server文件最后又学到一个知识点 if (require.main == module), 如果是node直接运行,则判断为true, 如果是其他文件引用,则为 false
下面写个简单的websocket链接到 服务端
var ws = new WebSocket("ws://192.168.10.59:8080/hub/uncertainty__bCJMJqJnBt");
ws.onopen = (evt) => {
console.log('连上')
}
ws.onmessage = (evt) => {
console.info('收到信息', evt.data)
}
ws.onerror = () => {
console.info('服务出错了')
}
ws.onclose = () => {
console.info('服务关闭了')
}
let btn = document.querySelector('#send')
btn.onclick = () => {
// 发送字符串,如果需要对象,转换为字符串。
ws.send('{"name":"测不准","age":123}')
}
打开多个界面,一个界面发送信息,其他界面可以收到信息。这样服务端代码可以直接使用,真香
注:如果有其他的客户端服务如u3d的ws,只要连接了同一个server端,同样可以收到信息
最后
这是我第一次在掘金写分享,也参考了官网和网上的一些资料,如果对你有帮助就最好不过了。一直以来也从掘金社区也学到了很多,野百合也是要春天的,也希望新的一年能继续进步。 如果文章中有不对的地方请多指正,如果有建议也希望大家指点一二,谢谢阅读!