上图
实现简单的
增删改查
reactive, toRefs, computed, watchEffect, filters,localStorage数据存储、获取
。如果想要实现多组件封装,请看这个
代码如下
<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)">删除</button>
</div>
<!-- 编辑待办 -->
<input
type="text"
class="edit"
v-model="todo.title"
v-todo-focus="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' }"
>全部</span
>
<span
@click="visibility = 'active'"
:class="{ selected: visibility === 'active' }"
>代办</span
>
<span
@click="visibility = 'completed'"
:class="{ selected: visibility === '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 todoStorge = {
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 {
name: "apIndex",
// 自定义指令 todo-focus 也可以不要
directives: {
"todo-focus": (el, { value }) => {
console.log(el, value, "自定义操作");
if (value) {
el.focus();
}
},
},
setup() {
const state = reactive({
newTodo: "",
todos: todoStorge.fetch(),
// todos: [],
beforeEditCache: "", //缓存编辑前的title
editedTodo: null, //正在编辑的todo
visibility: "all", // 默认展示全部状态
filterdTodos: computed(() => { // 查询过滤
return filters[state.visibility](state.todos);
}),
});
// 回车添加事件
function addTodo() {
console.log(Date.now(), state.newTodo);
state.todos.push({
id: Date.now(),
title: state.newTodo,
completed: false,
});
// 添加之后输入框置空
state.newTodo = "";
}
// 删除事件
function removeTodo(todo) {
state.todos.splice(state.todos.indexOf(todo), 1);
}
// 编辑事件
function editTodo(todo) {
state.beforeEditCache = todo;
state.editedTodo = todo;
}
// 取消编辑
function cancelTodo(todo) {
todo.title = state.beforeEditCache;
state.editedTodo = null;
}
// 确认编辑
function doneEdit() {
state.editedTodo = null;
}
watchEffect(() => {
todoStorge.save(state.todos);
});
return {
...toRefs(state),
addTodo,
removeTodo,
editTodo,
cancelTodo,
doneEdit,
};
},
};
</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>