index.html 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <title>Todo List</title>
  7. <link rel="stylesheet" href="/assets/css/base.css">
  8. <link rel="stylesheet" href="/assets/css/index.css">
  9. <!-- 进度条 -->
  10. <link rel="stylesheet" href="/js/nprogress/nprogress.css">
  11. </head>
  12. <body>
  13. <section class="todoapp">
  14. <header class="header">
  15. <h1>todos</h1>
  16. <input class="new-todo" placeholder="What needs to be done?" id="task" autofocus>
  17. </header>
  18. <!-- This section should be hidden by default and shown when there are todos -->
  19. <section class="main">
  20. <input class="toggle-all" type="checkbox">
  21. <label for="toggle-all">Mark all as complete</label>
  22. <ul class="todo-list" id="todo-list"></ul>
  23. </section>
  24. <!-- This footer should hidden by default and shown when there are todos -->
  25. <footer class="footer">
  26. <!-- This should be `0 items left` by default -->
  27. <span class="todo-count"><strong id="count">0</strong> item left</span>
  28. <!-- Remove this if you don't implement routing -->
  29. <ul class="filters">
  30. <li>
  31. <a class="selected" href="javascript:;" id="all">All</a>
  32. </li>
  33. <li>
  34. <a href="javascript:;" id="active">Active</a>
  35. </li>
  36. <li>
  37. <a href="javascript:;" id="completed">Completed</a>
  38. </li>
  39. </ul>
  40. <!-- Hidden if no completed items are left ↓ -->
  41. <button class="clear-completed" id="clearAll">Clear completed</button>
  42. </footer>
  43. </section>
  44. <script src="/js/jquery.min.js"></script>
  45. <script src="/js/template-web.js"></script>
  46. <script src="/js/nprogress/nprogress.js"></script>
  47. <script type="text/html" id="taskTpl">
  48. {{each tasks}}
  49. <li class="{{$value.complete ? 'completed': ''}}">
  50. <div class="view">
  51. <input class="toggle" type="checkbox" {{$value.complete ? 'checked': ''}}>
  52. <label>{{$value.title}}</label>
  53. <button class="destroy" data-id="{{$value._id}}"></button>
  54. </div>
  55. <input class="edit" value="Rule the web">
  56. </li>
  57. {{/each}}
  58. </script>
  59. <script>
  60. let taskAry = [];
  61. const taskBox = $("#todo-list");
  62. const strong = $("#count");
  63. const all = $("#all");
  64. const completed = $("#completed");
  65. const active = $("#active");
  66. const clearAll = $("#clearAll");
  67. $.ajax({
  68. url: '/todo/task',
  69. type: 'get',
  70. success: (response) => {
  71. taskAry = response;
  72. render(taskAry);
  73. }
  74. })
  75. const task = $("#task");
  76. task.on('keyup', function (event) {
  77. if(event.keyCode === 13){
  78. // 回车键
  79. let taskName = $(this).val();
  80. if( taskName.trim().length === 0) {
  81. alert('请输入任务名称')
  82. return;
  83. }
  84. $.ajax({
  85. url: '/todo/addTask',
  86. type: 'post',
  87. data: JSON.stringify({
  88. title: taskName,
  89. }),
  90. contentType: 'application/json',
  91. success: response => {
  92. taskAry.push(response);
  93. render(taskAry);
  94. task.val('');
  95. }
  96. })
  97. }
  98. })
  99. const render = (arr) => {
  100. const html = template("taskTpl", {
  101. tasks: arr
  102. })
  103. taskBox.html(html);
  104. accumulate();
  105. }
  106. // 删除任务
  107. taskBox.on('click', '.destroy', function () {
  108. const id = $(this).attr('data-id');
  109. $.ajax({
  110. url: '/todo/deleteTask',
  111. type: 'get',
  112. data: {
  113. id
  114. },
  115. success: (response) => {
  116. if(response === 'ok') {
  117. // 找到已删除的id
  118. var index = taskAry.findIndex(item => item._id === id);
  119. taskAry.splice(index, 1);
  120. render(taskAry);
  121. }else {
  122. alert('删除失败');
  123. }
  124. }
  125. });
  126. })
  127. // 勾选
  128. taskBox.on('change', '.toggle', function () {
  129. // 代表复选框是否选中,true是选中,false是未选中
  130. const status = $(this).is(':checked');
  131. const id = $(this).siblings('button').attr('data-id');
  132. $.ajax({
  133. url: '/todo/updateTask',
  134. type: 'post',
  135. data: JSON.stringify({
  136. id,
  137. complete: status
  138. }),
  139. contentType: 'application/json',
  140. success: (response) => {
  141. if(response === 'ok') {
  142. // 修改任务的状态
  143. var task = taskAry.find(item => item._id === id);
  144. task.complete = status;
  145. render(taskAry);
  146. }else {
  147. alert('修改失败');
  148. }
  149. }
  150. });
  151. })
  152. // 双击
  153. taskBox.on('dblclick', 'label', function () {
  154. $(this).parent().parent().addClass('editing');
  155. $(this).parent().siblings('input').val($(this).text());
  156. $(this).parent().siblings('input').focus();
  157. })
  158. // 当文本框离开焦点
  159. taskBox.on('blur', '.edit', function () {
  160. const newTitle = $(this).val();
  161. const id = $(this).siblings().find('button').attr('data-id');
  162. $.ajax({
  163. url: '/todo/modifyTask',
  164. type: 'post',
  165. data: JSON.stringify({
  166. id,
  167. title: newTitle
  168. }),
  169. contentType: 'application/json',
  170. success: (response) => {
  171. if(response === 'ok') {
  172. // 修改任务的状态
  173. var task = taskAry.find(item => item._id === id);
  174. task.title = newTitle;
  175. render(taskAry);
  176. }else {
  177. alert('修改失败');
  178. }
  179. }
  180. });
  181. })
  182. function accumulate() {
  183. let count = 0;
  184. // 未完成的数组
  185. let newAry = taskAry.filter(item => !item.complete);
  186. count = newAry.length;
  187. strong.text(count);
  188. }
  189. all.on('click', function () {
  190. render(taskAry);
  191. $(this).addClass('selected').parent().siblings().find('a').removeClass('selected');
  192. })
  193. completed.on('click', function () {
  194. render(taskAry.filter(item => item.complete));
  195. $(this).addClass('selected').parent().siblings().find('a').removeClass('selected');
  196. })
  197. active.on('click', function () {
  198. render(taskAry.filter(item => !item.complete));
  199. $(this).addClass('selected').parent().siblings().find('a').removeClass('selected');
  200. })
  201. clearAll.on('click', function () {
  202. if(!confirm('你确认要删除全部已完成的任务吗'))return;
  203. $.ajax({
  204. url: '/todo/clearAll',
  205. success: (response => {
  206. if(response === 'ok') {
  207. taskAry = taskAry.filter(item => !item.complete);
  208. render(taskAry);
  209. }else {
  210. alert('操作失败');
  211. }
  212. })
  213. })
  214. })
  215. // 当页面有ajax请求的时候触发
  216. $(document).on('ajaxStart', function () {
  217. NProgress.start();
  218. })
  219. // 当页面有ajax请求完成时候触发
  220. $(document).on('ajaxComplete', function () {
  221. NProgress.done();
  222. })
  223. </script>
  224. </body>
  225. </html>