邁出全棧第一步,vue+node+mysql獨立完成先後端分離的增刪改查流程

寫在前面

本文只是本人學習過程的一個記錄,並非什麼很是嚴謹的教程,但願和你們一塊兒共同進步。也但願你們能指出個人問題。適合有必定基礎,志在全棧的前端初學者學習,從點擊按鈕提交ajax到得到服務器response,而後更新頁面,這其中到底發生了什麼?下面咱們就來實現一個小demo,之前後端分離的方式獨立跑通一個簡單的增刪改查流程,邁出全棧第一步。php

用到的一些技術棧html

  • 數據庫:mysql mysqlfront(數據庫gui工具)
  • 後端:node express mysqljs(node數據庫模塊)
  • 前端: vue(mvvm框架) elment-ui(快速搭建前端頁面) axios(ajax) webpack(構建工具)

後端負責提供接口,操做數據庫提供前端所需的數據和狀態。
前端負責調用接口,將數據展現給用戶,並對用戶的一些操做轉發給後端處理。
數據庫固然是負責存儲數據啦,關於數據庫,網上不少教程都是使用mongodb,經過mongoose操做mongdb的確比mysql便捷不少,不過實際工做中仍是使用mysql的多,技術仍是得迴歸實際應用才能體現出價值。前端

本demo使用node建立本地服務器,在localhost就能完成所有流程,並不須要線上服務器。雖然功能很是簡單,可是用的的模塊和工具仍是蠻多的,建議你們把注意力放在從前到後的這個流程上,一些工具和庫的使用我也不詳細介紹了,你們本身google,要成爲全棧這點學習能力仍是要有的。vue

項目結構

先上github倉庫地址node

項目結構

大體介紹下項目結構,先後端在不一樣的文件夾下面,互不影響。前端使用webpack構建,利用webpack-dev-server開發,前端入口是localhost:8888/dist/index.html。後端使用express框架,利用nodemon自動重啓,主機是localhost:9999。使用webpack-dev-server和express分別建立了兩個服務器,用同一個端口會衝突,so這裏會有跨域問題,不過用devserver能夠輕鬆解決,後面會說到具體解決辦法。若是是線上服務器的話放一個裏面就好了。mysql

先從前端開始

首先用vue-cli生成項目模板就好了,用webpack-simple就夠了,改相關配置方便點。webpack

咱們的頁面很簡單,主要有兩個組件list.vue(展現全部數據和相關操做),一個form.vue(新增及修改商品),這麼一個頁面各位前端估計啪啪幾下就搞定了吧,至於你用不用element-ui都無所謂,用的話速度快點顏值高點。你們請無視我項目裏使用的pug(jade)模板、餓了麼主題文件、登陸組件等,這只是爲了方便之後擴展。前端index.html用一個空殼就好了。ios

list
form

配置一下前端路由,/admin下有兩個子頁面,list和form,默認爲list(通常默認是個後臺概況頁)git

export default new Router({
    routes: [
        {
            path: '/admin',
            redirect: '/admin/list',
            name: 'admin',
            component: Admin,
            children: [
                {
                    path: '/admin/list',
                    name: 'list',
                    component: List,
                },
                {
                    path: '/admin/form',
                    name: 'form',
                    component: Form,
                },]
        },
    ]
});

靜態部分基本完成了,下面來編寫組件中的數據流轉邏輯程序員

列表的數據是從後端來的,因此list組件的created鉤子裏應有一個獲取所有數據的ajax。先不急着上,要用ajax的地方不少,那麼咱們先對ajax方法作一個封裝吧。

// pubulic/func.js

import axios from "axios";

export default {
    ajaxGet (api, cb) {
        axios.get(api)
            .then(cb)
            .catch(err => {
                console.log(err);
            })
    },
    ajaxPost (api, post, cb) {
        axios.post(api, post)
            .then(cb)
            .catch(err => {
                console.log(err);
            })
    },
}

這裏咱們使用的axios模塊來進行ajax請求,寫法是promise的鏈式操做,封裝一個get和一個post就夠用了。

// pubulic/api.js

let host = '/api';

export default {
    goodsList: host + '/goods-list',
    goodsDetail: host + '/goods-detail',
    goodsDelete: host + '/goods-delete',
    goodsAdd: host + '/goods-add',
}

一樣在public文件夾下建立一個api.js把全部的接口信息都寫在一塊兒,方便後續修改。路徑要與後端接口一致。

下面解決跨域問題,配置一下devserver.proxy就能輕鬆搞定,按照下面的配置,路徑以/api開頭的請求就會被node服務器轉發到9999端口,關於webpack的一些東西能夠看看個人另外一篇文章關於webpack的一點當心得

// webpack.config.js
// ...

devServer: {
    port: 8888,
    historyApiFallback: true,
    stats: 'minimal',  // 輸入精簡信息
    overlay: true, // 將錯誤顯示在html之上
    proxy: {
        '/api': {
            target: 'http://localhost:9999',
            secure: false,
            changeOrigin: true,
        }
    }
},

終於要進入組件中寫具體的業務邏輯了,咱們在created裏拿到數據,渲染進表格。雖而後端還沒開始呢,但咱們指望res.data是一個包含全部商品的數組(若是數據大了還要分頁哦),數據以後在後端中處理,實際項目中可使用mock模擬數據。

刪除操做把要刪除的商品id post至指定接口,而後在回調裏判斷返回的狀態,這個status應該是約定好的,我就設爲201是成功好了。後端返回成功後,前端數據中對應的元素也要刪掉,更新視圖。

// list.vue

import func from '../../public/func';
import api from '../../public/api';
// ...省略代碼若干行

methods: {
    // 刪除
    handleDelete(row) {
        func.ajaxPost(api.goodsDelete, {id: row.Id}, res => {
            if (res.status === 201) {
                let index = this.tableData.indexOf(row);
                this.tableData.splice(index, 1);
                this.$message.success('刪除成功');
            }
        });
    },

    // 修改
    handleEdit (row) {
        this.$router.push({name: 'form', query: {id: row.Id}});
    },
},

created () {
    func.ajaxGet(api.goodsList, res => {
        this.tableData = res.data;
    });
},

list頁的修改操做就是路由跳轉到form頁了,同時把id以query形式傳過去。在form的created鉤子裏判斷,若是有query.id的話就說明是在修改商品,沒有的話就是添加,這樣就能夠複用這個form組件咯。不愛偷懶的程序員不是好程序員。這個修改操做也能夠用vuex把商品數據傳遞過來,不過頁面刷新就沒有了,仍是用ajax穩妥。

// form.vue

// ...省略代碼若干行

created () {
    let id = this.$route.query.id;
    console.log(id);
    if (id) {
        func.ajaxPost(api.goodsDetail, {id}, res => {
            this.form = res.data;
        });
    }
},

其餘的一些操做不具體說了,都挺簡單的,讓咱們進入久違的後端吧。

建立數據庫

來到後端第一步就是建立一個數據庫,這裏我用的是phpstudy附帶的,固然你也能夠本身裝,畢竟這個附帶的仍是老舊的5.5版本。sql語句我玩不來啊就用phpstudy附帶的mysqlfront這個gui工具來擼了。建一個叫vue-admin的庫,而後一張goods的表,只有id,name,price,create_time這四個字段,簡單明瞭。
mysql

編寫後端接口

終於玩到node了,首先全局安裝nodemon幫咱們自動重啓,而後裝好express等包,新手不推薦使用express-generator建立項目。看到這裏請你們先去預習一下mysqljs這個模塊。

咱們把數據庫的配置寫在單獨的文件中,抽離配置文件是一個好習慣。而後在控制器中使用mysql.createPool(db)建立鏈接池。

// db.js

module.exports = {
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: 'root',
    database: 'vue-admin'
};

// controls/goods.js

let pool = mysql.createPool(db);

下面編寫增刪改查等路由接口,與前端的api.js中的路徑保持一致,get仍是post根據狀況而定,回調函數不寫在這裏寫進控制器goods.js中。在入口文件中use router,這時候咱們的接口路徑就是/api/goods-list

// router.js

router.get('/goods-list', goods.getGoodsList);
router.post('/goods-detail', goods.getOneGoods);
router.post('/goods-add', goods.addGoods);
router.post('/goods-delete', goods.deleteGoods);

module.exports = router;

// app.js

let router = require('./routes/router');
app.use('/api', router);

控制器中一樣是增刪改查四個方法,首先咱們把一些可複用的sql語句封裝起來。這是mysqljs中的語法,?就是變量,雙??是表名或字段名,單?則爲value。insert和update就不封裝了,涉及到具體字段,直接寫好了。

// sql.js

module.exports = {
    queryAll: 'SELECT * FROM ??',
    queryById: 'SELECT * FROM ?? WHERE id=?',
    del: 'DELETE FROM ?? WHERE id=?',
};

控制器裏拿一個方法出來講一下吧,完整的代碼都在github。使用pool.getConnection方法從鏈接池創建鏈接,SELECT * FROM goods獲取goods表中全部數據,res.json將數據以json格式傳給前端。讀取操做完成後調用release()釋放鏈接。rows及前端拿到的res的數據格式你們能夠console看一下,都是數組類型。

// 獲取商品列表
    getGoodsList (req, res) {
    pool.getConnection((err, conn) => {
        conn.query(sql.queryAll, 'goods', (err, rows) => {
            if (err) throw err;

            rows = formatDate(rows);
            res.json(rows);

            conn.release();
        });
    });
},

// formatDate函數利用moment.js將數據庫中的時間戳格式轉化爲年月日的格式
function formatDate(rows) {
    return rows.map(row => {
        let date = moment(row.create_time).format('YYYY-MM-DD');
        return Object.assign({}, row, {create_time: date});
    });
}

寫後端接口的時候還跑去前端提交請求比較蛋疼,這裏推薦你們使用postman這個工具來測試接口,提升效率。postman能夠以chrome插件的形式安裝,十分方便。

postman

後端接口跑通後,先後端協調修改一下,從前端調用接口,到後端從數據庫中讀取數據,最後返回給前端,整個流程至此就跑通了。

全棧之路修遠兮

咱們只是完成了一個web應用最最基本的功能,新手可能一臉懵逼,大牛可能一臉蔑視,全棧之路還遠着呢。接下來須要去增長登陸等模塊,更復雜的業務邏輯,還有安全方面的考慮,讓程序健壯起來,你們一塊兒加油吧。

相關文章
相關標籤/搜索