Vue.js 101 todo PWA 教程
奖励 - 离线渐进式 Web 应用程序 (PWA)
本教程的目标是介绍 vue.js ❤。
该内容最初是为DAM Digital London的一个研讨会撰写的。
Vue.js 是一个用于构建用户界面(UI)的渐进式框架。
本教程假设您已经具备一些关于 HTML、CSS 和 JavaScript 的中级知识。如果您对这些领域没有任何了解,请查看freeCodeCamp,他们提供了丰富的资源来学习这些主题😉。
本教程将涵盖以下主题:
- v-bind 指令
- 类和样式绑定
- 事件处理
- 属性中的数据绑定
- 列表渲染
- 插值 - 胡子
- 表单输入绑定 - 复选框
- v-模型
- 方法
- 条件渲染
- v-if
- v-否则
- PWA 简介
我们将创建一个能够拥有多个待办事项列表的待办事项应用程序。
入门
从 github克隆入门材料。它包含基础 HTML、CSS 和 JS。
您可以在github上找到本教程的最终代码,如果您点击此链接,还可以找到演示。
Vue CDN 已经包含在我们的 index.html 以及 CSS 和 content/js/app.js 中😃。
在移动设备上切换导航
首先,移动设备(📱 < 850px)上的侧边导航应该显示和隐藏。
当我们点击菜单时,我们想要<nav>
切换类别.is-open
。
在 Vue.js 中,v-bind
允许我们在 HTML 属性内绑定数据。例如v-bind:id=""
、v-bind:style=""
、v-bind:data-target=""
等。 的简写v-bind
是:
。
在 中index.html
,我们将动态传递.is-open
使用v-bind:class
。如果isNavOpen
为真,则我们将添加我们的类。
<nav v-bind:class="{'is-open': isNavOpen}">
<!-- ... -->
</nav>
在 中content/js/app.js
,我们需要isNavOpen
数据。如果将最后一个值更改为true,导航就会显示出来。
vue.js 中的data属性用于存储应用程序的数据以及 UI 的状态。例如,默认isNavOpen
设置为 false,但通过将其值更改为 true,我们可以将is-open类绑定到 DOM。
在我们的 app.js 中,我们需要添加isNavOpen: false
。
var app = new Vue({
el: "#app",
data: {
isNavOpen: false
}
});
isNavOpen
现在我们想要改变单击菜单按钮时的值。
我们将使用“on click”事件处理程序。在 Vue.js 中,我们可以使用v-on:
或@
(简写)来监听 DOM 事件。在本例中,我们想要监听点击事件。因此,我们将使用v-on:click
/ @click
。
<button v-on:click="isNavOpen = !isNavOpen" class="menu">Menu</button>
如您所见,我们可以传递内联 javascript 语句,我们也可以使用方法(函数),我们将在本教程的后面看到如何使用最后一个方法。
文档参考
将待办事项列表绑定到侧边导航
在中content/js/app.js
,让我们添加一些虚拟列表,以便我们可以开始整合我们的侧面导航。
var app = new Vue({
el: "#app",
data: {
isNavOpen: false,
todoLists: [
{
title: "✈️ Trip to japan",
keyword: "japan",
items: [
{ name: "Eat ramen", isCompleted: true },
{ name: "Visit mt Fuji", isCompleted: false },
{ name: "Learn japanese", isCompleted: false }
]
},
{
title: "🏂 Ski trip to the Alps",
keyword: "Alps",
items: [
{ name: "Find a chalet", isCompleted: true },
{ name: "Learn how to ski", isCompleted: false }
]
},
{
title: "🍉 Groceries",
keyword: "Food",
items: [
{ name: "Apples", isCompleted: false },
{ name: "Banana", isCompleted: true },
{ name: "Tomatoes", isCompleted: false },
{ name: "Bread", isCompleted: true }
]
}
]
}
});
为了在侧面导航中呈现我们的列表,我们需要使用v-for
指令。
<nav v-bind:class="{'is-open': isNavOpen}">
<ul>
<li v-for="todoList in todoLists">
<button>
{{todoList.title}}
<span>
{{todoList.items.length}}
</span>
</button>
</li>
<li>
<button class="is-add">Create a new list</button>
</li>
</ul>
</nav>
todoLists
是源数据,todoList
是用于在数组中迭代的别名。
我们使用“moustache”语法{{}}
将文本绑定到视图。moustache 标签将被 中的目标值替换todoLists
。
文档参考
主要部分
标题
我们希望能够在主页面中看到待办事项。目前,我们只渲染第一个todoLists
列表(索引 0)。
在content/js/app.js
=>data
添加currentListIndex: 0
。
var app = new Vue({
el: "#app",
data: {
isNavOpen: false,
currentListIndex: 0,
todoLists: [
//...
]
}
});
使用标题中的胡须语法绑定列表的标题。
<h1>{{todoLists[currentListIndex].title}}</h1>
标题有一张背景图片。我们使用Unsplash Source获取随机图片。我们可以指定关键词来获取与标题相关的图片。
https://source.unsplash.com/featured/?{KEYWORD},{KEYWORD}
当我们将关键字绑定到属性中时,我们使用v-bind
<header v-bind:style="'background-image: url(https://source.unsplash.com/featured/?' + todoLists[currentListIndex].keyword + ')'">
<!-- ... -->
</header>
待办事项
要在主部分中呈现待办事项,我们需要使用v-for
。由于我们希望每个输入都有单独的 ID 和名称,因此我们在 for 循环中传递了索引v-for="(value, index) in object"
。
如果这些已经被检查过,我们就会用它v-bind
来检查/勾选我们的待办事项输入。
当我们点击复选框时,我们使用v-model
来更新 todos 的值。当复选框被选中时, isCompleted 将获得 true 的值,并且父级将自动获得isCompleted 的类名。isCompleted
li
.is-completed
true
该v-model
指令创建双向数据绑定,这意味着当值更新时,UI 也会更新。
<ul>
<li v-for="(todo, index) in todoLists[currentListIndex].items" v-bind:class="{'is-completed': todo.isCompleted}">
<label v-bind:for="'todo' + index">
<input
type="checkbox"
v-bind:name="'todo' + index"
v-bind:id="'todo' + index"
v-bind:checked="todo.isCompleted"
v-model="todo.isCompleted">
{{todo.name}}
</label>
<button class="is-danger">Edit todo</button>
</li>
<li>
<button class="is-add">New Todo</button>
</li>
</ul>
文档参考
更改当前列表
我们希望能够更改当前显示的列表。这个功能由currentListIndex
我们应用的数据设置。当我们点击某个列表项时,我们希望切换currentListIndex
到该列表项的索引,并关闭侧边导航(如果打开)。
我们还需要向用户显示当前正在显示的列表,为此,我们添加了类.is-active
if currentListIndex === index
。
<li v-for="(todoList, index) in todoLists" v-bind:class="{'is-active' : currentListIndex === index}">
<button v-on:click="currentListIndex = index; isNavOpen = false">
{{todoList.title}}
<span>
{{todoList.items.length}}
</span>
</button>
</li>
创建新列表
切换侧边栏
点击“创建新列表”时,我们会显示.sidebar
。为此,我们需要将 类添加.is-open
到此列表,然后如果此列表在移动设备上打开,则关闭导航栏。此操作方法与我们在移动设备上对导航栏的操作非常相似。
在我们的数据中,我们首先添加一个新条目isSidebarOpen: false
:
var app = new Vue({
el: "#app",
data: {
isNavOpen: false,
isSidebarOpen: false,
currentListIndex: 0
//...
}
});
现在让我们将我们的类绑定.is-open
到我们的.sidebar
:
<div class="sidebar" v-bind:class="{'is-open' : isSidebarOpen}">
<!-- ... -->
</div>
我们需要在单击“创建新列表”时添加一个事件处理程序,该事件处理程序将打开侧边栏并关闭移动设备上的导航:
<button class="is-add" v-on:click="isSidebarOpen = true; isNavOpen = false;">Create a new list</button>
很好,现在我们可以打开侧边栏🎉。
现在,当我们单击“取消”时,让我们关闭侧边栏:
<button type="button" class="is-danger" v-on:click="isSidebarOpen = false">Cancel</button>
添加新列表
要创建新列表,我们需要输入标题和关键字的值。当用户点击“创建列表”时,我们会将新值推送到todoLists
数据中。如果其中一个输入为空,则会显示默认值。
在我们的app.js中,添加一个tempNewList
数组,它将存储我们的输入值。
var app = new Vue({
el: "#app",
data: {
isNavOpen: false,
isSidebarOpen: false,
currentListIndex: 0,
tempNewList: [
{
title: null,
keyword: null
}
]
//...
}
});
现在我们将使用绑定我们的输入v-model
。
<form>
<h3>Create a new list</h3>
<label for="listTitle">Title:</label>
<input id="listTitle" name="listTitle" type="text" placeholder="My amazing next trip to south america" v-model="tempNewList.title">
<label for="listKeyword">Keyword:</label>
<input id="listKeyword" name="listKeyword" type="text" placeholder="Colombia" v-model="tempNewList.keyword">
<div class="buttons">
<button type="button" class="is-danger" v-on:click="isSidebarOpen = false">Cancel</button>
<button type="button" class="is-confirm">Create List</button>
</div>
</form>
好的,现在让我们将新tempNewList
值推送到todoLists
。
创建一个名为 的方法addNewList
。方法是存储为对象属性的函数。这里的对象是 Vue 实例。在 Vue 中,我们的方法将存储在一个methods
对象中。
addNewList
方法将遵循以下场景:
- 如果标题为空,则使用默认字符串
"🕵️ List with no name"
- 如果关键字为空,则使用默认字符串
"earth"
- 推动我们的价值观
todoLists
- 将当前列表更改为新列表
- 关闭侧边栏
- 重置输入的值
var app = new Vue({
el: "#app",
data: {
//...
},
methods: {
addNewList: function() {
var listTitle = this.tempNewList.title;
var listKeyword = this.tempNewList.keyword;
if (listTitle == null) {
listTitle = "🕵️ List with no name";
}
if (listKeyword == null) {
listKeyword = "earth";
}
this.todoLists.push({
title: listTitle,
keyword: listKeyword,
items: []
});
this.currentListIndex = this.todoLists.length - 1;
this.isSidebarOpen = false;
this.tempNewList.title = null;
this.tempNewList.keyword = null;
}
}
});
最后,我们将把我们的方法绑定到我们的创建列表按钮。
<button type="button" class="is-confirm" v-on:click="addNewList">Create List</button>
文档参考
编辑列表
好的,现在我们可以创建新列表了,我们希望能够编辑现有列表。我们可以编辑标题、关键字,还可以删除列表。
切换侧边栏内容
创建一个新方法openSidebar
。该方法将:
- 打开侧边栏
- 显示我们想要使用的表单
- 如果此导航处于打开状态,请关闭它
在数据中,让我们添加sidebarContentToShow: null
,这将使我们知道应该显示什么形式。
var app = new Vue({
el: "#app",
data: {
isNavOpen: false,
isSidebarOpen: false,
sidebarContentToShow: null,
currentListIndex: 0
//...
},
methods: {
//...
}
});
我们的侧边栏中有 4 种表单可供切换:
"createNewList"
"editList"
"createNewTodo"
"editTodo"
在 HTML 中,我们将根据 的值有条件地渲染表单sidebarContentToShow
。为此,我们使用了v-if
指令。它允许我们在条件成立时渲染代码块。我们需要取消注释表单,并添加一个v-if
指令。
<div class="sidebar" v-bind:class="{'is-open' : isSidebarOpen}">
<div class="sidebar-content">
<form v-if="sidebarContentToShow === 'createNewList'">
<h3>Create a new list</h3>
<!-- ... -->
</form>
<form v-if="sidebarContentToShow === 'editList'">
<h3>Edit list</h3>
<!-- ... -->
</form>
<form v-if="sidebarContentToShow === 'createNewTodo'">
<h3>Create a new todo</h3>
<!-- ... -->
</form>
<form v-if="sidebarContentToShow === 'editTodo'">
<h3>Edit todo</h3>
<!-- ... -->
</form>
</div>
</div>
现在,当我们点击“创建新列表”时,侧边栏出现了,但我们看不到……什么都没有😱。记得,那个正常的值sidebarContentToShow
被设置为了 null 😉。
为了改变的值,sidebarContentToShow
我们将创建一种openSidebar
方法来打开侧边栏并改变我们想要显示的形式。
var app = new Vue({
el: "#app",
data: {
//...
},
methods: {
openSidebar: function(contentToShow) {
this.isSidebarOpen = true;
this.isNavOpen = false;
this.sidebarContentToShow = contentToShow;
}
//...
}
});
现在我们可以更改创建一个新列表,以便我们可以使用openSidebar
<button class="is-add" v-on:click="openSidebar('createNewList')">Create a new list</button>
好了,我们现在渲染“创建新列表”表单。你可能已经猜到了,我们将在“编辑列表”按钮中重用我们的方法。
<button class="is-primary" v-on:click="openSidebar('editList')">Edit list</button>
编辑列表表单
删除列表
我们从删除列表按钮开始。创建一个名为 的新方法deleteList
。它将删除当前显示的列表并显示第一个列表。
//...
deleteList: function() {
this.todoLists.splice(this.currentListIndex, 1);
this.currentListIndex = 0;
this.isSidebarOpen = false;
}
//...
<button type="button" class="is-danger" v-on:click="deleteList">Delete list</button>
现在我们可以删除列表,但如果我们尝试删除所有列表,我们会收到错误并且我们的应用程序停止工作。
[Vue warn]: Error in render: "TypeError: todoLists[currentListIndex] is undefined"
你可能已经猜到了,出现这个错误是因为我们的todoLists
为空,而我们仍然尝试渲染依赖于 值的应用程序部分todoLists
。我们将使用条件渲染v-if
和v-else
,为了解决这个问题,我们将仅在 的情况下渲染主要内容todoLists.length > 0
。此外,我们希望用户能够创建新列表,我们将使用v-else
来显示一个可帮助用户创建新列表的替代主要内容。
<main v-if="todoLists.length > 0">
<!-- ... -->
</main>
<main v-else>
<header style="background-image: url(https://source.unsplash.com/featured/?cat">
<div class="header-content">
<h1>Please create a new list</h1>
<button class="is-add" v-on:click="openSidebar('createNewList')">Create a new list</button>
</div>
</header>
</main>
更改标题和关键字值
让我们回到editList表单。我们想要:
todoLists
使用将我们的输入与正确的元素绑定v-model
。- 当我们点击完成时,我们想要关闭滑块。
- 仅在以下情况下呈现此表单
todoLists.length > 0
<form v-if="sidebarContentToShow === 'editList' && todoLists.length > 0">
<h3>Edit list</h3>
<label for="listTitle">Title:</label>
<input id="listTitle" name="listTitle" type="text" placeholder="My amazing next trip to south america" v-model="todoLists[currentListIndex].title">
<label for="listKeyword">Keyword:</label>
<input id="listKeyword" name="listKeyword" type="text" placeholder="Colombia" v-model="todoLists[currentListIndex].keyword">
<div class="buttons">
<button type="button" class="is-danger" v-on:click="deleteList">Delete list</button>
<button type="button" class="is-confirm" v-on:click="isSidebarOpen = false">Done</button>
</div>
</form>
文档参考
创建和编辑待办事项
我们的应用程序的 UI 几乎完成了,我们还需要:
- 在列表中创建新的待办事项
- 编辑和删除现有的待办事项
听起来和我们对列表的操作很像吧?步骤几乎一样。
创建待办事项
在我们的数据中创建一个新的元素tempNewList
:
tempNewTodo: [
{
name: null,
isCompleted: false
}
],
我们需要一种新方法,以便我们可以将新的待办事项添加到列表中todoLists
addNewTodo: function() {
var todoName= this.tempNewTodo.name;
var todoCompleted = this.tempNewTodo.isCompleted;
if (todoName == null) {
todoName = "🕵️ unnamed todo";
}
this.todoLists[this.currentListIndex].items.push({
name: todoName,
isCompleted: todoCompleted
});
this.isSidebarOpen = false;
this.tempNewTodo.name = null;
this.tempNewTodo.isCompleted = false;
}
现在让我们深入了解 HTML。
我们需要使用createNewTodo表单打开侧边栏。
<button class="is-add" v-on:click="openSidebar('createNewTodo')">New Todo</button>
正如我们之前所做的那样,我们将使用绑定我们的输入v-model
并使用该addNewTodo
方法来推送我们的新值。
<form v-if="sidebarContentToShow === 'createNewTodo'">
<h3>Create a new todo</h3>
<label for="todoName">Name:</label>
<input id="todoName" name="todoName" type="text" placeholder="Do things..." v-model="tempNewTodo.name">
<label for="todoCompleted"><input name="todoCompleted" id="todoCompleted" type="checkbox" v-bind:checked="tempNewTodo.isCompleted" v-model="tempNewTodo.isCompleted"> Is completed</label>
<div class="buttons">
<button type="button" class="is-danger" v-on:click="isSidebarOpen = false">Cancel</button>
<button type="button" class="is-confirm" v-on:click="addNewTodo">Create todo</button>
</div>
</form>
由于我们现在正在绑定待办事项中的数据isCompleted
,因此我们将在导航中显示已完成待办事项的数量。
在我们的app.js中,创建一个totalTodosCompleted
传递当前 todoList 索引的方法。
totalTodosCompleted: function(i){
var total = 0;
for (var j = 0; j < this.todoLists[i].items.length; j++) {
if(this.todoLists[i].items[j].isCompleted){
total++;
}
}
return total;
}
现在navigation
,我们将使用新方法返回已完成待办事项的总数。
<li v-for="(todoList, index) in todoLists" v-bind:class="{'is-active' : currentListIndex === index}">
<button v-on:click="currentListIndex = index; isNavOpen = false">
{{todoList.title}}
<span>
{{totalTodosCompleted(index)}} / {{todoList.items.length}}
</span>
</button>
</li>
编辑待办事项
要编辑待办事项,首先,我们需要知道将要编辑的待办事项的索引,在我们的数据中创建currentTodoIndex
。
currentTodoIndex: 0,
我们需要一种deleteTodo
方法来删除当前的待办事项。
deleteTodo: function() {
this.todoLists[this.currentListIndex].items.splice(this.currentTodoIndex, 1);
this.isSidebarOpen = false;
this.currentTodoIndex = 0;
}
现在让我们看一下 HTML。
首先,我们要打开滑块并改变的值currentTodoIndex
。
<button class="is-primary" v-on:click="openSidebar('editTodo'); currentTodoIndex = index">Edit todo</button>
在我们的editTodo表单中,我们将:
- 仅在以下情况下显示我们的表格
todoLists[currentListIndex].items.length > 0
- 绑定待办事项名称,如果完成,使用
v-model
- 当我们点击删除待办事项时,触发该方法
deleteTodo
- 当我们点击完成时,关闭侧边栏
<form v-if="sidebarContentToShow === 'editTodo' && todoLists[currentListIndex].items.length > 0">
<h3>Edit todo</h3>
<label for="todoName">Todo:</label>
<input id="todoName" name="todoName" type="text" placeholder="Do things..." v-model="todoLists[currentListIndex].items[currentTodoIndex].name">
<label for="todoCompleted"><input name="todoCompleted" id="todoCompleted" type="checkbox" v-bind:checked="todoLists[currentListIndex].items[currentTodoIndex].isCompleted" v-model="todoLists[currentListIndex].items[currentTodoIndex].isCompleted"> Is completed</label>
<div class="buttons">
<button type="button" class="is-danger" v-on:click="deleteTodo">Delete todo</button>
<button type="button" class="is-confirm" v-on:click="isSidebarOpen = false">Done</button>
</div>
</form>
🎉🎉🎉🎉🎉 我们的待办事项的 UI 现已完成!
本地存储
当我们重新加载页面时,它会恢复到我们的虚拟值。如果我们能将列表和待办事项存储在本地,那该有多好啊?
我们将使用window.localStorage 。它是Web Storage API的一部分。
localStorage允许我们存储没有到期日期的数据。
在我们的app.js中,创建一个新方法updateTodoLocalStorage
//...
updateTodoLocalStorage: function () {
localStorage.setItem('todoLocalStorage', JSON.stringify(this.todoLists));
}
//...
我们使用setItem()
Web Storage API 中的方法。我们传递以下参数:
setItem(keyName, keyValue);
keyName
:我们要创建/更新的键的名称('todoLocalStorage'
)。keyValue
:我们想要赋予您正在创建/更新的密钥的值(JSON.stringify(this.todoLists)
)。
我们现在希望每次更新待办事项或列表的值时都使用此方法。Vue 允许我们使用选项来响应数据变化watch
。每当我们的值发生变化时todoLists
,我们都会调用我们的updateTodoLocalStorage
方法。由于我们的对象具有嵌套值,我们希望检测这些值内部的变化。我们可以通过传递deep: true
来实现这一点。
var app = new Vue({
el: "#app",
data: {
//...
},
watch: {
todoLists: {
handler() {
this.updateTodoLocalStorage();
},
deep: true
}
},
methods: {
//...
updateTodoLocalStorage: function() {
localStorage.setItem("todoLocalStorage", JSON.stringify(this.todoLists));
}
}
});
现在让我们检查一下我们的应用,并查看一下本地存储。如果我们创建/更新一个列表或待办事项,我们可以看到todoLocalStorage
存储正在更新。
现在,当我们加载页面时,我们需要将 our 设置todoLists
为 our todoLocalStorage
。Vue 自带了生命周期钩子。我们将使用它created: function()
来设置值。此外,我们还要删除虚拟值。
var app = new Vue({
el: "#app",
data: {
//...
todoLists: []
},
created: function() {
this.todoLists = JSON.parse(
localStorage.getItem("todoLocalStorage") || "[]"
);
},
watch: {
//...
},
methods: {
//...
}
});
现在,如果我们重新加载、关闭并重新打开我们的应用程序,我们所有的待办事项和列表都已保存。
文档参考
奖励 - 离线渐进式 Web 应用程序 (PWA)
在本教程的奖励部分中,我们将设置一个渐进式 Web 应用程序 (PWA) 和服务工作者,以便我们可以在智能手机上离线使用此 Web 应用程序。
设置 PWA
PWA 是:
渐进式 Web 应用是指 Web 应用,其内容类似于常规网页或网站,但用户在浏览时可以像传统应用或原生移动应用一样。这类应用试图将大多数现代浏览器提供的功能与移动体验的优势相结合。维基百科
它本质上是一个利用最新技术运行的网络应用程序,感觉就像一个原生应用程序。
要设置我们的 PWA,我们需要创建一个manifest.json
文件并设置我们的服务人员。
PWA 必须从安全来源(HTTPS)提供服务。
生成图标资产
首先,将所有图标资源添加到我们的项目中。这些图标已通过https://realfavicongenerator.net/生成。它们包含在 中content/img/
。
在我们的 HTML 头部,我们要包含:
<link rel="apple-touch-icon" sizes="180x180" href="content/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="content/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="content/img/favicon-16x16.png">
<link rel="mask-icon" href="content/img/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="content/img/favicon.ico">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-config" content="content/img/browserconfig.xml">
<meta name="theme-color" content="#77c4d3">
Web 应用清单
Web 应用清单 (manifest.json) 是一个提供 Web 应用相关信息的文件,例如图标、应用程序名称等。它是 PWA 技术的一部分。您可以在MDN Web 文档中获取更多关于 Web 应用清单的信息。
在我们的项目根目录下创建此文件。
{
"name": "todo",
"short_name": "todo",
"author": "Vincent Humeau",
"lang": "en-GB",
"icons": [
{
"src": "content/img/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "content/img/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#77c4d3",
"background_color": "#77c4d3",
"display": "standalone",
"orientation": "portrait",
"scope": "/todo/",
"start_url": "/todo/"
}
在我们的 HTML 文件中,我们想要包含它。
<link rel="manifest" href="manifest.json">
服务人员
什么是服务人员?
Service Worker 是一项新的浏览器功能,它提供独立于网页运行的事件驱动脚本。与其他 Worker 不同,Service Worker 可以在事件结束时关闭,请注意,它不会保留文档的引用,并且可以访问全域事件,例如网络抓取。Service Worker 还具有可脚本化的缓存。除了能够通过脚本响应来自特定网页的网络请求之外,它还为应用程序提供了一种“离线”的方式。w3c /ServiceWorker - Github
本教程并不旨在深入介绍服务工作者,您可以在网上找到一些很棒的教程和资源:
- 如何设置基本服务工作线程(带缓存) - bitofcode(视频)
- Service Worker:简介
- pwabuilder-服务人员
- pwabuilder-服务人员
- 灯塔
- 使用 ServiceWorker 实现简单的离线工作网站
- Service Worker 入门
对于我们的服务人员,我们使用来自 Omranic 的这个要点
sw.js
在我们的项目根目录创建一个文件。
在我们的index.html中:
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('sw.js');
});
}
</script>
然后,在我们的sw.js中,我们将缓存所有允许我们的应用程序离线使用的资产:
var shellCacheName = "pwa-todo-v1";
var filesToCache = [
"./",
"./index.html",
"./content/css/screen.min.css",
"./content/js/app.js",
"https://cdn.jsdelivr.net/npm/vue",
"https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css"
];
现在,我们只需要遵循这个要点并添加部分“监听安装事件”、“更新资产缓存”和“从缓存中离线提供应用程序外壳”。
本教程终于完成了。我们的待办事项 vue.js PWA现在可以在这里访问了:https://vinceumo.github.io/todo
文章来源:https://dev.to/vinceumo/vuejs-101-todo-pwa-tutorial-4bne