chatwork插件
##chatwork简介
Chatwork是一个结合了聊天室与任务分配的一个在线系统。
##编写插件的原因
因为Chatwork新消息到来时不会有任何提示。所以需要经常查看页面否则会使得回复速度变慢降低聊天的效率。
##技术思路
插件的功能是有新消息到来时,提醒用户。
提醒方式还没有确定。
新消息到来,聊天页面会改变。改变的内容就是新的内容。新消息可以从页面中获取或者从与服务器交互中的表单获取。
所以可以通过检测页面结构(DOM)是否改变。如果改变则执行提醒函数即可。
###第一版
先给页面挂事件。通过google查找到页面改变对应的事件名是DOMSubtreeModified
,在控制带中输入$
发现chatwork有使用jQuery
。那么事情就简单了。直接使用jQuery
添加事件即可。代码如下。
1 | $(".chatTimeLine").bind("DOMSubtreeModified", function() { |
####测试
经过测试新消息到来时能够弹出提示框
####缺点
因为监听的是事件改动,所以对于新消息来的这个需求吻合得不够。目前有一下缺点。
- 页面其他变动也会有提示
- 一个新消息多次弹窗
- 提醒的方式不够友好
###第二版
第一版中使用了DOMSubtreeModified
事件,这个事件范围太广,来一次消息往往会多次改变DOM子节点,所以再次Google找到了新的事件监听方案——使用MutationObserver
MutationObserver给开发者们提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力.该API设计用来替换掉在DOM3事件规范中引入的Mutation事件 ——Mozilla Develop
使用MutationObserver
有几个步骤
编写回调函数
在发生相应的事件时就会调用回调函数,代码如下1
2
3
4
5
6observer = new (
window.MutationObserver ||window.WebKitMutationObserver)(function(mutationRecord,observer){
mutationRecord.forEach(function(mutation){
console.log(mutation)
})
})其中
mutationRecord
和observer
是调用回调函数时浏览器传入的参数。注册事件监听
向浏览器注册要监听的事件。注: childList, attributes, 或者characterData三个属性中必须至少有一个为true.否则,会抛出异常”An invalid or illegal string was specified”.
这里选择childList
作为监听事件。因为来新消息的时候,DOM必定会增加子节点,所以childList
必定会改变。相应的代码如下所示1
2
3target = $(".chatTimeLine")[0]
config = {childList:true}
observer.observe(target,config);其中
target
必须是DOM对象。所以使用取数组元素的方式将jQuery
对象转换为DOMObject
。
####测试
从控制台中看到返回两个Mutation
,其中包含了每个改变的节点。
####缺点
换用了MutationObserver
后,缩小了监控范围。使得事件更贴切需求。
页面其他变动也会有提示- 一个新消息两次弹窗
- 提醒的方式不够友好
###第三版
事件部分已经基本解决。接下来要解决提示部分。弹框实在是太不友好了。这里想到了HTML5的新特性之一桌面通知
桌面通知的效果是这样的。
先找到桌面通知的相关文档来学习使用桌面通知
Notification 对象使用来为用户设置和显示桌面通知。——Mozilla Develop
在使用通知前必须先申请权限,申请权限的代码如下
1 | window.Notification.requestPermission() |
实例代码如下
1 | new window.Notification("有新消息",{body:"消息内容"}) |
提醒的标题可以改为说话者,消息内容既是接受到的内容。所以现在要获取消息的说话者和消息内容。
通过使用jQuery
可以轻松的获取,通过观察DOM结构即可得到一下代码。
1 | var chatName = $(".chatName").last().find("span").text(); |
与上面提示的代码结合,稍微修改后如下
1 | show = function(){ |
####测试
这次弹出两次提示。原因是chatwork网站消息机制。至此基本功能已经开发完毕。但还有一些问题待解决
页面其他变动也会有提示- 一个新消息两次弹窗
提醒的方式不够友好- 提示不会自动关闭
- 提示信息不够完善
###第四版
接下来解决一些主要问题。
一个新消息两次弹窗
一开始尝试了将提醒函数设定为只运行一次。之后发现只有第一次来消息时提示。后面就没有提示了。因为提醒函数运行一次就不会运行第二次了。思考良久,没有找到比较好的解决方案。在Snatic的提醒下,恍然开悟。只需要判断这两次的内容是否相同即可。代码如下1
2
3
4
5
6
7
8var avatarSpeaker = $(".avatarSpeaker").last().find("img").attr("src");//说话者
var speakTime = $(".timeStamp").last().text();//讲话时间
if(message === last["message"] && speakTime === last["speakTime"] && chatName === last["chatName"]){
//什么事都不做
}else{
last["message"] = message
last["speakTime"] = speakTime
}提示不会自动关闭
添加计时函数,三秒后关闭对话框即可。1
2var n = new window.Notification(chatName,{body:message})
setTimeout(function(){n.close();},3000)提示信息不够完善
提示信息的左边是空白的比较难看。所以根据文档稍加修改,添加说话人的头像,提醒代码修改如下。1
2
3var avatarSpeaker = $(".avatarSpeaker").last().find("img").attr("src");
var n = new window.Notification(chatName,{icon:avatarSpeaker,body:message})
setTimeout(function(){n.close();},3000)至此已经解决剩余的问题。目前功能较为完善。最终代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38(function(){
window.Notification.requestPermission()
last = []
last["message"] = "tuoxiedafahao"
last["speakTime"] = "15:21"
last["chatName"] = "tuoxiedang"
show = function(){
var chatNameArray = $(".chatName");
var i = chatNameArray.length;
while(i--){
if(chatNameArray.eq(i).text() !== "") break;
}
var chatName = $(".chatName").eq(i).find("span").text();
var message = $("div.chatTimeLine div._message").last().find("pre").text();
var avatarSpeaker = $(".avatarSpeaker").last().find("img").attr("src");
var speakTime = $(".timeStamp").last().text();
var myName = $(".myStatusName").text();
if(message === last["message"] && speakTime === last["speakTime"] && chatName === last["chatName"]){
}else if (myName === chatName){
console.log("you say it")
} else{
var n = new window.Notification(chatName,{icon:avatarSpeaker,body:message})
setTimeout(function(){n.close();},3000)
last["message"] = message
last["speakTime"] = speakTime
last["chatName"] = chatName
}
}
observer = new (window.MutationObserver||window.WebKitMutationObserver)(show)
target = $(".chatTimeLine")[0]
config = {childList:true}
observer.observe(target,config);
})()
###测试
效果跟一开始想法差不多。
##后记
这篇文章在我插件完成两个星期后才写完。其中还有一些功能没有介绍就突然在最终代码里面出现了。改天有空再来填坑吧。(改天根本就不会想起来好吧!摔!)