浮叶蓝空的博客
分享学习心得,记录学习笔记
文章:
84
访问:
526039
登录
关于
首页
今天是:
2025年09月09日 星期二
类别
PHP(39)
其他笔记(20)
Java(1)
C++(17)
mysql(2)
JavaScript(4)
近期文章
Linux下Cmake引用第三方静态库示例
Linux下使用Cmake构建静态库示例
Ubuntu设置自动挂载硬盘,挂载U盘
压力测试工具Apache JMeter基本使用
使用PHP脚本借助FFmpeg一键合并视频
Shell中的>、1>、2>、2>&1、&>详解
PHP开启多进程实现异步非阻塞并行执行任务
博主推荐
PHP实现文件下载接口
Qt读写注册表,C++读写注册表
PHP动态修改配置文件,存储为文件
MySql常用语法
Powershell远程连接
PHP从字符串中获取需要的内容部分
封装PHP的HTTP请求
后台自定义消息通知
fuyelk
2019年08月31日
3420
# 基于Jquery的消息弹窗 ## 特性 - 进入后台自动与服务端建立Websocket连接 - 在模板中创建,后台任意界面都可以看到消息。 - 消息可设置链接 - 可设置消息事件,如语音提醒 [](https://www.milinger.com/a154.html "基于Jquery的消息弹窗样式") ## 使用说明 **1.** 写一个绑定client_id和auth_id的接口**bindClientID()**,名字自定义 ```php /** * 给后台消息客户端绑定身份 * @return void * @author fuyelk <fuyelk@fuyelk.com> * @date 2024/6/27 17:46 */ public function bindClientID() { $client_id = $this->request->post('client_id'); if (empty($client_id)) { $this->error('请求有误'); } if (!Gateway::isOnline($client_id)) { $this->error('Client id 无效', ''); } // 记录消息框客户端ID $this->redis->hSet('fmsg_client', $client_id, $this->auth->id); $this->success('ok', '', ['client_id' => $client_id]); } ``` **2.** 用Workerman写一个定时任务,轮询在线客户端,逐个查询需要发送的消息 ``` /** * 分发后台消息 * @param Redis $redis * @return void * @author fuyelk <fuyelk@fuyelk.com> * @date 2024/6/27 17:48 */ private function dispatchBackendMsg(Redis $redis) { Timer::add(5, function () use ($redis) { // 遍历在线的后台Websocket客户端 $fmsgClientIDs = $redis->hGetAll('fmsg_client'); foreach ($fmsgClientIDs as $clientID => $auth_id) { // 删除离线的客户端 if (!Gateway::isOnline($clientID)) { $redis->hDel('fmsg_client', $clientID); continue; } // 按客户端权限查询消息 $authMsg = $this->getAuthMsg($auth_id); $msg = [ 'event' => 'notice', 'data' => $authMsg, 'data_md5' => md5(json_encode($authMsg, JSON_UNESCAPED_UNICODE)) ]; Gateway::sendToClient($clientID, json_encode($msg, JSON_UNESCAPED_UNICODE)); } }); } /** * 获取后台账号的消息 * @param int $auth_id * @return array * @throws \think\Exception * @author fuyelk <fuyelk@fuyelk.com> * @date 2024/6/27 17:38 */ private function getAuthMsg(int $auth_id): array { $data = []; // DEMO:在线用户数量 $data[] = [ 'title' => '在线用户数量', 'color' => 'green', 'url' => '', 'value' => User::count(), ]; return $data; } ``` **3.** 在后台框架的最底层**模板文件**中引入fuyelk.js(引入前需引入jquery), 如:` application/admin/view/index/index.html` 文件: ``` <script src="/assets/libs/jquery/dist/jquery.js"></script> <script src="/static/common/js/fuyelk.js"></script> <script> // 创建消息对象 var msg = new fmsg(); var lastMsgCount = 0; // 方法1:创建定时轮询的消息监听 msg.createInterval("index/getMsg", 5000, function (msg) { if (msg.msgCount > lastMsgCount) { new Audio('/assets/voice/notice.mp3').play(); } lastMsgCount = msg.msgCount; }); // 方法2:创建websocket监听 msg.createWsMessage('ws://127.0.0.1:8888', 'http://demo.localhost.com/index/bindClinetID', function (msg) { if (msg.msgCount > lastMsgCount) { new Audio('/assets/voice/notice.mp3').play(); } lastMsgCount = msg.msgCount; } ); </script> ``` ### 附: js中可用的方法 ``` 创建对象: var msg = new fmsg('消息框标题') 创建单条消息: msg.create(data); 创建列表消息: msg.createList(data) 显示消息: msg.show(); 关闭消息: msg.close(); 显示消息条: msg.showBar(); 关闭消息条: msg.closeBar(); 销毁消息: msg.destory(); 设置新消息事件:msg.onNewMessage(); 通过API获取消息(单次): msg.ajax('/api.html'); 推荐用法1:通过接口定时获取消息: msg.createInterval("index/getMsg", 5000, function (msg) { new Audio('/assets/voice/notice.mp3').play(); }); 推荐方法2:通过websocket获取消息: msg.createWsMessage('ws://127.0.0.1:8888', 'http://demo.localhost.com/index/bindClinetID', function (msg) { if (msg.msgCount > lastMsgCount) { new Audio('/assets/voice/notice.mp3').play(); } lastMsgCount = msg.msgCount; } ); ``` [=========] #### [点击下载:fuyelk-message.min.js](https://www.milinger.com/upload/202205/fuyelk-message.min.js "点击下载:fuyelk-message.min.js") ### fuyelk-message.js源码如下 ```javascript /** * 屏幕右下角消息弹窗,十秒钟自动退出 * * createtime :2019年8月20日 * updatetime :2022年5月3日 * Author: fuyelk<fuyelk@fuyelk.com> * * @param title 消息框标题 * * 可执行方法 * * 创建对象: var msg = new fuyelk("通知消息") * * 创建消息: msg.create(data); * * 创建列表消息: msg.createList(data) * * 显示消息: msg.show(); * * 显示消息条: msg.showBar(); * * 关闭消息: msg.close(); * * 关闭消息条: msg.closeBar(); * * 销毁消息: msg.destory(); * * 设置新消息事件:msg.onNewMessage(); * * 通过API获取消息: msg.ajax("/api.html"); * * 推荐用法1:通过接口定时获取消息: * msg.createInterval("index/getMsg", 5000, function (msg) { * new Audio('/assets/voice/notice.mp3').play(); * }); * * 推荐方法2:通过websocket获取消息: * msg.createWsMessage('ws://127.0.0.1:8888', 'http://demo.localhost.com/index/bindClinetID', * function (msg) { * if (msg.msgCount > lastMsgCount) { * new Audio('/assets/voice/notice.mp3').play(); * } * lastMsgCount = msg.msgCount; * } * ); */ function fmsg(title) { // 当前对象别名 var that = this; // 消息内容高度 this.msg_height = 300; // 消息框消失时间 this.msg_close_time = 10000; // 10秒 // 控制消息框消失定时器 var timer_close_msg; // 控制消息条显示的定时器 var timer_show_bar; // 默认轮询间隔时间 this.reqInterval = 60000; // 1分钟 // 展开图标 this.imgShow = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAACYElEQVRoge2XTYhNYRjHnzloQjSaUrJifI2Fna/bWCDUbBQNG5KFpCymJFKWYjFLKzYiSmymRDE+0l0ojY8i6Waa0iQlcrlqpvH7W8xRp+u875175557Uu9vfZ7/8//d2znnPWaBQCAQCAQCgUAN2rIMB+ab2VYzazezB1EUlbPclwnAMmAQ+An8AorAhrx71QWwDnisKoASsCXvftNCUg/wvloiITMK7M67pxdgO/DBJZGQKQMH8+6bCnAA+FpLokrmiKRMHzh1ARwCvjkKfwc+eYTO5t3fzMyAM0DFcz/0AgXgteOaSeCcpHl5CbTHEr8dBUeAnYnr1wJFzz9zOX7vtFRiAXDJU2oY2JgytxoY8sxdBZa0SqJT0hVPmWfASs/8YuCWZ34I6MpUQtJy4K6nxM3p/KLAQuCGK0fSE2BVJhJAF/DIJyGpY7p5kuZIuuDJewdsbrbEemDYs/SipEX15kqKgPOeB0YJKDRLogCMeCQGJM1uNF/SLKAf+OHI/wjsmZGEpD7gs2NBBTgxE4kkwDGg7NhVBvY3GrzPdeSIg482Q6Bq515gzLOzX1JUT+Bxz5FjVFJfsyUSu7fFO9J2TwCnaoZIagNOAhMuCWBHVhIJmU3AC0eHcWAAmOsLOOx5grxq5UcR0A08T+sSc9o3fM8h8RLobpXEXyStAR46Or1xDgLXUwbuACta2L+6UycwmNLrqXNIU5+ppfimqgC31cCLrtlI6gCuxZ0mgTGgN3nNP19n8YGvx8y+mNn9KIrGW9TXi6aONLvMbKmZFaMoept3p0AgEAgEAoHAf8YfRKNn4ePQT5UAAAAASUVORK5CYII="; // 收起图标 this.imgClose = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAACFElEQVRoge2XP2jUYBiH38RWRKTioFQQUeiigw4VKYhLBTcHqYObiwpOulVwEnFQcBB0EgRBxKUugtDFTbCCLg4dimhF6FBbcRCq4PNziRDP5E3uLl+yfM94l/f3J3yXvGcWiUQikUgkEolUkPR+IGm7pCkzW03T9F0HmUoBpsxsr5ktpGm67F14EFhSBvBI0mhrSR2Au7lca8Ax7+I59QDMA2MtZv4HSSPAk4JcryT9d6LMzAx40zuQDb2WNN5yB5O0DXhRkumDpLRwELhSNJQNLgITbZUAdmV3vSzPzSqB287wF0mTLZTYD7x3cjyUNFJHaNYRWQemA5Y4DCw7/nf6FbzgiG0AMwFKHAdWHd9rgwrPABuO8PkGS5wCfjhel4Y1mAbWHYPZBkqcA36X6P8Czg7rYWZmkiazH3pZmVtDlLjs6H4HTjZSImc4ASw6pg8G0Lzu6K0ARxst8RdJ49nLscx8TtKWmiXuOTpLwIEgJXIBxoB5J8RLSTvK5iVtAh4782+BPUFL5MKMAk/7DSNn5ahzE4IB3K97PICdFSvHM9U8lqHK3HDCrWRv6t0VK0ffD4ogVCyba8Bn5/uBH91B8F5qDle7zl1I1ZrRw8Wu87rUWPx+Ame6zlkL4BDwqaDEN+BE1/n6QtI+YCFX4iNwJJRf8Z/3hpC0WdJpM9uaJMnzJEm+hvSLRCKRSCQSiURc/gBmWEcdutN39wAAAABJRU5ErkJggg=="; // 标题 this.title = undefined === title ? "通知消息" : title; // 记录websocket连接状态 var ws_is_on = false; // 用于绑定client_id的url,ws连接成功后收到event=connect将请求改地址 var bind_client_id_url = ''; // 连接失败次数 var ws_connect_fail_times = 0; // 存放用户新消息事件 var newMessageEvent = function () { }; /** * 新消息事件 * @param event */ this.onNewMessage = function (event) { newMessageEvent = event; }; /** * 显示消息框 */ this.show = function () { // 关闭消息条 that.closeBar(); // 展开消息框 $(".fuyelk-notice").stop().animate({ height: 45 + that.msg_height }); // 延时关闭消息框 timer_close_msg = setTimeout(that.close, that.msg_close_time); }; /** * 显示消息条 */ this.showBar = function () { // 清除显示消息条的定时器 clearTimeout(timer_show_bar); // 显示消息条 $(".fuyelk-notice-bar").fadeIn(); }; /** * 关闭消息框 */ this.close = function () { // 清除关闭消息窗的定时器 clearTimeout(timer_close_msg); // 关闭消息窗 $(".fuyelk-notice").stop().animate({ height: 0 }); // 延时显示消息条 timer_show_bar = setTimeout(function () { that.showBar(); }, 400); }; /** * 关闭消息条 */ this.closeBar = function () { $(".fuyelk-notice-bar").fadeOut(); }; /** * 添加关闭按钮的监听 */ function addCloseListen() { $(".fylk-nt-close").on("click", function () { that.close(); }); } /** * 创建消息框,及CSS * @param content */ this.create = function (content) { var dom_notice = "" + "<div class='fuyelk-notice'>" + " <div class='fylk-nt-title'>" + " <span>" + that.title + "</span>" + " <span class='fylk-nt-close'><img src='" + that.imgClose + "' title='收起' alt='收起'></span>" + " </div>" + " <div class='fylk-nt-content'>" + content + "</div>" + "<div class='fylk-nt-css'>" + getCSS() + "</div>" + "</div>"; $("body").append(dom_notice); addCloseListen(); // 检查消息条是否已创建 if ($(".fuyelk-notice-bar").length === 0) { that.createMsgbar(1); } // 消息不为空则显示消息框,否则显示消息条 if (content !== "" && content !== undefined) { that.show(); } else { that.showBar(); } }; /** * 创建收起的消息条,及CSS * @param num */ this.createMsgbar = function (num) { if (undefined === num) { num = 0; } var dom_notice = "<div class='fuyelk-notice-bar'><div class='fylk-nt-title'><span>" + that.title + "</span><span style='color: #fff;font-weight: bold'> " + num + " </span><span class='fylk-nt-show'><img src='" + that.imgShow + "' title='展开' alt='展开'></span></div><div class='fylk-nt-css'>" + getCSS("bar") + "</div></div>"; $("body").append(dom_notice); $(".fylk-nt-show").on("click", function () { that.show(); }); }; /** * 销毁消息框 */ this.destory = function (cover = false) { // 覆盖旧的消息内容 if (cover) { var check_ele = $(".fylk-nt-check"); if (check_ele.length === 0) { $("body").append("<span class='fylk-nt-check' style='display: none;' data-noticemd5 = ''></span>"); } else { check_ele.data("noticemd5", ''); } } $(".fuyelk-notice").remove(); $(".fuyelk-notice-bar").remove(); // 清除关闭消息窗的定时器 clearTimeout(timer_close_msg); }; /** * 创建列表消息 * @param {[{color: string, title: string, url: string,value: string}]} data 消息数据 */ this.createList = function (data) { // 消息框高度为条数*35px if (data.length < 3) { that.msg_height = 105; } else { that.msg_height = data.length * 35; } var dom_content = ""; if (data.length !== 0) { var dom_notice_li = ""; data.forEach(function (item) { var item_url = undefined !== item.url ? item.url : "javascript:void(0)"; var item_color = undefined !== item.color ? item.color : "red"; var item_title = undefined !== item.title ? item.title : ""; var item_value = undefined !== item.value ? item.value : ""; dom_notice_li += "<li class='fylk-nt-li'><a href='" + item_url + "' title='" + item_title + ":" + item_value + "' style='cursor: pointer'>" + "<b>" + item_title + ":</b><span style='color:" + item_color + "'>" + item_value + "</span></a></li>"; }); dom_content = "<ul class='fylk-nt-ul'>" + dom_notice_li + "</ul>"; } that.createMsgbar(data.length); that.create(dom_content); }; /** * 检查消息是否有更新,有则更新消息框和校验值 * @param {{event:string,data: Array,data_md5: string}} msg */ function checkMsg(msg) { switch (msg.event) { case "connect": $.ajax({ type: "POST", dataType: "json", data: JSON.stringify({ client_id: msg.client_id }), contentType: "application/json;charset=UTF-8", url: bind_client_id_url }); break; case "notice": draw(msg.data, msg.data_md5); } } /** * 绘制消息框 * @param {array} data * @param {string} data_md5 */ function draw(data, data_md5) { var check_ele = $(".fylk-nt-check"); if (check_ele.length === 0 || check_ele.data("noticemd5") !== data_md5) { if (check_ele.length === 0) { $("body").append("<span class='fylk-nt-check' style='display: none;' data-noticemd5 = '" + data_md5 + "'></span>"); } else { check_ele.data("noticemd5", data_md5); } // 新消息事件 var msgCount = data.length; if (msgCount > 0) { newMessageEvent({msgCount: msgCount}); } that.destory(); that.createList(data); } } /** * 通过API创建消息 * @param api 获取消息接口 */ this.ajax = function (api) { $(function () { $.ajax({ type: "GET", contentType: "application/json;charset=UTF-8", url: api, success: function (result) { checkMsg(result); }, error: function (e) { } }); }); }; /** * 定时通过API创建消息 * @param api 获取消息接口 * @param time 定时时间(毫秒) * @param cb 新消息触发事件 * @returns {boolean} */ this.createInterval = function (api, time, cb) { if (undefined === api) { return false; } if (undefined === time) { time = that.reqInterval; } if (undefined !== cb) { newMessageEvent = cb; } that.ajax(api); setInterval(function () { that.ajax(api); }, time); }; /** * 创建websocket连接 * @param url websocket地址 */ function createWSConnection(url) { var ws, heartbeatTimer; ws = new WebSocket(url); // 连接成功 ws.onopen = function () { // 定时发送心跳 heartbeatTimer = setInterval(function () { var msg = JSON.stringify({event: "ping"}); ws.send(msg); }, 10000); // 声明运行正常 ws_is_on = true; ws_connect_fail_times = 0; }; // 收到消息 ws.onmessage = function (e) { checkMsg(JSON.parse(e.data)); }; // 出错 ws.onerror = function (e) { ws_is_on = false; // 断开连接 clearInterval(heartbeatTimer); ws.close(); if (ws_connect_fail_times < 3) { that.destory(true); } }; // 断开连接,声明没有运行 ws.onclose = function (e) { ws_is_on = false; clearInterval(heartbeatTimer); if (ws_connect_fail_times < 3) { that.destory(true); } }; // 监听窗口关闭 在窗口关闭前自动关闭连接 ws.onbeforeunload = function () { if (ws_is_on) { ws.close(); } }; } /** * 通过websocket创建消息 * @param ws_url websocket地址 * @param bind_url 绑定client_id地址 * @param cb 新消息触发事件 */ this.createWsMessage = function (ws_url, bind_url, cb) { bind_client_id_url = bind_url; if (undefined !== cb) { newMessageEvent = cb; } createWSConnection(ws_url); // 尝试建立连接 setInterval(function () { if (!ws_is_on) { createWSConnection(ws_url); // 连接失败警告 if (++ws_connect_fail_times >= 3) { draw([ { title: "计划任务未启动", value: "请联系技术人员操作!", url: "javascript:void(0)", color: "red" } ], "not connected"); } } }, 5000); }; } /** * 获取CSS * @param ele * @returns {string} */ function getCSS(ele) { if (ele === "bar") { return "" + "<style>" + ".fuyelk-notice-bar{background-color: #fff;width: 200px;height: 45px;display: none;max-height: 360px;float: left;position: fixed;bottom: 0;right: 0;z-index: 1000;margin: 0;padding: 0;overflow: hidden;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px 0 0 0;}" + ".fuyelk-notice img{max-width: 250px;}" + ".fylk-nt-title{width: 100%;height: 45px;color: #fff;line-height: 45px;padding-left: 15px;font-size: 16px;background-color: #009688;}" + ".fylk-nt-show {float: right;width: 50px;height: 45px;text-align: center;cursor: pointer;}" + ".fylk-nt-show img{width: 25px;height: 23px;}" + ".fylk-nt-show:hover{background-color: #008c7e;}" + "</style>"; } return "" + "<style>" + ".fuyelk-notice ::-webkit-scrollbar{width:5px}" + // 滚动条度 ".fuyelk-notice ::-webkit-scrollbar-track{background-color:#ffffff}" + // 背景颜色 ".fuyelk-notice ::-webkit-scrollbar-thumb{background-color:rgb(205,205,205)}" + // 滚动条颜色 ".fuyelk-notice ::-webkit-scrollbar-thumb:hover {background-color:rgb(193,193,193)}" + // 鼠标悬浮颜色 ".fuyelk-notice ::-webkit-scrollbar-thumb:active {background-color:rgb(193,193,193)}" + // 鼠标按住颜色 ".fuyelk-notice{background-color: #fff;width: 300px;height: 0;max-height: 360px;float: left;position: fixed;bottom: 0;right: 0;z-index: 1000;margin: 0;padding: 0;overflow: hidden;-webkit-border-radius: 5px;-moz-border-radius: 5px;border-radius: 5px 0 0 0;}" + ".fuyelk-notice img{max-width: 250px;}" + ".fylk-nt-title{width: 100%;height: 45px;color: #fff;line-height: 45px;padding-left: 15px;font-size: 16px;background-color: #009688;}" + ".fylk-nt-close {float: right;width: 50px;height: 45px;text-align: center;cursor: pointer;}" + ".fylk-nt-close img{width: 25px;height: 23px;}" + ".fylk-nt-close:hover{background-color: #008c7e;}" + ".fylk-nt-content{width: 100%;max-height: 315px;overflow-x: hidden;overflow-y: scroll}" + ".fylk-nt-ul{width: 100%;margin: 0;padding: 0;}" + ".fylk-nt-li{width: 300px;height: 35px;line-height: 35px;margin: 0 0;padding: 0 10px;border-bottom: 1px dashed #80808073;list-style: none;overflow: hidden;}" + "</style>"; } ``` #### [点击下载:fuyelk-message.js](https://www.milinger.com/upload/202205/fuyelk-message.js "点击下载:fuyelk-message.js")
上一篇:
html滚动条
下一篇:
Thinkphp Hook 钩子
1人点赞
登录后评论
友情链接
doywb
2018-2025 Copyright© 米灵尔 浮叶蓝空
豫ICP备15007436号-1
豫公网安备 41152302000146号