网页插件:WebSocket消息推送[新消息提醒]

@Ta 2023-03-18发布,2023-03-19修改 28522点击
导入网页插件:新消息提醒(当前用户:17,总安装次数:35)
<link rel="stylesheet" href="https://hu60.cn/q.php/api.webplug-file.17813_public_tip_css.css" />
<script src="https://hu60.cn/q.php/api.webplug-file.17813_public_wstip_js.js"></script>

需要重新导入

以下最初源代码来自@残缘,和@老虎会游泳 的虎绿林WebSocket消息推送参考客户端,由ChatGPT修改完成,达到勉强可用的状态
期待更多虎友参与优化,目前存在的问题,悬浮窗消息展示不太美观,并且读取后不会把消息设为已读

更新内容

最新版更新内容

  • 使用了WebSocket消息推送,只会实时推送信息,并不会推送还未读的旧消息
  • 连上推送服务器后也没有查询消息数量接口,因为网页会显示未读的旧消息

以下是旧版本更新内容

  • 删除了新消息提醒的呼吸灯效果,改为了在浮窗显示新消息的数量,更加简洁直观
  • 添加了?pageSize=1作为查询参数,从而限制返回的消息数量,提高查询效率,节省服务器资源。
  • 使用SVG图标代替Emoji,使图标显示更加一致,可在不同浏览器和设备上获得更好的兼容性。
  • 替换浮窗消息中链接后缀.json为.html,在浮窗消息列表也可以直达新消息的位置

效果展示

16791273829766.png(1.67 KB)16791273838802.png(2.58 KB)

代码审查


  $(document).ready(function () {
    showAlertDiv();
    connectToWebSocket();
  });

  let messageList;

  function connectToWebSocket() {
    const socket = new WebSocket("wss://hu60.cn/ws/msg");

    socket.onopen = (event) => {
      console.log("WebSocket 连接已经建立");

      setInterval(() => {
        socket.send('{"action":"ping"}');
      }, 60000);
    };

    socket.onmessage = (event) => {
      console.log("收到 WebSocket 消息", event.data);
      handleWebSocketMessage(event.data);
    };

    socket.onerror = (event) => {
      console.error("WebSocket 连接出错", event);
      socket.close();
    };

    socket.onclose = (event) => {
      console.log("WebSocket 连接已关闭", event);

      setTimeout(() => {
        console.log("重新连接 WebSocket");
connectToWebSocket();
}, 5000);
};
}

function handleWebSocketMessage(eventData) {
try {
const message = JSON.parse(eventData);

  if (message.event === "ping") {
    console.log("收到 keep-alive 响应");
  } else if (message.event === "msg") {
    const msgData = message.data;
    if (msgData.type === 0 || msgData.type === 1) {
      showMessage(msgData);
      // 把消息添加到消息列表
      addToMessageList(msgData);
    } else {
      console.log("收到未知类型的推送消息:", msgData);
    }
  } else {
    console.log("收到未知事件类型的推送消息:", message);
  }
} catch (error) {
  console.error("处理 WebSocket 消息时出错:", error);
}
}

function addToMessageList(msgData) {
    if (!messageList) {
      messageList = createFloatingMessageList();
    }
    const content = formatMessage(msgData.content); // 使用 formatMessage() 处理消息内容
    const messageItem = document.createElement("div");
    messageItem.innerHTML = content;
    messageList.appendChild(messageItem);
  }

function formatMessage(messageContent) {
  let formattedContent = "";
  try {
    const elements = JSON.parse(messageContent);

    elements.forEach((element) => {
      switch (element.type) {
        case "markdown":
          // 处理 Markdown 内容
          // 如果您需要支持完整的 Markdown,请使用一个库(如:https://github.com/showdownjs/showdown)
          break;
        case "text":
          formattedContent += element.value;
          break;
        case "face":
          formattedContent += `<img src="表情图片的URL" alt="${element.face}" />`;
          break;
        case "atMsg":
          formattedContent += `<a href="${element.url}" target="_blank">${element.pos}</a> `;
          element.msg.forEach((msgElement) => {
            if (msgElement.type === "text") {
              formattedContent += msgElement.value;
            } else if (msgElement.type === "at") {
              formattedContent += `<strong>@${msgElement.tag}</strong>`;
            }
          });
          break;
        default:
          console.warn(`未知消息元素类型:${element.type}`);
      }
    });
  } catch (error) {
    console.error("解析消息内容时出错:", error);
  }
  return formattedContent;
}

function showFloatingMessageList() {
if (!messageList) {
messageList = createFloatingMessageList();
}
messageList.style.display = "block";
}

function createFloatingMessageList() {
const messageList = document.createElement("ul");
messageList.id = "messageList";
messageList.style.display = "none";

const closeButton = document.createElement("button");
closeButton.textContent = "关闭";
closeButton.addEventListener("click", function () {
  messageList.style.display = "none";
});
messageList.appendChild(closeButton);

// 将浮动的div元素添加到body元素中
document.body.appendChild(messageList);

return messageList;
}

function showAlertDiv() {
// 创建浮动的div元素
const floatingDiv = document.createElement("div");
floatingDiv.id = "floatingDiv";
floatingDiv.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" width="35" height="35" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg><span id="messageCount" style="display:none;"></span>';

floatingDiv.addEventListener("click", function () {
  showFloatingMessageList();
});

// 将浮动的div元素添加到body元素中
document.body.appendChild(floatingDiv);
}

function showMessage(msgData) {
const messageCount = parseInt(
document.getElementById("messageCount").textContent || "0"
);
document.getElementById("messageCount").textContent = messageCount + 1;
document.getElementById("messageCount").style.display = "inline";
}
回复列表(28|隐藏机器人聊天)
  • @Ta / 2023-03-18 / /
    👍
  • @Ta / 2023-03-18 / /
    @残缘,大哥不会介意吧
  • @Ta / 2023-03-18 / /
    @旧人,怎么会,你太棒了,修复了我一直懒得改的那个跳到json页面问题
  • @Ta / 2023-03-18 / /

    @残缘,我不太会写,不过比较会提需求,chatgpt很牛,你可以改下这里
    // 替换content中的.json为.html
    content = content.replace(/.json/g, ".html");

  • @Ta / 2023-03-18 / /

    你这轮训速度太快了,会把老虎服务器干坏的
    iPhone13 PRO MAX 1T 国行远峰蓝 非海南免税版

  • @Ta / 2023-03-18 / /

    @idc状态,可以自行修改,1500还好,会有一定的延迟

  • @Ta / 2023-03-19 / /
    @TabKey9,试试
  • @Ta / 2023-03-19 / /
    @旧人,有新消息提醒,那个图标有点违和感呢
  • @Ta / 2023-03-19 / /

    @TabKey9,有啥参考的图标吗,可以修改一下

  • @Ta / 2023-03-19 / /
    正在尝试使用WebSocket消息推送
  • @Ta / 2023-03-19 / /

    @旧人,测试

  • @Ta / 2023-03-19 / /

    @旧人

    连上推送服务器后也没有查询消息数量接口,因为网页会显示未读的旧消息

    这个不一定成立啊,如果连接断开,重连的这段时间来的消息就会错过。还有从开始连接到连上这段时间来的消息也会错过。

  • @Ta / 2023-03-19 / /

    @老虎会游泳,我测试了很长时间,期间一直挂在后台,连接还算稳定,作为一个网站来说很少有用户在一个网页停留这么久吧,而且即使查询接口显示未读消息数量,似乎WebSocket也不会把未读的消息再推送一次,只有数量16792041359536.png(205.4 KB)

  • @Ta / 2023-03-19 / /

    @旧人,对,只有数量。那暂时忽略错过消息的问题也可以。

  • @Ta / 2023-03-19 / /

    @老虎会游泳,底层网络协议自己会发心跳包吗?还需要 websocket 自己发吗?

  • @Ta / 2023-03-19 / /

    @无名啊,不会。如果应用自己不主动发,一个数据包都不会有。

  • @Ta / 2023-03-20 / /
    似乎代码会不显示,image.png(77.67 KB)
  • @Ta / 2023-03-20 / /

    @残缘,有啥好的方法可以改改的吗,我本来倾向于原来那种调用jaon接口看消息的的

  • @Ta / 2023-03-20 / /
    @旧人,按道理直接把json返回的html插入进入就能显示的
添加新回复
回复需要登录