任务清单(单文件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
<style>
table {
border: 1px solid black;
border-collapse: collapse;
}
tr,
td {
border: 1px solid black;
text-align: center;
padding: 10px;
}
</style>
</head>
<body>
<div id="app">
<h3>小满记事本</h3>
<p><input type="text" v-model="text" @keyup.enter="addTask"> <button @click="addTask">添加任务</button> <button
@click="clear" v-show="taskList.length > 0">清空任务</button></p>
<table v-show="taskList.length > 0">
<tr>
<td>任务id</td>
<td>任务内容</td>
<td colspan="2">操作</td>
</tr>
<tr v-for="(task, index) in taskList" :key="task.id">
<td>{{index+1}}</td>
<td>{{task.name}}</td>
<td><button @click="changeTask(task)">修改任务</button></td>
<td><button @click="del(task.id)">删除任务</button></td>
</tr>
</table>
<p v-show="taskList.length > 0">任务数量: {{taskList.length}} </p>
<br>
<!-- 修改任务的时候会用到 -->
<div v-show="isShow">
<label>请输入新的任务内容<input type="text" v-model="newText"></label> <button @click="relChange">确认修改</button>
</div>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
taskList: [
{ "id": 1, "name": "欺负小满" },
{ "id": 2, "name": "逃课" }
],
text: "",
newText: "",
isShow: 0,
// 需要被修改的对象
changeOBJ: null,
},
methods: {
// 新增任务
addTask() {
if (this.text !== "") {
this.taskList.push(
{ id: this.taskList.length + 1, name: this.text }
)
this.text = ""
} else {
alert("请输入任务名称!")
}
},
// 删除任务 根据id去删除
del(id) {
this.taskList = this.taskList.filter(item => item.id !== id)
},
// 首次修改
changeTask(obj) {
this.isShow = 1
this.changeOBJ = obj
},
// 最终修改
relChange() {
this.changeOBJ.name = this.newText
alert("任务修改成功!")
this.isShow = 0
},
// 清空任务
clear() {
this.taskList = []
}
},
})
</script>
</html>
效果演示
任务清单(组件版)
- 父子通信,遵循单文件流原则
- 自己的数据自己负责,即虽然数据是从父传给子的,但是修改还是要子传给父,然后父操作修改或者删除
- 别忘记加scoped,保证样式互不影响
- 持久化存储 watch ,created里面,深度监视 deep
持久化存储更简单的写法
list: JSON.parse(localStorage.getItem("data")) || [默认数组]
NoteDetail.vue
<template>
<div class="note-detail">
<!-- 头部 -->
<ToDoHeader @addTask="addTask"></ToDoHeader>
<br>
<!-- 身体 -->
<ToDoMain :list="list" @delTask="delTask"></ToDoMain>
<br>
<!-- 底部 -->
<ToDoFooter :list="list" @clearTask="clearTask" v-show="list.length > 0"></ToDoFooter>
</div>
</template>
<script>
import ToDoHeader from "@/components/ToDoHeader.vue";
import ToDoMain from "@/components/ToDoMain.vue";
import ToDoFooter from "@/components/ToDoFooter.vue";
export default {
components: {
ToDoHeader,
ToDoMain,
ToDoFooter,
},
data() {
return {
baseLsit: [
{ id: 1, name: "按时吃饭" },
{ id: 2, name: "按时摸鱼" },
{ id: 3, name: "按时学习" },
],
// 传递给子组件的数组 这里置空了因为数据从本地读取
list: [],
// 用来控制当数据为空的适合 底部组件是否显示
isShow: true
};
},
created() {
// 如果能从本地读取到数据,默认的数据就从本地获取
// 如果读取不到 默认数据就从初始化的baseList获取
if (localStorage.getItem('data')){
this.list = JSON.parse(localStorage.getItem('data'))
}else{
this.list = this.baseLsit
}
},
methods: {
// 添加单个任务
addTask(value){
this.list.unshift({
id: this.list.length + 1,
name: value
})
},
// 删除单个任务
delTask(id){
this.list = this.list.filter(item => item.id !== id)
},
// 清空全部任务
clearTask(value){
this.list = value
}
},
watch: {
list: {
deep: true,
handler(newValue){
// 持久化到本地
localStorage.setItem("data", JSON.stringify(newValue))
}
}
}
};
</script>
<style scoped>
.note-detail {
margin: 50px;
width: 500px;
/* height: 300px; */
background-color: tomato;
padding: 50px;
}
</style>
ToDoHeader.vue
<!-- ToDoHeader.vue -->
<template>
<div class="todo-header">
<p>
<label><input type="text" placeholder="请输入任务名称" v-model="task" @keyup.13="addTask"></label>
 
<button @click="addTask" class="btn btn-dark">添加任务</button>
</p>
</div>
</template>
<script>
export default {
data() {
return {
task: ""
}
},
methods: {
addTask(){
if (this.task.trim() === ''){
alert('不能为空')
return
}
// 添加让父组件添加
this.$emit("addTask", this.task)
// 清空默认的输入
this.task = ''
}
},
}
</script>
<style scoped>
.todo-header p {
margin: auto;
width: 80%;
}
</style>
ToDoMain.vue
<!-- ToDoMain.vue -->
<template>
<div class="todo-main">
<ul v-for="(item, index) in list" :key="item.id">
<li>
<span>{{ index + 1 }} {{ item.name }}</span>
<span @click="del(item.id)">x</span>
</li>
<hr>
</ul>
</div>
</template>
<script>
export default {
props: {
list: {
type: Array,
required: true,
},
},
methods: {
del(id){
this.$emit("delTask", id)
}
},
};
</script>
<style scoped>
.todo-main ul {
list-style: none;
}
li {
/* text-indent: 2em; */
margin: 0 10px 0 10px;
display: flex;
justify-content: space-between
}
</style>
ToDoFooter.vue
<!-- ToDoFooter.vue -->
<template>
<div class="todo-footer">
<div class="inner">
<span>合计:{{ totalCount }}</span>
<span><button @click="clearTask" class="btn btn-danger">清空任务</button></span>
</div>
</div>
</template>
<script>
export default {
props: {
list: {
type: Array,
required: true,
default: () => [],
},
},
computed: {
totalCount() {
return this.list.length;
},
},
methods: {
clearTask(){
this.$emit("clearTask", [])
}
},
};
</script>
<style scoped>
div.inner {
display: flex;
justify-content: space-between;
}
span {
font-weight: 700;
color: #fff;
}
</style>