一、环境搭建
在coding之前,我们先把环境搭好,包括数据库的安装配置以及thinkjs的安装配置。
1、数据库安装
本项目使用关系型数据库MySQL,电脑上没有安装上MySQL的同学可以自行上官网下载安装,有关MySQL的知识可以上菜鸟教程和慕课网学习,这里不多说。
2、ThinkJS安装
这里我们使用ThinkJS 2.2版本,所以以下步骤都是针对2.2版本,想使用3.0版本的同学可以自行尝试。可直接使用npm进行安装,参考官方文档。安装完成后即可创建项目。
3、模版引擎安装
使用thinkjs命令创建好项目好,通过npm install安装依赖项,然后可以安装模版引擎,这里以nunjucks为例,安装命令如下:
npm install nunjucks --save
二、项目配置
主要进行两项配置,一是数据库配置,二是模版引擎配置。
1、数据库配置
配置文件db.js所在目录如下图(2.2版本):
配置代码如下图:
2、模版引擎的配置
配置文件view.js所在目录如下图(2.2版本):
nunjucks配置代码如下图:
三、数据表创建
项目的开始我们要设计数据表,我们可以只创建一个表think_tododemo,它包含三个键,参考代码如下:
CREATE TABLE IF NOT EXISTS `think_tododemo`( `id` INT UNSIGNED AUTO_INCREMENT, `title` VARCHAR(100) NOT NULL, `done` INT UNSIGNED NOT NULL, PRIMARY KEY ( `id` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8;
其中id用作编号,title为每项事务的内容,done表示是否已经完成(0表示正在进行,1表示已经完成)。当然你可以设计不同的数据表。
四、后端接口设计
由于我们要实现的todolist是单页应用,所以只需要一个控制器,在里面实现相应的接口方法即可。
1、home/index/indexAction
首先,我们实现home模块中index控制器的indexAction方法,参考代码如下:
async indexAction(){ let model = this.model('tododemo'); //查询正在进行的待办项数据 let todoData = await model.where({done: 0}).select(); //查询已经完成的待办项数据 let doneData = await model.where({done: 1}).select(); //变量赋值,传递给view this.assign('todoList', todoData); this.assign('doneList', doneData); this.assign('todoCount', todoData.length); this.assign('doneCount', doneData.length); return this.display(); }
这样访问这个控制器方法就可以把数据库中的数据赋值到变量中,并且渲染view中对应的index_index.html。
2、home/index/addAction
然后我们实现addAction这个方法,用于添加新的待办项,参考代码如下:
async addAction(){ let model = this.model('tododemo'); if(this.isPost()){ let item = this.post('title'); let insertItem = await model.add({ title: item, done: 0 }); if(!insertItem){ return this.fail(1000, '添加待办项失败!'); } else{ return this.success(); } } else { return this.fail(2000, 'post传递参数不存在!'); } }
当待办项被正确添加到数据库中,可以通过this.success(data)返回数据,否则可以通过this.fail(errno, errmsg)返回错误提示。
其他需要实现的方法包括updateAction、removeAction、clearAction等等,请同学们自行实现。
五、前端结构设计
在view目录中,我们实现HTML的结构设计,即home模块下的index_index.html。在完成这一步之前,需要先学习一下模版引擎,比如我们这里要用到nunjucks。参考代码如下:
DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ToDoListtitle>
<link rel="stylesheet" type="text/css" href="/static/css/index.css">
<script type="text/javascript" src="http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js">script>
head>
<body>
<header>
<form action="javascript:add()" method="POST">
<label for="title">ToDoListlabel>
<button id="btn" class="btn" type="submit">提交button>
<input type="text" id="title" name="title" placeholder="添加ToDo">
form>
header>
<section>
<h2>正在进行
<span id="todocount">
{{ todoCount }}
span>
h2>
<ol id="todolist" class="list">
{% for item in todoList %}
<li>
<input type="checkbox" onchange="update({{ item.id }}, 1)" />
<p id="p-{{item.id}}" onclick="edit({{ item.id }})">{{ item.title }}p>
<a href="javascript:remove({{ item.id }})">-a>
li>
{% endfor %}
ol>
<h2>已经完成
<span id="donecount">
{{ todoCount }}
span>
h2>
<ul id="donelist" class="list">
{% for item in doneList %}
<li>
<input type="checkbox" onchange="update({{ item.id }}, 0)" />
<p id="p-{{item.id}}" onclick="edit({{ item.id }})">{{ item.title }}p>
<a href="javascript:remove({{ item.id }})">-a>
li>
{% endfor %}
ul>
section>
<footer>Copyright © 2017
<a href="javascript:clear()">cleara>
footer>
<script type="text/javascript" src="/static/js/index.js">script>
body>
html>
这里要注意css和js文件的存放位置以及引用路径,而且这里用到了jQuery,所以同时需要引用jQuery。同学们可以自行添加不同的css样式。
六、前端JavaScript方法设计
前端js文件存放在www/static/js目录下(2.2版本),我们要实现其中的方法,比如添加待办项的add方法,参考代码如下:
function add(){ var title = document.querySelector("#title"); if(title.value == ""){ alert("内容不能为空"); } else{ var item = title.value; $.ajax({ url: '/home/index/add', type: 'POST', dataType: 'json', data: { title: item }, success: res => { if(!res.errno) { window.location.reload(); } else alert(res.errmsg); } }); } }
在参考代码中,实际上只有当后端返回成功提示时,页面才会刷新显示新添加的数据,这并不是一种良好的交互设计,所以可想办法使得提交新待办项后前端页面可以及时更新而不用等后端响应。
这里只实现了add方法,其他方法请自行实现。
七、拓展功能
除了上述功能外,可以按照自己的想法实现一些新功能,比如正在进行的列表项可以拖拽改变它们的顺序。