摘要:本使用創(chuàng)建本地服務(wù)器,在就能完成全部流程,并不需要線上服務(wù)器。路徑要與后端接口一致。后端返回成功后,前端數(shù)據(jù)中對(duì)應(yīng)的元素也要?jiǎng)h掉,更新視圖。控制器里拿一個(gè)方法出來說一下吧,完整的代碼都在。讀取操作完成后調(diào)用釋放連接。
寫在前面
本文只是本人學(xué)習(xí)過程的一個(gè)記錄,并不是什么非常嚴(yán)謹(jǐn)?shù)慕坛蹋M痛蠹乙黄鸸餐M(jìn)步。也希望大家能指出我的問題。適合有一定基礎(chǔ),志在全棧的前端初學(xué)者學(xué)習(xí),從點(diǎn)擊按鈕提交ajax到獲得服務(wù)器response,然后更新頁(yè)面,這其中到底發(fā)生了什么?下面我們就來實(shí)現(xiàn)一個(gè)小demo,以前后端分離的方式獨(dú)立跑通一個(gè)簡(jiǎn)單的增刪改查流程,邁出全棧第一步。
用到的一些技術(shù)棧
數(shù)據(jù)庫(kù):mysql mysqlfront(數(shù)據(jù)庫(kù)gui工具)
后端:node express mysqljs(node數(shù)據(jù)庫(kù)模塊)
前端: vue(mvvm框架) elment-ui(快速搭建前端頁(yè)面) axios(ajax) webpack(構(gòu)建工具)
后端負(fù)責(zé)提供接口,操作數(shù)據(jù)庫(kù)提供前端所需的數(shù)據(jù)和狀態(tài)。
前端負(fù)責(zé)調(diào)用接口,將數(shù)據(jù)展示給用戶,并對(duì)用戶的一些操作轉(zhuǎn)發(fā)給后端處理。
數(shù)據(jù)庫(kù)當(dāng)然是負(fù)責(zé)存儲(chǔ)數(shù)據(jù)啦,關(guān)于數(shù)據(jù)庫(kù),網(wǎng)上很多教程都是使用mongodb,通過mongoose操作mongdb的確比mysql便捷很多,不過實(shí)際工作中還是使用mysql的多,技術(shù)還是得回歸實(shí)際應(yīng)用才能體現(xiàn)出價(jià)值。
本demo使用node創(chuàng)建本地服務(wù)器,在localhost就能完成全部流程,并不需要線上服務(wù)器。雖然功能非常簡(jiǎn)單,但是用的的模塊和工具還是蠻多的,建議大家把注意力放在從前到后的這個(gè)流程上,一些工具和庫(kù)的使用我也不詳細(xì)介紹了,大家自己google,要成為全棧這點(diǎn)學(xué)習(xí)能力還是要有的。
項(xiàng)目結(jié)構(gòu)先上github倉(cāng)庫(kù)地址吧
大致介紹下項(xiàng)目結(jié)構(gòu),前后端在不同的文件夾下面,互不影響。前端使用webpack構(gòu)建,利用webpack-dev-server開發(fā),前端入口是localhost:8888/dist/index.html。后端使用express框架,利用nodemon自動(dòng)重啟,主機(jī)是localhost:9999。使用webpack-dev-server和express分別創(chuàng)建了兩個(gè)服務(wù)器,用同一個(gè)端口會(huì)沖突,so這里會(huì)有跨域問題,不過用devserver可以輕松解決,后面會(huì)說到具體解決辦法。如果是線上服務(wù)器的話放一個(gè)里面就行了。
先從前端開始首先用vue-cli生成項(xiàng)目模板就行了,用webpack-simple就夠了,改相關(guān)配置方便點(diǎn)。
我們的頁(yè)面很簡(jiǎn)單,主要有兩個(gè)組件list.vue(展示所有數(shù)據(jù)和相關(guān)操作),一個(gè)form.vue(新增及修改商品),這么一個(gè)頁(yè)面各位前端估計(jì)啪啪幾下就搞定了吧,至于你用不用element-ui都無(wú)所謂,用的話速度快點(diǎn)顏值高點(diǎn)。大家請(qǐng)無(wú)視我項(xiàng)目里使用的pug(jade)模板、餓了么主題文件、登錄組件等,這只是為了方便以后擴(kuò)展。前端index.html用一個(gè)空殼就行了。
配置一下前端路由,/admin下有兩個(gè)子頁(yè)面,list和form,默認(rèn)為list(一般默認(rèn)是個(gè)后臺(tái)概況頁(yè))
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, },] }, ] });
靜態(tài)部分基本完成了,下面來編寫組件中的數(shù)據(jù)流轉(zhuǎn)邏輯
列表的數(shù)據(jù)是從后端來的,所以list組件的created鉤子里應(yīng)有一個(gè)獲取全部數(shù)據(jù)的ajax。先不急著上,要用ajax的地方很多,那么我們先對(duì)ajax方法做一個(gè)封裝吧。
// 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模塊來進(jìn)行ajax請(qǐng)求,寫法是promise的鏈?zhǔn)讲僮?,封裝一個(gè)get和一個(gè)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文件夾下創(chuàng)建一個(gè)api.js把所有的接口信息都寫在一起,方便后續(xù)修改。路徑要與后端接口一致。
下面解決跨域問題,配置一下devserver.proxy就能輕松搞定,按照下面的配置,路徑以/api開頭的請(qǐng)求就會(huì)被node服務(wù)器轉(zhuǎn)發(fā)到9999端口,關(guān)于webpack的一些東西可以看看我的另一篇文章關(guān)于webpack的一點(diǎn)小心得
// webpack.config.js // ... devServer: { port: 8888, historyApiFallback: true, stats: "minimal", // 輸入精簡(jiǎn)信息 overlay: true, // 將錯(cuò)誤顯示在html之上 proxy: { "/api": { target: "http://localhost:9999", secure: false, changeOrigin: true, } } },
終于要進(jìn)入組件中寫具體的業(yè)務(wù)邏輯了,我們?cè)赾reated里拿到數(shù)據(jù),渲染進(jìn)表格。雖然后端還沒開始呢,但我們期望res.data是一個(gè)包含所有商品的數(shù)組(如果數(shù)據(jù)大了還要分頁(yè)哦),數(shù)據(jù)之后在后端中處理,實(shí)際項(xiàng)目中可以使用mock模擬數(shù)據(jù)。
刪除操作把要?jiǎng)h除的商品id post至指定接口,然后在回調(diào)里判斷返回的狀態(tài),這個(gè)status應(yīng)該是約定好的,我就設(shè)為201是成功好了。后端返回成功后,前端數(shù)據(jù)中對(duì)應(yīng)的元素也要?jiǎng)h掉,更新視圖。
// 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頁(yè)的修改操作就是路由跳轉(zhuǎn)到form頁(yè)了,同時(shí)把id以query形式傳過去。在form的created鉤子里判斷,如果有query.id的話就說明是在修改商品,沒有的話就是添加,這樣就可以復(fù)用這個(gè)form組件咯。不愛偷懶的程序員不是好程序員。這個(gè)修改操作也可以用vuex把商品數(shù)據(jù)傳遞過來,不過頁(yè)面刷新就沒有了,還是用ajax穩(wěn)妥。
// form.vue // ...省略代碼若干行 created () { let id = this.$route.query.id; console.log(id); if (id) { func.ajaxPost(api.goodsDetail, {id}, res => { this.form = res.data; }); } },
其他的一些操作不具體說了,都挺簡(jiǎn)單的,讓我們進(jìn)入久違的后端吧。
創(chuàng)建數(shù)據(jù)庫(kù)來到后端第一步就是創(chuàng)建一個(gè)數(shù)據(jù)庫(kù),這里我用的是phpstudy附帶的,當(dāng)然你也可以自己裝,畢竟這個(gè)附帶的還是老舊的5.5版本。sql語(yǔ)句我玩不來啊就用phpstudy附帶的mysqlfront這個(gè)gui工具來擼了。建一個(gè)叫vue-admin的庫(kù),然后一張goods的表,只有id,name,price,create_time這四個(gè)字段,簡(jiǎn)單明了。
終于玩到node了,首先全局安裝nodemon幫我們自動(dòng)重啟,然后裝好express等包,新手不推薦使用express-generator創(chuàng)建項(xiàng)目。看到這里請(qǐng)大家先去預(yù)習(xí)一下mysqljs這個(gè)模塊。
我們把數(shù)據(jù)庫(kù)的配置寫在多帶帶的文件中,抽離配置文件是一個(gè)好習(xí)慣。然后在控制器中使用mysql.createPool(db)創(chuàng)建連接池。
// 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根據(jù)情況而定,回調(diào)函數(shù)不寫在這里寫進(jìn)控制器goods.js中。在入口文件中use router,這時(shí)候我們的接口路徑就是/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);
控制器中同樣是增刪改查四個(gè)方法,首先我們把一些可復(fù)用的sql語(yǔ)句封裝起來。這是mysqljs中的語(yǔ)法,?就是變量,雙??是表名或字段名,單?則為value。insert和update就不封裝了,涉及到具體字段,直接寫好了。
// sql.js module.exports = { queryAll: "SELECT * FROM ??", queryById: "SELECT * FROM ?? WHERE id=?", del: "DELETE FROM ?? WHERE id=?", };
控制器里拿一個(gè)方法出來說一下吧,完整的代碼都在github。使用pool.getConnection方法從連接池建立連接,SELECT * FROM goods獲取goods表中所有數(shù)據(jù),res.json將數(shù)據(jù)以json格式傳給前端。讀取操作完成后調(diào)用release()釋放連接。rows及前端拿到的res的數(shù)據(jù)格式大家可以console看一下,都是數(shù)組類型。
// 獲取商品列表 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函數(shù)利用moment.js將數(shù)據(jù)庫(kù)中的時(shí)間戳格式轉(zhuǎn)化為年月日的格式 function formatDate(rows) { return rows.map(row => { let date = moment(row.create_time).format("YYYY-MM-DD"); return Object.assign({}, row, {create_time: date}); }); }
寫后端接口的時(shí)候還跑去前端提交請(qǐng)求比較蛋疼,這里推薦大家使用postman這個(gè)工具來測(cè)試接口,提高效率。postman可以以chrome插件的形式安裝,十分方便。
后端接口跑通后,前后端協(xié)調(diào)修改一下,從前端調(diào)用接口,到后端從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),最后返回給前端,整個(gè)流程至此就跑通了。
全棧之路修遠(yuǎn)兮我們只是完成了一個(gè)web應(yīng)用最最基本的功能,新手可能一臉懵逼,大??赡芤荒樏镆?,全棧之路還遠(yuǎn)著呢。接下來需要去增加登錄等模塊,更復(fù)雜的業(yè)務(wù)邏輯,還有安全方面的考慮,讓程序健壯起來,大家一起加油吧。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82765.html
摘要:表示需要攔截的請(qǐng)求類型。表示數(shù)據(jù)模板,可以是對(duì)象或字符串。表示用于生成響應(yīng)數(shù)據(jù)的函數(shù)。指向本次請(qǐng)求的選項(xiàng)集。生成規(guī)則是可選的。返回成功的數(shù)據(jù),就是登錄成功了,否則相反。模擬登錄接下來介紹模擬表格增刪改查。 前言 關(guān)于mockjs,官網(wǎng)描述的是 1.前后端分離 2.不需要修改既有代碼,就可以攔截 Ajax 請(qǐng)求,返回模擬的響應(yīng)數(shù)據(jù)。 3.數(shù)據(jù)類型豐富 4.通過隨機(jī)數(shù)據(jù),模擬各種場(chǎng)景。 5...
摘要:我所在的美團(tuán)酒店事業(yè)部去年月份成立,新的業(yè)務(wù)新的開發(fā)團(tuán)隊(duì),這一切使得我們的前后端分離推進(jìn)的很徹底。日志監(jiān)控平臺(tái)日志監(jiān)控平臺(tái)是美團(tuán)內(nèi)部的一個(gè)日志收集系統(tǒng),目前美團(tuán)統(tǒng)一使用收集日志,具有接收格式日志的能力,而日志監(jiān)控平臺(tái)也是以格式日志來收集。 轉(zhuǎn)自:美團(tuán)技術(shù)團(tuán)隊(duì) 作者:美團(tuán)技術(shù)團(tuán)隊(duì) 分享理由:很好的分享,可見,基于Node的前后端分離的架構(gòu)是越顯流行和重要,前端攻城獅們,No...
閱讀 3357·2021-11-25 09:43
閱讀 3045·2021-10-15 09:43
閱讀 1997·2021-09-08 09:36
閱讀 2957·2019-08-30 15:56
閱讀 776·2019-08-30 15:54
閱讀 2714·2019-08-30 15:54
閱讀 3008·2019-08-30 11:26
閱讀 1286·2019-08-29 17:27