手把手教你用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:一點想法

羞愧地說,這都是一個多月前做的了,不管當時有什麼想法,現在都不記得了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章