js通知提醒

JS通知总结下来有4种方法,分别是声音提醒、通知提醒、标题变化、icon变化; 比较常见的是标题变化和icon变化;

方式1:声音通知

人性化提示音:xxx平台收到音视频呼叫,请接听; 您有收到一条新的消息;

  • 优点:通知即时,无干扰和历史残留;
  • 缺点:
    • 浏览器要求必须和页面发生一次交互,才能播放; 静音后将无法收到提醒;
    • 浏览器静音/系统静音将无法听到播放声音;

备注: 如果手动开启浏览器声音播放权限;将不会有必须与页面发生交互的错误;

方式2:Notification通知(强提醒)
  • 优点:强提醒,用户隐藏tab也会收到;
  • 缺点
    • win系统5-6秒左右会自动隐藏;
    • 无法指定常驻时间,设置自定义样式;
    • 如果用户拒绝过,将无法再次弹出授权通知,需要用户手动去设置中开启;
    • 无法自定义按钮,只能触发点击事件;
    • 如果用户授权, 但是系统设置里面关闭了浏览器通知,将无法监测到;
    • 大部分用户拒绝后,可能自己找不到设置中哪里开启;
    • 由于刷新或异常关闭,会导致老旧的通知存在任务栏;无法释放;

备注:可以手动开启浏览器通知权限; 并设置系统允许浏览器通知

相关代码
/*
    Notification.requestPermission; 
    - 'denied': 用户拒绝显示通知
    - 'granted': 用户接受显示通知
    - 'default': 用户选择是未知的

*/

function notifyMe() {
  if (!("Notification" in window)) {
    // 检查浏览器是否支持通知
    alert("当前浏览器不支持桌面通知");
  } else if (Notification.permission === "granted") {
    // 检查是否已授予通知权限;如果是的话,创建一个通知
    const notification = new Notification("你好!");
    // …
  } else if (Notification.permission !== "denied") {
    // 我们需要征求用户的许可
    Notification.requestPermission().then((permission) => {
      // 如果用户接受,我们就创建一个通知
      if (permission === "granted") {
        const notification = new Notification("你好!");
        // 或者  
        const notification = new Notification("通知标题:", {
            body: '通知内容',    
            icon: '',
        })
      }
    });
 }
}

// 判断当前浏览器是否支持通知
if (!("Notification" in window)) {
  console.log("此浏览器不支持通知API");
}
// 如果用户已经禁用了通知,提示用户手动开启
if (Notification.permission === "denied") {
  alert("您已阻止通知,请在浏览器设置中开启通知权限以获得最佳体验。");
}
// 绑定事件
notification.onclick = function () {
  window.focus(); // 点击通知时将焦点切换回窗口
  notification.close(); // 关闭通知
};
// 点击通知时打开指定页面
notification.onclick = function () {
  window.open("https://baidu.com"); 
};
方式3:修改Favicon(弱提醒)
  • 多个tab也可以看到变化
  • 缺点
    • 如果最小化将无法看到效果;
    • 使用定时器刷新,影响性能;
相关代码
/*
	也可以直接替换icon
	<link rel="icon" href="/favicon.ico"/>
*/
function changeFavicon(url) {
  const link = document.querySelector("link[rel*='icon']") || document.createElement("link");
  link.type = "image/x-icon";
  link.rel = "shortcut icon";
  link.href = url;
  document.getElementsByTagName("head")[0].appendChild(link);
}

// 动态生成带数字的Favicon
// 可以生成一个红底里面放数字的图标
function drawFaviconWithNumber(number) {
    const canvas = document.createElement("canvas");
    canvas.width = 16;
    canvas.height = 16;
    const context = canvas.getContext("2d");
    context.fillStyle = "red";
    context.beginPath();
    context.arc(8, 8, 8, 0, 2 * Math.PI);
    context.fill();
    context.fillStyle = "white";
    context.font = "10px Arial";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(number, 8, 8);
    const url = canvas.toDataURL("image/png");
    changeFavicon(url);
}
标题闪烁提示(弱提醒)
  • 缺点
    • 如果用户切到别的tab,任务栏看不到名称变化效果;
    • 当有多个tab时候提示不明显;
    • 使用定时器刷新,影响性能;
let title = '有新消息'
setInterval(() => {
    if (title === '有新消息'){
        document.title = 'xxx平台'
        title = 'xxx平台'
    } else {
        document.title = '有新消息'
        title = '有新消息'
    }
}, 1000)
辅助方法
// 监听页面可见性变化
document.addEventListener("visibilitychange", () => {
    /*
        - 如果页面处于前台且可见,document.hidden 的值为 false
        - 如果页面处于后台或被隐藏,document.hidden 的值为 true
    */
    if (document.hidden) {
        console.log("页面已隐藏,可以弹出通知");
    } else {
        console.log("页面已激活,不弹出通知");
    }
});
// 监听页面关闭或刷新是清空当前弹窗
window.addEventListener('beforeunload', (event) => {
});
封装方法
import notifIcon from '@/assets/icon.png';
// 页面默认icon  <link rel="icon" href="/favicon.ico"/>
import faviconIco from '@/assets/favicon.ico';
// 新消息icon  <link rel="icon" href="/inCallIcon.ico"/>
import inCallIcon from '@/assets/inCallIcon.svg';

import { Modal } from 'antd';
const { warning } = Modal;

class MediaNotic {
    pageIsHide: boolean;
    openPageHideNotUpdate: boolean;
    toggleTime: any;
    notiPerWarning: any;
    notification: any;
    constructor () {
        // 当前页面是是否显示: true_隐藏 false_页面激活;
        this.pageIsHide = false;
        // 是否开启页面不可见才弹出通知
        this.openPageHideNotUpdate = false;
        // 切换定时器
        this.toggleTime = null;
        // 通知权限弹窗
        this.notiPerWarning = null;
        // 当前通知系统弹窗
        this.notification = null;
        this.init();
    }
    init() {
        this.getCurentDocumentHide();
        this.bindDocumentVisiChange();
        this.firstLoadingNotiPermission();
    }
    /*
        是否设置开启页面隐藏才触发通知
    */
    setOpenPageHideNotUpdate(open: boolean) {
        this.openPageHideNotUpdate = open;
    }
    open() {
        // 如果开启页面隐藏才弹窗
        if (this.openPageHideNotUpdate) {
            if (!this.pageIsHide) { 
                this.close();
                return;
            };
        }
        this.toggleTime = setTimeout(() => {
            this.toggleTime = null;
            const title = document.title;
            if (title === '有新来电'){
                this.resetTitleFavicon();
            } else {
                document.title = '有新来电';
                // this.drawFaviconWithNumber(1);
                this.changeFavicon(inCallIcon);
            }
            this.open();
        }, 1000);
    }
    close() {
        if (this.toggleTime) {
            clearTimeout(this.toggleTime);
            this.toggleTime = null;
        };
        this.resetTitleFavicon();
        if (this.notification) {
            this.notification.close();
            this.notification = null;
        };
    }
    resetTitleFavicon() {
        document.title = '三级调度平台';
        this.changeFavicon(faviconIco);
    }
    changeFavicon(url: string) {
        const link: any = document.querySelector("link[rel*='icon']") || document.createElement("link");
        link.type = "image/x-icon";
        link.rel = "shortcut icon";
        link.href = url;
        document.getElementsByTagName("head")[0].appendChild(link);
    }
    /* 获取当前页面是否可见 */
    getCurentDocumentHide() {
        this.pageIsHide = document.hidden;
    }
    /* 监听页面可见性变化 */
    bindDocumentVisiChange() {
        /*
            - 如果页面处于前台且可见,document.hidden 的值为 false
            - 如果页面处于后台或被隐藏,document.hidden 的值为 true
        */
        document.addEventListener("visibilitychange", () => {
            this.pageIsHide = document.hidden;
            // 如果开启页面隐藏才弹窗
            if (this.openPageHideNotUpdate && !this.pageIsHide) {
                this.close();
            }
        });
        window.addEventListener('beforeunload', (event) => {
            this.close();
        });
    }
    // 动态生成带数字的Favicon
    drawFaviconWithNumber(number: number) {
        const canvas = document.createElement("canvas");
        canvas.width = 16;
        canvas.height = 16;
        const context: any = canvas.getContext("2d");
        context.fillStyle = "red";
        context.beginPath();
        context.arc(8, 8, 8, 0, 2 * Math.PI);
        context.fill();
        context.fillStyle = "white";
        context.font = "10px Arial";
        context.textAlign = "center";
        context.textBaseline = "middle";
        // context.fillText(number, 8, 8);
        const url = canvas.toDataURL("image/png");
        this.changeFavicon(url);
    }
    /* 通知权限
       - 如果用户没有赋予就去申请一下;
       - 如果用户判断已经拒绝, 就简单提示一下;
    */
    firstLoadingNotiPermission() {
        if (!("Notification" in window)) {
            return;
        }
        const notPerm = Notification.permission;
        // 表示用户还没有指定通知权限
        if (notPerm === 'default') {
            // 主动获取通知权限
            Notification.requestPermission();
            return;
        } else if (notPerm === 'denied') {
            // alert 会阻塞页面加载,不建议使用
            // alert('您已阻止通知, 请在浏览器设置中开启通知权限以获得最佳体验!');
            if (this.notiPerWarning) {
                this.notiPerWarning.destroy();
                this.notiPerWarning = null;
            };
            this.notiPerWarning = warning({
                icon: '',
                title: '提示',
                content: '您已选择关闭通知权限,将无法收到来电邀请通知, 请在设置中开启通知权限以获得最佳体验!',
                okText: '确定',
                onCancel: () => {
                    this.notiPerWarning = null;
                }
            });
            // // 超时关闭
            // setTimeout(() => {
            //     if (this.notiPerWarning) {
            //         this.notiPerWarning.destroy();
            //         this.notiPerWarning = null;
            //     }
            // }, 15 * 1000);
            return;
        }
    }
    openNoti() {
        // 如果开启页面隐藏才弹窗
        if (this.openPageHideNotUpdate) {
            if (!this.pageIsHide) { 
                this.close();
                return;
            };
        }
        if (!("Notification" in window)) {
            return;
        }
        if (this.notification) {
            this.notification.close();
            this.notification = null;
        };
        Notification.requestPermission().then((permission) => {
            // 如果用户接受,我们就创建一个通知
            if (permission === "granted") {
                if (this.notification) {
                    this.notification.close();
                    this.notification = null;
                };
                this.notification = new Notification("来电提醒", {
                    body: 'xxx平台收到音视频邀请, 请前往接听!',    
                    icon: notifIcon,
                });
                // 绑定事件
                this.notification.onclick = function () {
                    window.focus(); // 点击通知时将焦点切换回窗口
                    this.notification.close(); // 关闭通知
                };
                // 系统大概5秒后会自己消失
                setTimeout(() => {
                    if (this.notification) {
                        this.notification.close();
                        this.notification = null;
                    };
                }, 30 * 1000);
            }
        });
    }
}
const InCallMediaNotic = new MediaNotic();
export default InCallMediaNotic;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值