实现web应用调起系统通知:Notification封装

155 阅读5分钟

使用js原生的API:Notification封装了处理系统通知的方法,包括请求通知权限,创建通知,关闭单个通知,清楚所有通知四个方法

请求通知权限

// 请求通知权限
export const requestNotificationPermission = () => {
    return Notification.requestPermission().then((permission: string) => {
        if (permission === 'granted') {
            console.log('Notify allowed')
            return true
        } else if (permission === 'denied') {
            console.log('Notify reject')
            return false
        }
    })
}

创建通知

type optionsType = {
    badge?: string; //一个 USVString 包含用于表示通知的图像的 URL,当没有足够的空间来显示通知本身时
    body?: string; //一个 DOMString 表示通知的正文,将显示在标题下方。
    dir?: NotificationDirection; //显示通知的方向。默认是 auto,跟随浏览器语言设置行为,你也可以通过设置 ltr 和 rtl 的值来覆盖该行为
    icon?: string; //一个 USVString 包含要在通知中显示的图标的 URL。
    lang?: string; //通知的语言
    tag?: string; //一个 DOMString 代表通知的 一个识别标签。
    image?: string; //一个 USVString包含要在通知中显示的图像的 URL。
    data?: any; //您想要与通知相关联的任意数据。这可以是任何数据类型。
    vibrate?: any; //一个振动模式 vibration pattern (en-US) 设备的振动硬件在通知触发时发出。
    renotify?: boolean; //一个 Boolean (en-US) 指定在新通知替换旧通知后是否应通知用户。默认值为 false,这意味着它们不会被通知。
    requireInteraction?: boolean; //表示通知应保持有效,直到用户点击或关闭它,而不是自动关闭。默认值为 false。
    silent?: boolean; //个 Boolean (en-US) 指明通知是否应该是无声的,即,不需要发出声音或振动,无论设备设置如何。默认值为 false,这意味着它不会保持静默。
    sound?: string; //一个 USVString 包含通知触发时要播放的音频文件的 URL。
    noscreen?: boolean; //一个 Boolean (en-US) 指定通知触发是否应启用设备的屏幕。默认值为 false,这意味着它将启用屏幕。
    sticky?: boolean; //一个 Boolean (en-US) 指明通知是否应该是“粘”, 即不易被用户清理。默认值为 false,这意味着它不会粘。
    timeout?: number; //超时时间,默认5秒后关闭,若非常驻提示,最高设置5秒存在时间,单位ms
    onClickCallback?: () => any; //点击通知之后的回调函数
}

let allNotification: any[] = []

// 创建通知
export const createNotification = (title: string, options: optionsType) => {
    if (Notification.permission === 'granted') {
        const { timeout, onClickCallback, requireInteraction } = options
        options.silent = true
        if (navigator.userAgent.indexOf('Firefox') != -1 && title.length > 30) {
            // 用户使用的是 Firefox 浏览器,超过一行直接截断,若没这个需求可以不处理
            title = title.slice(0, 50) + '...'
        }
        let notification = new Notification(title, options)
        allNotification.push(notification)
        if (!requireInteraction) {
            setTimeout(() => {
                notification.close()
            }, timeout && timeout < 5000 ? timeout : 5000)
        }
        notification.onclick = function (e: any) {
            if (onClickCallback && typeof onClickCallback === 'function') {
                onClickCallback()
            }
            notification.close()
        }
        notification.onclose = function (e: any) {
            const { timestamp } = e.currentTarget
            const closeIndex = allNotification.findIndex((item: any) => {
                return item.timestamp === timestamp
            })
            if (closeIndex >= 0) {
                allNotification.splice(closeIndex, 1)
            }
        }
    }
}

 根据通知tag关闭单个通知

export const closeNotification = (tag: string) => {
    const closeIndex = allNotification.findIndex((item: any) => {
        return item.tag === tag
    })
    if (closeIndex >= 0) {
        if (allNotification[closeIndex].close) {
            allNotification[closeIndex].close()
            allNotification.splice(closeIndex, 1)
        }
    }
}

清除所有通知

// 清除所有通知
export const clearNotification = () => {
    allNotification.forEach((item: any) => {
        if (item.close) item.close()
    })
    allNotification = []
}

完整代码

type optionsType = {
    badge?: string; //一个 USVString 包含用于表示通知的图像的 URL,当没有足够的空间来显示通知本身时
    body?: string; //一个 DOMString 表示通知的正文,将显示在标题下方。
    dir?: NotificationDirection; //显示通知的方向。默认是 auto,跟随浏览器语言设置行为,你也可以通过设置 ltr 和 rtl 的值来覆盖该行为
    icon?: string; //一个 USVString 包含要在通知中显示的图标的 URL。
    lang?: string; //通知的语言
    tag?: string; //一个 DOMString 代表通知的 一个识别标签。
    image?: string; //一个 USVString包含要在通知中显示的图像的 URL。
    data?: any; //您想要与通知相关联的任意数据。这可以是任何数据类型。
    vibrate?: any; //一个振动模式 vibration pattern (en-US) 设备的振动硬件在通知触发时发出。
    renotify?: boolean; //一个 Boolean (en-US) 指定在新通知替换旧通知后是否应通知用户。默认值为 false,这意味着它们不会被通知。
    requireInteraction?: boolean; //表示通知应保持有效,直到用户点击或关闭它,而不是自动关闭。默认值为 false。
    silent?: boolean; //个 Boolean (en-US) 指明通知是否应该是无声的,即,不需要发出声音或振动,无论设备设置如何。默认值为 false,这意味着它不会保持静默。
    sound?: string; //一个 USVString 包含通知触发时要播放的音频文件的 URL。
    noscreen?: boolean; //一个 Boolean (en-US) 指定通知触发是否应启用设备的屏幕。默认值为 false,这意味着它将启用屏幕。
    sticky?: boolean; //一个 Boolean (en-US) 指明通知是否应该是“粘”, 即不易被用户清理。默认值为 false,这意味着它不会粘。
    timeout?: number; //超时时间,默认5秒后关闭,若非常驻提示,最高设置5秒存在时间,单位ms
    onClickCallback?: () => any; //点击通知之后的回调函数
}

let allNotification: any[] = []

// 创建通知
export const createNotification = (title: string, options: optionsType) => {
    if (Notification.permission === 'granted') {
        const { timeout, onClickCallback, requireInteraction } = options
        options.silent = true
        if (navigator.userAgent.indexOf('Firefox') != -1 && title.length > 30) {
            // 用户使用的是 Firefox 浏览器
            title = title.slice(0, 50) + '...'
        }
        let notification = new Notification(title, options)
        allNotification.push(notification)
        if (!requireInteraction) {
            setTimeout(() => {
                notification.close()
            }, timeout && timeout < 5000 ? timeout : 5000)
        }
        notification.onclick = function (e: any) {
            if (onClickCallback && typeof onClickCallback === 'function') {
                onClickCallback()
            }
            notification.close()
        }
        notification.onclose = function (e: any) {
            const { timestamp } = e.currentTarget
            const closeIndex = allNotification.findIndex((item: any) => {
                return item.timestamp === timestamp
            })
            if (closeIndex >= 0) {
                allNotification.splice(closeIndex, 1)
            }
        }
    }
}

// 根据通知tag关闭单个通知
export const closeNotification = (tag: string) => {
    const closeIndex = allNotification.findIndex((item: any) => {
        return item.tag === tag
    })
    if (closeIndex >= 0) {
        if (allNotification[closeIndex].close) {
            allNotification[closeIndex].close()
            allNotification.splice(closeIndex, 1)
        }
    }
}

// 清除所有通知
export const clearNotification = () => {
    allNotification.forEach((item: any) => {
        if (item.close) item.close()
    })
    allNotification = []
}

// 请求通知权限
export const requestNotificationPermission = () => {
    return Notification.requestPermission().then((permission: string) => {
        if (permission === 'granted') {
            console.log('Notify allowed')
            return true
        } else if (permission === 'denied') {
            console.log('Notify reject')
            return false
        }
    })
}

项目中使用(测试案例)

createNotification('123', {
    icon: square, // 文件中导入的图标文件
    body: '456',
    onClickCallback: function () {
        window.focus()
    },
})