1 <!DOCTYPE html>
2 <html>
3
4 <head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <title>VueTodoList</title>
9 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 <link href="css/style.css" rel="stylesheet" />
11 <link href="css/animate.css" rel="stylesheet" />
12 </head>
13
14 <body>
15 <div id="app">
16 <header>
17 <section>
18 <form action="javascript:;">
19 <label for="title">ToDoList</label>
20 <!-- 绑定回车事件 -->
21 <input type="text" id="title" name="title" placeholder="添加ToDo" autocomplete="off" required
22 v-model="addDoingThings" @keydown.enter="addDoingThingsList" />
23 </form>
24 </section>
25 </header>
26 <section>
27 <h2>正在进行 <span id="todocount">0</span></h2>
28 <div id="todolist" class="demo-box">
29 <transition-group name="slide" enter-active-class="animated bounceInLeft"
30 leave-active-class="animated bounceOutRight">
31 <span class="doingItem" v-for="(item, index) in doingList" :key="'item'+index">
32 <input type="checkbox" @click.prevent="checkDoneThings(item.id)">
33 <span>{{item.content}}</span>
34 <a href="javascript:;" class="delBtn" @click.prevent="delThings(item.id)">-</a>
35 </span>
36 </transition-group>
37 </div>
38 <h2>已经完成 <span id="donecount">0</span></h2>
39 <div id="donelist">
40 <transition-group name="slide" enter-active-class="animated bounceInLeft"
41 leave-active-class="animated bounceOutRight">
42 <span class="doneItem" v-for="(item, index) in doneList" :key="'item'+index">
43 <input type="checkbox" checked @click.prevent="checkDoneThings(item.id)">
44 <span>{{item.content}}</span>
45 <a href="javascript:;" class="delBtn" @click.prevent="delThings(item.id)">-</a>
46 </span>
47 </transition-group>
48 </div>
49 </section>
50 <footer>
51 Copyright © 2020 <a href="https://www.cnblogs.com/rchi/">股股清流@博客园</a>
52 </footer>
53 </div>
54 <script>
55 var app = new Vue({
56 el: '#app',
57 data: {
58 todoList: [],
59 addDoingThings: ""
60 },
61 computed: {
62 //通过过滤未做好事情列表和已做好事件列表
63 //正在做的事件
64 doingList: function () {
65 let arr = this.todoList.filter(function (item, index) {
66 return !item.isDone
67 })
68 return arr;
69 },
70 //已做好的事件
71 doneList: function () {
72 let arr = this.todoList.filter(function (item, index) {
73 return item.isDone
74 })
75 return arr;
76 }
77 },
78 mounted() {
79 //页面初始化完毕,从本地存储中拿到todoList替换本地todoList
80 this.todoList = localStorage.todoList ? JSON.parse(localStorage.todoList) : [];
81 },
82 methods: {
83 //添加待做事情列表,id:要做的事情的序号,content:要做的事情,idDone:是否做好,默认是未做好
84 addDoingThingsList: function () {
85 if (this.addDoingThings == "") return
86 this.todoList.push({
87 id: this.todoList.length,
88 content: this.addDoingThings,
89 isDone: false
90 })
91 this.addDoingThings = ""
92 this.saveData()
93 },
94 //保存数据到本地存储
95 saveData: function () {
96 localStorage.todoList = JSON.stringify(this.todoList)
97 },
98 //选择做完的事情
99 checkDoneThings: function (id) {
100 this.todoList[id].isDone = !this.todoList[id].isDone;
101 //每次修改后要保存
102 this.saveData();
103 },
104 //删除任务
105 delThings: function (id) {
106 this.todoList.splice(id, 1)
107 this.todoList.forEach(function (item, i) {
108 item.id = i
109 })
110 //每次修改后要保存
111 this.saveData();
112 }
113 }
114 });
115 </script>
116 </body>
117 </html>
1 body {
2 margin: 0;
3 padding: 0;
4 font-size: 16px;
5 background: #cdcdcd;
6 }
7
8 a {
9 text-decoration: none;
10 }
11
12 header {
13 height: 50px;
14 background: #333;
15 background: rgba(47, 47, 47, 0.98);
16 }
17
18 section {
19 margin: 0 auto;
20 }
21
22 label {
23 float: left;
24 width: 100px;
25 line-height: 50px;
26 color: #ddd;
27 font-size: 24px;
28 cursor: pointer;
29 font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
30 }
31
32 header input {
33 float: right;
34 width: 60%;
35 height: 24px;
36 margin-top: 12px;
37 text-indent: 10px;
38 border-radius: 5px;
39 box-shadow: 0 1px 0 rgba(255, 255, 255, 0.24),
40 0 1px 6px rgba(0, 0, 0, 0.45) inset;
41 border: none;
42 }
43
44 input:focus {
45 outline-width: 0;
46 }
47
48 h2 {
49 position: relative;
50 }
51
52 .doingItem,
53 .doneItem {
54 display: flex;
55 }
56
57 .doingItem span,
58 .doneItem span {
59 flex: 10;
60 display: inline-block;
61 padding: 0 5px;
62 text-align: left;
63 color: #666;
64 font-size: 14px;
65 }
66
67 .doingItem input,
68 .doneItem input {
69 width: 22px;
70 height: 22px;
71 cursor: pointer;
72 align-self: center;
73 }
74
75 p {
76 margin: 0;
77 }
78
79 .doingItem p input,
80 .doneItem p input {
81 top: 3px;
82 left: 40px;
83 width: 70%;
84 height: 20px;
85 line-height: 14px;
86 text-indent: 5px;
87 font-size: 14px;
88 }
89
90 .doingItem,
91 .doneItem {
92 height: 32px;
93 line-height: 32px;
94 background: #fff;
95 position: relative;
96 margin-bottom: 10px;
97 padding: 0 10px;
98 border-radius: 3px;
99 border-left: 5px solid #629a9c;
100 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
101 }
102
103 .doneItem {
104 border-left: 5px solid #666;
105 }
106
107 .doingItem a.delBtn,
108 .doneItem a.delBtn {
109 display: inline-block;
110 line-height: 18px;
111 width: 22px;
112 height: 22px;
113 border-radius: 14px;
114 text-align: center;
115 background: #f1f1f1;
116 color: #666;
117 font-size: 28px;
118 cursor: pointer;
119 align-self: center;
120 }
121
122 footer {
123 color: #666;
124 font-size: 14px;
125 text-align: center;
126 }
127
128 footer a {
129 color: #666;
130 text-decoration: none;
131 color: #999;
132 }
133
134 @media screen and (max-device-width: 620px) {
135 section {
136 width: 96%;
137 padding: 0 2%;
138 }
139 }
140
141 @media screen and (min-width: 620px) {
142 section {
143 width: 600px;
144 padding: 0 10px;
145 }
146 }