|
|
|
|
@ -0,0 +1,169 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="notification-container">
|
|
|
|
|
<h1 class="text-2xl font-bold mb-4">浏览器通知示例</h1>
|
|
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
@click="requestNotificationPermission"
|
|
|
|
|
:disabled="!isSupported"
|
|
|
|
|
class="mb-4"
|
|
|
|
|
>
|
|
|
|
|
{{ buttonText }}
|
|
|
|
|
</el-button>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
v-if="!isSupported"
|
|
|
|
|
class="warning-message"
|
|
|
|
|
>
|
|
|
|
|
您的浏览器不支持通知功能或当前环境不安全(非HTTPS)
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<el-form
|
|
|
|
|
v-if="isSupported && permissionGranted"
|
|
|
|
|
:model="form"
|
|
|
|
|
label-width="120px"
|
|
|
|
|
class="notification-form"
|
|
|
|
|
>
|
|
|
|
|
<el-form-item label="通知标题">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.title"
|
|
|
|
|
placeholder="输入通知标题"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item label="通知内容">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.body"
|
|
|
|
|
type="textarea"
|
|
|
|
|
:rows="3"
|
|
|
|
|
placeholder="输入通知内容"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item label="图标URL">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.icon"
|
|
|
|
|
placeholder="输入图标URL(可选)"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-button
|
|
|
|
|
type="success"
|
|
|
|
|
@click="sendNotification"
|
|
|
|
|
:disabled="!form.title || !form.body"
|
|
|
|
|
>
|
|
|
|
|
发送通知
|
|
|
|
|
</el-button>
|
|
|
|
|
</el-form>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed, onMounted } from 'vue';
|
|
|
|
|
import { ElButton, ElForm, ElFormItem, ElInput } from 'element-plus';
|
|
|
|
|
/**
|
|
|
|
|
1. 主要浏览器对非HTTPS通知的支持
|
|
|
|
|
Chrome/Edge:从Chrome 80+版本开始,非HTTPS网站不再支持通知功能,必须使用HTTPS或localhost
|
|
|
|
|
Firefox:仍然允许非HTTPS网站使用通知,但会显示明显的安全警告
|
|
|
|
|
Safari:要求必须是HTTPS或localhost
|
|
|
|
|
Opera:与Chrome相同,要求HTTPS
|
|
|
|
|
|
|
|
|
|
2. 开发环境例外
|
|
|
|
|
在以下开发环境中,即使没有HTTPS也可以使用通知:
|
|
|
|
|
http://localhost 或 http://127.0.0.1
|
|
|
|
|
http://*.localhost (某些浏览器支持)
|
|
|
|
|
使用自签名证书的本地开发服务器
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
// 检查浏览器是否支持通知
|
|
|
|
|
const isSupported = ref('Notification' in window);
|
|
|
|
|
const permissionGranted = ref(false);
|
|
|
|
|
|
|
|
|
|
// 通知表单数据
|
|
|
|
|
const form = ref({
|
|
|
|
|
title: '你好!',
|
|
|
|
|
body: '这是一个浏览器通知示例',
|
|
|
|
|
icon: 'https://vuejs.org/images/logo.png',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 按钮文本计算属性
|
|
|
|
|
const buttonText = computed(() => {
|
|
|
|
|
if (!isSupported.value) return '不支持通知';
|
|
|
|
|
return permissionGranted.value ? '已授权通知' : '请求通知权限';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 请求通知权限
|
|
|
|
|
const requestNotificationPermission = async () => {
|
|
|
|
|
if (!isSupported.value) return;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const permission = await Notification.requestPermission();
|
|
|
|
|
permissionGranted.value = permission === 'granted';
|
|
|
|
|
|
|
|
|
|
if (permissionGranted.value) {
|
|
|
|
|
// 立即显示一个简单的通知
|
|
|
|
|
new Notification('通知权限已授予', {
|
|
|
|
|
body: '您现在可以发送自定义通知了!',
|
|
|
|
|
icon: form.value.icon,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('请求通知权限失败:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 发送自定义通知
|
|
|
|
|
const sendNotification = () => {
|
|
|
|
|
if (!permissionGranted.value || !form.value.title || !form.value.body) return;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
new Notification(form.value.title, {
|
|
|
|
|
body: form.value.body,
|
|
|
|
|
icon: form.value.icon || undefined,
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('发送通知失败:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 组件挂载时检查权限状态
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
if (isSupported.value) {
|
|
|
|
|
permissionGranted.value = Notification.permission === 'granted';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
.notification-container {
|
|
|
|
|
max-width: 600px;
|
|
|
|
|
margin: 2rem auto;
|
|
|
|
|
padding: 1.5rem;
|
|
|
|
|
background-color: #f8fafc;
|
|
|
|
|
border-radius: 0.5rem;
|
|
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
|
color: #334155;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.warning-message {
|
|
|
|
|
padding: 1rem;
|
|
|
|
|
background-color: #fef2f2;
|
|
|
|
|
color: #dc2626;
|
|
|
|
|
border-radius: 0.375rem;
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.notification-form {
|
|
|
|
|
background-color: white;
|
|
|
|
|
padding: 1.5rem;
|
|
|
|
|
border-radius: 0.5rem;
|
|
|
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
|
|
|
|
|
|
|
|
.el-form-item {
|
|
|
|
|
margin-bottom: 1.25rem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|