前端PWA:让你的网站变成App

前端PWA:让你的网站变成App

毒舌时刻

前端PWA?这不是噱头吗?

"PWA有什么用,用户直接用浏览器不就好了"——结果用户体验差,无法离线访问,
"我有原生App,不需要PWA"——结果开发成本高,维护困难,
"PWA就是加个manifest和service worker,多简单"——结果功能不完整,用户体验差。

醒醒吧,PWA不是简单的技术组合,而是一种现代化的Web应用模式!

为什么你需要这个?

  • 离线访问:即使没有网络也能访问应用
  • 安装到主屏幕:像原生App一样方便使用
  • 推送通知:及时向用户发送重要信息
  • 性能提升:缓存静态资源,加快加载速度
  • 跨平台:一次开发,多平台运行

反面教材

<!-- 反面教材:不完整的PWA配置 --> <!DOCTYPE html> <html> <head> <title>我的PWA应用</title> <!-- 缺少manifest.json --> <!-- 缺少service worker --> </head> <body> <h1>我的PWA应用</h1> <p>这是一个PWA应用</p> </body> </html> 
// 反面教材:简单的service worker // service-worker.js self.addEventListener('install', event => { console.log('Service Worker 安装'); }); self.addEventListener('activate', event => { console.log('Service Worker 激活'); }); self.addEventListener('fetch', event => { console.log('Service Worker 拦截请求'); }); 

正确的做法

<!-- 正确的做法:完整的PWA配置 --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>我的PWA应用</title> <!-- 添加manifest.json --> <link rel="manifest" href="/manifest.json"> <!-- 添加主题颜色 --> <meta name="theme-color" content="#317EFB"> <!-- 添加Apple Touch Icon --> <link rel="apple-touch-icon" href="/icons/icon-192x192.png"> <!-- 添加预加载 --> <link rel="preload" href="/style.css" as="style"> <link rel="preload" href="/script.js" as="script"> <link rel="stylesheet" href="/style.css"> </head> <body> <h1>我的PWA应用</h1> <p>这是一个完整的PWA应用</p> <button>发送通知</button> <script src="/script.js"></script> <script> // 注册service worker if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/service-worker.js') .then(registration => { console.log('Service Worker 注册成功:', registration.scope); }) .catch(error => { console.log('Service Worker 注册失败:', error); }); }); } </script> </body> </html> 
// 正确的做法:manifest.json { "name": "我的PWA应用", "short_name": "PWA应用", "description": "一个完整的PWA应用示例", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#317EFB", "icons": [ { "src": "/icons/icon-72x72.png", "sizes": "72x72", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-96x96.png", "sizes": "96x96", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-128x128.png", "sizes": "128x128", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-144x144.png", "sizes": "144x144", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-152x152.png", "sizes": "152x152", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-384x384.png", "sizes": "384x384", "type": "image/png", "purpose": "any" }, { "src": "/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" } ] } 
// 正确的做法:完整的service worker // service-worker.js const CACHE_NAME = 'pwa-app-cache-v1'; const ASSETS_TO_CACHE = [ '/', '/index.html', '/style.css', '/script.js', '/manifest.json', '/icons/icon-72x72.png', '/icons/icon-96x96.png', '/icons/icon-128x128.png', '/icons/icon-144x144.png', '/icons/icon-152x152.png', '/icons/icon-192x192.png', '/icons/icon-384x384.png', '/icons/icon-512x512.png' ]; // 安装Service Worker self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Cache opened'); return cache.addAll(ASSETS_TO_CACHE); }) .then(() => self.skipWaiting()) ); }); // 激活Service Worker self.addEventListener('activate', event => { const cacheWhitelist = [CACHE_NAME]; event.waitUntil( caches.keys().then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { if (cacheWhitelist.indexOf(cacheName) === -1) { return caches.delete(cacheName); } }) ); }) .then(() => self.clients.claim()) ); }); // 拦截网络请求 self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { // 如果缓存中有响应,直接返回 if (response) { return response; } // 否则发起网络请求 return fetch(event.request) .then(response => { // 如果响应有效,缓存一份 if (response && response.status === 200 && response.type === 'basic') { const responseToCache = response.clone(); caches.open(CACHE_NAME) .then(cache => { cache.put(event.request, responseToCache); }); } return response; }) .catch(error => { // 网络错误时返回离线页面 if (event.request.mode === 'navigate') { return caches.match('/offline.html'); } }); }) ); }); // 处理推送通知 self.addEventListener('push', event => { const data = event.data.json(); const options = { body: data.body, icon: '/icons/icon-192x192.png', badge: '/icons/icon-72x72.png', data: { url: data.url } }; event.waitUntil( self.registration.showNotification(data.title, options) ); }); // 处理通知点击 self.addEventListener('notificationclick', event => { event.notification.close(); event.waitUntil( clients.openWindow(event.notification.data.url) ); }); 
// 正确的做法:使用推送通知 // script.js // 请求通知权限 function requestNotificationPermission() { if ('Notification' in window) { Notification.requestPermission().then(permission => { if (permission === 'granted') { console.log('通知权限已授予'); } else { console.log('通知权限被拒绝'); } }); } } // 发送通知 function sendNotification() { if ('serviceWorker' in navigator && 'PushManager' in window) { navigator.serviceWorker.ready.then(registration => { registration.showNotification('测试通知', { body: '这是一条测试通知', icon: '/icons/icon-192x192.png', badge: '/icons/icon-72x72.png', data: { url: '/' } }); }); } } // 页面加载时请求通知权限 window.addEventListener('load', () => { requestNotificationPermission(); // 绑定按钮点击事件 const notificationBtn = document.getElementById('notification-btn'); if (notificationBtn) { notificationBtn.addEventListener('click', sendNotification); } }); // 检查是否是PWA模式 function checkPwaMode() { const isPwa = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone || document.referrer.includes('android-app://'); if (isPwa) { console.log('应用以PWA模式运行'); } else { console.log('应用以浏览器模式运行'); } } checkPwaMode(); 

毒舌点评

看看,这才叫前端PWA!不是简单地添加manifest和service worker,而是构建一个完整的PWA应用,包括离线访问、推送通知、安装到主屏幕等功能。

记住,PWA不是替代原生App,而是一种补充。它可以让你的Web应用获得类似原生App的体验,同时保持Web的跨平台优势。

所以,别再觉得PWA是噱头了,它是现代Web开发的重要方向!

总结

  • manifest.json:配置应用名称、图标、显示模式等
  • Service Worker:实现离线缓存、推送通知等功能
  • 离线访问:缓存静态资源,确保无网络时也能访问
  • 安装到主屏幕:提供类似原生App的入口
  • 推送通知:及时向用户发送重要信息
  • 性能优化:缓存策略、预加载等
  • 可访问性:确保PWA对所有用户都友好
  • 跨平台:一次开发,多平台运行

PWA,让你的网站变成真正的应用!

Read more

终极Notion风格编辑器:AI智能写作的完整指南

终极Notion风格编辑器:AI智能写作的完整指南 【免费下载链接】novelNotion-style WYSIWYG editor with AI-powered autocompletion. 项目地址: https://gitcode.com/gh_mirrors/no/novel Novel是一个开源的Notion风格所见即所得编辑器,具有AI驱动的自动补全功能。这款编辑器专为现代写作体验设计,将Notion的优雅界面与人工智能的强大能力完美结合,让写作变得更加高效和智能。无论您是内容创作者、开发者还是普通用户,Novel都能为您提供前所未有的写作体验。 🚀 什么是Notion风格编辑器? Notion风格编辑器以其简洁直观的界面和强大的块编辑功能而闻名。Novel编辑器继承了这些优点,同时加入了AI智能写作功能,让您能够: * 快速创建各种内容块(文本、列表、标题等) * 享受流畅的拖放操作体验 * 使用AI辅助完成写作任务 Notion风格编辑器的直观界面展示 ✨ 核心功能特性 AI智能写作辅助 Novel最引人注目的功能就是AI驱动的自动补全

Lostlife2.0任务系统智能化:LLama-Factory驱动动态任务生成

Lostlife2.0任务系统智能化:LLama-Factory驱动动态任务生成 在今天的开放世界游戏中,玩家早已不再满足于“前往A点、击败B怪、带回C物品”这种千篇一律的任务链条。他们期待的是一个能感知自身状态、理解行为偏好、甚至记住过往选择的“活”的游戏世界。而要实现这一点,传统脚本化设计显然力不从心——内容量大、维护成本高、缺乏灵活性。 正是在这样的背景下,Lostlife2.0 开始尝试用大语言模型(LLM)重构其任务系统的核心逻辑。我们不再预先编写成千上万条任务指令,而是训练一个能够“根据情境实时生成合理任务”的智能引擎。而支撑这一构想落地的关键工具,正是开源社区中迅速崛起的一站式微调框架——LLama-Factory。 从“写死逻辑”到“学会出题”:为什么我们需要模型来生成任务? 设想这样一个场景:两名等级相同的玩家同时进入幽暗森林。一人背包空空、饥饿值低;另一人则装备齐全但缺少治疗资源。如果系统给两人派发完全相同的任务,比如“去砍10棵树”,那显然既不合理也不有趣。 理想情况下,系统应该像一位经验丰富的DM(地下城主),能结合当前环境、

对比测试:Fun-ASR与Whisper语音识别效果与速度差异

对比测试:Fun-ASR与Whisper语音识别效果与速度差异 在企业办公场景中,每天都有成百上千小时的会议录音、客服通话和培训音频亟待处理。如何高效地将这些声音“翻译”成可搜索、可分析的文字?这不仅是效率问题,更是数据资产化的核心环节。过去几年,语音识别技术突飞猛进,尤其是OpenAI推出的Whisper系列模型,一度被视为行业标杆。然而,在真实中文语境下——口音多样、术语密集、环境嘈杂——通用型模型的表现往往不尽如人意。 正是在这种背景下,钉钉联合通义实验室推出的Fun-ASR逐渐进入开发者视野。它不追求“支持99种语言”的广度,而是聚焦于一件事:把中文说得更准、转得更快、用得更稳。更重要的是,它不是一段代码或一个API,而是一整套可以本地运行、开箱即用的语音识别系统,自带Web界面、热词增强、批量处理和历史管理功能。对于需要私有化部署、保障数据安全的企业来说,这种设计思路显然更具现实意义。 那么,当Fun-ASR真正面对Whisper时,差距究竟在哪里?是精度更高,还是速度快到质变?又或者只是“本地可用”这一点就足以决定胜负? 我们不妨从一次真实的批量转写任务说起。 假

Llama-3.2-3B部署实录:Ollama本地大模型从下载到生成仅需90秒

Llama-3.2-3B部署实录:Ollama本地大模型从下载到生成仅需90秒 想体验最新的大语言模型,但又担心复杂的部署流程和漫长的等待时间?今天,我要分享一个极其简单的方案:使用Ollama在本地部署Meta最新发布的Llama-3.2-3B模型。整个过程从下载模型到生成第一段文字,最快只需要90秒,而且完全免费,不需要任何复杂的配置。 Llama-3.2-3B是Meta推出的轻量级多语言大模型,虽然只有30亿参数,但在很多任务上的表现已经相当出色。更重要的是,它非常“亲民”,对普通电脑配置要求不高,通过Ollama这个工具,你可以像安装一个普通软件一样把它装到自己的电脑上,随时随地调用。 这篇文章,我将带你走一遍完整的部署流程,从零开始,手把手教你如何用最简单的方法,在自己的电脑上跑起这个强大的AI助手。 1. 准备工作:认识我们的工具和模型 在开始动手之前,我们先花一分钟了解一下今天要用到的两个核心:Ollama和Llama-3.2-3B模型。了解它们是什么,能帮你更好地理解后面的每一步操作。 1.1 Ollama:你的本地大模型管家 你可以把Ollama想象成