手把手教你用express + mysql + knex 做个 todoList

成果展示

项目源代码地址见git,在routes下找todolist
这里写图片描述

启动mysql,用knex连接数据

终端运行

mysql.server start

看到“starting mysql SUCCESS!”,把服务启动起来后,再新开一个终端窗口,用root登录

mysql -u root  //  显示welcome to the MySQL monitor
show databases   
use example   //例子中用到了example这个database

knex是一个npm包,用于node.js下连接mysql

连接mysql

var knex = require('knex')({
    client:'mysql',
    connection:{
        host:'localhost',
        user: 'root',
        password: '',
        database: 'example'
    }
})

接口功能拆分

建表:创建任务列表

function createToDoList() {
    return 
    knex.schema
    .hasTable('todolist')
    .then( ifExist => {
        if(!ifExist){
            return knex.schema.createTable('todolist', (table) =>{
                table.increments('task_id').primary()
                table.string('task_name').notNullable()
                table.integer('task_status').notNullable().defaultTo(0)
                table.dateTime('task_start_date')
                table.dateTime('task_end_date')
            })
        }
    })  
    .catch( err => {
        console.log('error !!!', err.message, err.stack)
        return
    })
}

查询任务列表

状态分为0(未完成)和1(已经完成),分别保存在两个数组里。

async function getTasks(){
    var toDoTasks = await knex('todolist').select().where('task_status', 0)
    var finishedTasks = await knex('todolist').select().where('task_status', 1)
    return {toDoTasks, finishedTasks}
}

添加任务

function addTask(content){
    return knex('todolist').insert({
        task_name: content,
        task_start_date: new Date(),
    }).then( (task_id) => {
        return knex('todolist').select().where('task_id', task_id)
    }).then( newtask =>{
        return newtask
    })
    .catch(err => {
        throw err
    })
}
// 测试一下
//addTask('learn knex api ')
//addTask('finish eg.js').then( (task_id) => {console.log('from addTask', task_id)})

删除任务

function deleteTask(task_id){
    return knex('todolist').where('task_id', task_id).del()
                    .then( deleteRowNum => {            
                        return deleteRowNum
                    })
                    .catch(err => {
                        throw err
                    })
}

//deleteTask(1)

修改任务内容


function editTask(taskobj){
    return knex('todolist').where('task_id', taskobj.task_id)
                    .update('task_name', taskobj.task_name)
                    .then( editRowNum => {
                        return editRowNum
                    })
                    .catch(err => {
                        throw err
                    })
}

// editTask({
//  task_id: 1,
//  task_name: 'wanna eat dinner'
// })

把任务设为已完成/恢复任务为未完成

function checkTask(taskobj){
    var dateobj = +taskobj.task_status? {} : {task_end_date: new Date()}
    var updateobj = Object.assign({}, {task_status :taskobj.task_status? 0 : 1}, dateobj)
    return knex('todolist')
           .where('task_id', taskobj.task_id)
                 .update(updateobj)
                 .then( editRowNum => {
                        return editRowNum
                    })
                 .catch(err => {
                        throw err
                    })
}

然后配一下controller,让路由去到正确的操作。我是整体配在/taskapi下面的,再分到每一个具体的api。以getTasks和addTask为例:

const {createToDoList, getTasks, addTask, deleteTask, editTask, checkTask } = require('../models/tasks')

const express = require('express');

const router = express.Router();

router.get('/getTasks',  (req, res, next) => {

    getTasks().then( tasks => {

        res.send(tasks)

    }).catch(err => {

        throw err
    })

})

router.post('/addTask', (req, res) => {

    addTask(req.body['task_name'])

            .then( newtasks =>{

                res.send(newtasks[0])
            })
            .catch(err => {

                throw err
            })  
})

前端展示:vue+bootstrap

express的view engine 设的是ejs,对应views下的 todolist.ejs 引入vue和bootstrap等文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title><%= title %>- Demo</title>
    <link rel='stylesheet' href='/lib/bootstrap/dist/css/bootstrap.min.css' />
    <link rel='stylesheet' href='/stylesheets/todolist.css' />
    <script type="text/javascript" src='/lib/vue/dist/vue.min.js'></script>
  </head>

要使src顺利引入,还需要配一下static的路径。

app.use('/lib', express.static('whereYourNodeModulesFolderAre/orResourcesInOtherPlace')) //

以下是todolist.ejs 的 主体部分,直接写vue 就可以了,就该怎么写怎么写呗~~

<div class="container root">
  <h3>to do list</h3>
  <aside>点击要做的事项,即可编辑</aside>
  <ul>
    <li is='to-do-item' v-for="(task,taskIndex ) in toDoTasks" :key="task.task_id"
    :task=task
    @remove='toDoTasks.splice(taskIndex, 1)'
    ></li>
    <div class="input-group mb-3">
      <input class="form-control" v-model='newTaskName' @keyup.enter='addNewToDo' placeholder='回车键添加新任务' />
    </div>
  </ul>
  <h3>finished tasks</h3>
  <ol v-if='finishedTasks.length' class='listgroup'>
    <li v-for='task in finishedTasks' :key='task.task_id' class="list-group-item">{{task.task_name}}</li>
  </ol>
  <hr />
  <footer>
    <p><a href="https://blog.csdn.net/github_36487770" target="_blank">十方魔</a> 2018</p>
  </footer>
</div>

发送ajax就跟正常一样就行了

addNewToDo(){
            const _task_name = this.newTaskName.trim()
            if(!_task_name){
                alert('任务不能为空')
                return
            }
            $.post('/taskapi/addTask', {task_name: _task_name}, (newtask) => {
                this.toDoTasks.push(newtask)
                this.newTaskName = ''
            })
}

All Done:一点想法

羞愧地说,这都是一个多月前做的了,不管当时有什么想法,现在都不记得了。

猜你喜欢

转载自blog.csdn.net/github_36487770/article/details/80406834