一个ToolList案例
App.vue中
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
<Todos></Todos>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import Todos from './components/Todos.vue'
export default {
name: 'App',
components: {
HelloWorld,
Todos
}
}
</script>
Todos.vue中:
<template>
<div>
<!-- 新增todo -->
<input
type="text"
v-model="newTodo"
@keyup.enter="addTodo"
autofocus
placeholder="新增进入待办"
autocomplete="off"
/>
<!-- todo列表 -->
<ul>
<li
v-for="todo in filterdTodos"
:key="todo.id"
:class="{ completed: todo.completed, editing: todo === editedTodo }"
>
<div class="view">
<input type="checkbox" v-model="todo.completed" />
<label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button @click="removeTodo(todo)">X</button>
</div>
<!-- 编辑代办 -->
<input
type="text"
class="edit"
v-model="todo.title"
v-todo-foucs="todo===editedTodo"
@blur="doneEdit(todo)"
@keyup.enter="doneEdit(todo)"
@keyup.escape="cancelTodo(todo)"
/>
</li>
</ul>
<!-- 过滤 -->
<p class="filters">
<span @click="visibility='all'" :class="{selected:visibility==='all'}">ALL</span>
<span @click="visibility='active'" :class="{selected:visibility==='active'}">Active</span>
<span @click="visibility='completed'" :class="{selected:visibility==='completed'}">Completed</span>
</p>
</div>
</template>
<script>
import { reactive, toRefs ,computed,watchEffect} from "vue";
// 过滤器
const filters={
all(todos){
return todos
},
active(todos){
return todos.filter(todo=>!todo.completed)
},
completed(todos){
return todos.filter(todo=>todo.completed)
},
}
// 缓存操作
const todoStorage={
fetch(){
let todos=JSON.parse(localStorage.getItem('vue3-todos')||'[]')
todos.forEach((todo,index) =>{
todo.id=index+1
})
return todos
},
save(todos){
localStorage.setItem("vue3-todos",JSON.stringify(todos));
}
}
// 存储操作
export default {
setup() {
const state = reactive({
newTodo: "",
todos: todoStorage.fetch(),//初始化
beforeEditCache: '', //缓存编辑前的title
editedTodo: null, // 正在编辑的todo
visibility:'all',
filterdTodos:computed(()=>{
return filters[state.visibility](state.todos)
})
});
function addTodo() {
state.todos.push({
id: state.todos.length + 1,
title: state.newTodo,
completed: false,
});
// 状态置空
state.newTodo = "";
}
function removeTodo(todo) {
state.todos.splice(state.todos.indexOf(todo), 1);
}
function editTodo(todo) {
state.beforeEditCache = todo.title;
state.editedTodo = todo;
}
function cancelTodo(todo) {
todo.title = state.beforeEditCache;
state.editedTodo = null;
}
function doneEdit(todo) {
state.editedTodo = null;
}
watchEffect(()=>{
todoStorage.save(state.todos)
})
return {
...toRefs(state),
addTodo,
removeTodo,
editTodo,
cancelTodo,
doneEdit,
};
},
directives:{
"todo-foucs":(el,{value},vnode)=>{
if(value){
el.focus();
}
}
}
};
</script>
<style scoped>
.completed label {
text-decoration: line-through;
}
.edit,
.editing .view {
display: none;
}
.view,
.editing .edit {
display: block;
}
.filters >span{
padding:2px 4px;
margin-right: 4px;
border: 1px solid transparent;
}
.filters >span.selected{
border-color: rgba(173,47,47,0.2);
}
</style>