这是一个用Vue3实现的一个TodoList案例。
下面这张图是最终的实现效果。
下面是代码实现
一、项目骨架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<h2>{{title}}</h2>
<input type="text" v-model="title">
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const App = {
data() {
return {
title: "",
}
},
}
Vue.createApp(App).mount('#app');
</script>
</body>
</html>
二、任务列表
<div id="app">
<h2>{{title}}</h2>
<input type="text" v-model="title">
<ul>
<li v-for="todo in todos">{{todo}}</li>
</ul>
</div>
const App = {
data() {
return {
title: "",
todos: ['吃饭', '睡觉']
}
},
}
三、添加操作
const App = {
data() {
return {
title: "",
todos: ['吃饭', '睡觉']
}
},
methods: {
addTodo() {
this.todos.push(this.title);
this.title = "";
}
},
}
四、数组内改为对象
<div id="app">
<h2>{{title}}</h2>
<input type="text" v-model="title" @keydown.enter="addTodo">
<ul>
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.done">
<span>{{todo.title}}</span>
</li>
</ul>
</div>
const App = {
data() {
return {
title: "",
todos: [
{title: '吃饭', done: false},
{title: '睡觉', done: false},
]
}
},
methods: {
addTodo() {
this.todos.push({
title: this.title,
done: false
});
this.title = "";
}
},
}
五、底部全选实现
<div id="app">
<h2>{{title}}</h2>
<input type="text" v-model="title" @keydown.enter="addTodo">
<ul>
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.done">
<span>{{todo.title}}</span>
</li>
</ul>
<div>
全选
<input type="checkbox" v-model="allDone">
<span>{{active}} / {{all}}</span>
</div>
</div>
computed: {
active() {
return this.todos.filter(todo => !todo.done).length
},
all() {
return this.todos.length
},
allDone: {
get() {
return this.active === 0
},
set(val) {
this.todos.forEach(todo => todo.done = val)
}
}
},
六、清除已完成任务
<button @click="clear" v-if="active<all">清理</button>
clear() {
this.todos = this.todos.filter(todo => !todo.done)
}
七、完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.done {
color: grey;
text-decoration: line-through;
}
</style>
</head>
<body>
<div id="app">
<h2>{{title}}</h2>
<input type="text" v-model="title" @keydown.enter="addTodo">
<button @click="clear" v-if="active<all">清理</button>
<ul>
<li v-for="todo in todos">
<input type="checkbox" v-model="todo.done">
<span :class="{done: todo.done}">{{todo.title}}</span>
</li>
</ul>
<div>
全选
<input type="checkbox" v-model="allDone">
<span>{{active}} / {{all}}</span>
</div>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const App = {
data() {
return {
title: "",
todos: [
{title: '吃饭', done: false},
{title: '睡觉', done: false},
]
}
},
methods: {
addTodo() {
this.todos.push({
title: this.title,
done: false
});
this.title = "";
},
clear() {
this.todos = this.todos.filter(todo => !todo.done)
}
},
computed: {
active() {
return this.todos.filter(todo => !todo.done).length
},
all() {
return this.todos.length
},
allDone: {
get() {
return this.active === 0
},
set(val) {
this.todos.forEach(todo => todo.done = val)
}
}
},
watch: {
todos: {
handler(newVal, oldVal) {
console.info("todos->change")
localStorage.setItem("todos", JSON.stringify(this.todos))
},
deep: true
}
},
mounted() {
//加载数据
var todos = localStorage.getItem("todos");
if (todos) {
this.todos = JSON.parse(todos);
}
},
unmounted() {
//保存数据
localStorage.setItem("todos", JSON.stringify(this.todos))
},
}
Vue.createApp(App).mount('#app');
</script>
</body>
</html>