核心知识
上一篇文章探讨了petite-vue核心知识,本文实践一下这些知识。
petite-vue特点
petite-vue
is an alternative distribution of Vue optimized for progressive enhancement.
petite-vue的主要特点是渐进增强
,什么是渐进增强
呢?
image-20210724220557315
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
image-20210724220841196
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。比如一开始使用 CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行 hack 使其可以在低版本浏览器上正常浏览。
案例体验
TodoMVC淋漓尽致展现了这一点,一开始尽快实现最小的、简单的功能,再一点点增加功能,增强用户体验。
Step01:初始化
image-20210725174929068
首先是初始化,我们使用了如下知识点:
- 模块方式引入:
import {createApp} from 'https://unpkg.com/petite-vue?module'
- 根作用域
- 明确的挂载目标
- v-cloak指令应用
<style>
/* v-cloak应用 */
[v-cloak] {
display: none;
}
</style>
<script type="module">
// 模块方式引入
import { createApp } from 'https://unpkg.com/petite-vue?module'
// 根作用域
createApp({
todos: [
{ id: 1, title: 'petite-vue', completed: false },
{ id: 2, title: 'Alpine', completed: false },
{ id: 3, title: 'svelte', completed: false },
],
}).mount('#app') // 明确挂载目标
</script>
<!-- v-clock应用 -->
<div id="app" v-cloak>
<ul class="todo-list">
<!-- v-clock应用 -->
<li v-for="todo in todos" class="todo">
{{ todo.title }}
</li>
</ul>
</div>
Step02:数据修改和持久化
Jul-25-2021 17-52-14
下面维护todo列表数据,我们希望:
- 双击待办事项可以切换为编辑状态,这个通过动态class实现
<li v-for="todo in todos" class="todo"
:class="{ completed: todo.completed, editing: todo === editedTodo }">
- 切换为编辑状态,input可以自动获取焦点
- 修改数据之后,自动持久化到localStorage中
我们想要维护todo列表,就要在根作用域中添加若干方法,不同于vue中要放入methods
,它们存在于选项的根上:
<script type="module">
createApp({
editedTodo: null,
removeTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
},
editTodo(todo) {
this.beforeEditCache = todo.title
this.editedTodo = todo
},
doneEdit(todo) {
if (!this.editedTodo) {
return
}
this.editedTodo = null
todo.title = todo.title.trim()
if (!todo.title) {
this.removeTodo(todo)
}
},
cancelEdit(todo) {
this.editedTodo = null
todo.title = this.beforeEditCache
},
}).mount('#app')
</script>
视图中可以直接使用它们:
<li v-for="todo in todos" class="todo"
:class="{ completed: todo.completed,
editing: todo === editedTodo }">
<div class="view">
<input class="toggle" type="checkbox"
v-model="todo.completed" />
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button class="destroy" @click="removeTodo(todo)">X</button>
</div>
<!--副作用的应用-->
<input class="edit" type="text" v-model="todo.title"
@blur="doneEdit(todo)" @keyup.enter="doneEdit(todo)"
@keyup.escape="cancelEdit(todo)" />
</li>
接下来是保存功能的实现,这里利用了v-effect
指令,我们该如何理解它呢?看看下面数据保存功能:
根节点上面添加v-effect
,则save
方法中的响应式数据就会和save
之间建立依赖关系,数据变化,则save
再次执行。
<!-- 注意save()后面的小括号不能删除!!! -->
<div id="app" v-effect="save()">
......
</div>
save
将todos存入localStorage,从而实现数据持久化:
<script type="module">
createApp({
save() {
localStorage.setItem('todos', JSON.stringify(this.todos))
},
}).mount('#app')
</script>
另一个v-effect
用例是编辑输入框自动获取焦点,可以发现能够很好代替指令完成任务:
<input class="edit" v-effect="if(todo === editedTodo) $el.focus();" />
Step03:过滤
最后我们希望能够对todo进行过滤:
Jul-25-2021 18-01-22
这里实现一个简易路由,hash变更时修改过滤级别:
setupRouting() {
const onHashChange = () => {
const visibility = window.location.hash.substr(2)
if (['all', 'active', 'completed'].includes(visibility)) {
this.visibility = visibility
} else {
window.location.hash = ''
this.visibility = 'all'
}
}
window.addEventListener('hashchange', onHashChange)
onHashChange()
},
视图中通过mounted
钩子安装这个路由:
<div id="app" @mounted="setupRouting">
再利用get方法
计算出过滤结果,从而实现过滤功能:
get filteredTodos() {
switch (this.visibility) {
case 'all': return this.todos
case 'active': return this.todos.filter(todo => !todo.completed)
case 'completed': return this.todos.filter(todo => todo.completed)
}
},
视图中修改为这个过滤结果,这类似于计算属性
,注意添加key
<li v-for="todo in filteredTodos" :key="todo.id"></li>