准備工作
1.vscoude
2.node
3.mongodb
4.express
node安裝及使用
node的安裝參考: https://www.cnblogs.com/moluxi/p/13025592.html
mongo安裝以及使用
mongo的安裝參考:https://www.cnblogs.com/moluxi/p/13027549.html
express相關
express: https://www.expressjs.com.cn/
注
這種語句是在命令行運行的
構建項目
1.首先對自己安裝的node版本進行測試,8.0以下版本不能使用項目的相關模塊
node -v
如果版本過低,http://nodejs.cn/download/ 下載新的版本(windows:控制面板-程序-node-卸載)
2.使用國內的淘寶鏡像源(下載的速度會快些)
測試淘寶的鏡像源
cnpm -v
如果報錯 不是內部或者外部命令說明沒有安裝,需要安裝一下
npm install -g cnpm --registry=https://registry.npm.taobao.org
3.安裝項目腳手架(用express)
https://www.expressjs.com.cn/starter/generator.html
全局安裝espress
cnpm i express-generator -g
express --help
創建項目
利用express快速生成項目框架
express myapp --view=ejs //myapp為你的項目名
進入生成的項目目錄下
cd myapp
安裝所需依賴
cnpm i
運行項目
cnpm run start
express項目目錄理解
- myapp
- bin
www --- 設置了服務器的端口號,默認為3000,可以隨意更改3000/ 4200/8080/8000/9000
- public---靜態的資源目錄,存放css,js,網頁,圖片,可以直接通http://localhost:3000/images/1.jpg
- images
- javascripts
- stylesheets
- routes --- 定義路由 /login
index.js
users.js
- views --- 各個頁面,后綴名不再是html
error.ejs
index.ejs
app.js --- 服務器的准備
package.json --- 項目的描述文件,為什么可以使用cnpm run start 啟動項目
准備一個后台管理系統的模板(這里用admin-let)
首先復制admin-lte模版中的starter.html的內容
復制到 myapp/views/index.ejs、觀察 head部分 查看引入的css的路徑,找到需要的css文件夾bootsrtap + dist + font-awesome + Ionicons將這幾個文件夾復制到 myapp/public 修改index.ejs的路徑,以 / 開頭, 此 / 其實可以看作就是public的目錄、同理,引入相關的js文件。
抽離頁面結構
仔細觀察代碼可以看出,index.ejs頁面結構可以分為四個部分,分別將不同的部分存放在不同的文件夾中
頭部 header.ejs
菜單 menu.ejs
底部 footer.ejs
右側 sideBar.ejs
保留內容部分
將各個部分使用ejs模板語法添加到頁面
-
語法:<%%>
-
<% js的語句(for / if ) %>
-
<%- val %> ---- 解析輸出
-
<%= val %> ---- 轉義輸出
添加頭部的頁面
<%- include('./header.ejs') %>
這樣一來我們就能把頁面重組回去,在更多類似的頁面要使用時比較方便
myapp/views/index.ejs
<div class="wrapper">
<%- include('./header.ejs') %>
<%- include('./menu.ejs') %>
<div class="content-wrapper"></div>
<%- include('./footer.ejs') %>
<%- include('./sideBar.ejs') %>
</div>
設計左側菜單欄
我們准備在側邊欄設置以下為幾種功能的管理 首頁 、輪播圖管理、 商品管理 、用戶管理
購物車管理 、訂單管理 、活動管理 、消息管理
<!-- Sidebar Menu -->
<ul class="sidebar-menu" data-widget="tree">
<li class="header">HEADER</li>
<!-- 在這里先定義一些要使用的數據 -->
<% var arr = [
{ title: '首頁',icon: '', path: ''},
{ title: '輪播圖管理',icon: '', path: ''},
{ title: '商品管理',icon: '', path: ''},
{ title: '用戶管理',icon: '', path: ''},
{ title: '購物車管理',icon: '', path: ''},
{ title: '訂單管理',icon: '', path: ''},
{ title: '活動管理',icon: '', path: ''},
{ title: '消息管理',icon: '', path: ''}
] %>
<!-- 循環將各個標題的內容添加到頁面的li中 -->
<% for(var i = 0; i < arr.length; i++) { %>
<li class="active"><a href="#"><i class="fa fa-link"></i> <span>
<%- arr[i].title %>
</span></a></li>
<% } %>
</ul>
<!-- /.sidebar-menu -->
這個時候我們已經有了很多選項卡可以操作啦,但是還沒有任何的功能,由於我們做的是后端的管理系統用ajax局部刷新會對用戶不太友好,我們可以直接把每個選項卡寫一個頁面,使頁面跳轉更加精致
我們可以復制index頁面,並修改文件名和關鍵字從而得到每個選項卡所要對應的頁面
index.ejs banner.ejs product.ejs users.ejs cart.ejs order.ejs activity.ejs message.ejs
創建各個頁面對應的路由
有了頁面,要想讓頁面有交互效果,我們就拍給他配置相應的路由在outes文件夾下新建與rviews相對應的js文件,像下面這種形式
routes views
activity.js activity.ejs
banner.js banner.ejs
....
在剛剛建好的這些js文件中配置"/"的當前路由
router.get('/', function(req, res, next) {
// 如果用戶訪問 / 返回index.ejs頁面,並且返回變量title
res.render('index', { title: '1' }); //tiele用來表明是哪個選項卡
});
使各個路由生效
頁面有了,路由也有了,下面我們就要讓我們的路由生效啦
在app.js中引入路由文件並設置
//根據上下文寫到相對應的位置就可以啦
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var productRouter = require('./routes/product'); // +++
var cartRouter = require('./routes/cart'); // +++
var bannerRouter = require('./routes/banner'); // +++
var orderRouter = require('./routes/order'); // +++
var activityRouter = require('./routes/activity'); // +++
var messageRouter = require('./routes/message'); // +++
...
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/activity', activityRouter); // +++
app.use('/banner', bannerRouter); // +++
app.use('/product', productRouter); // +++
app.use('/cart', cartRouter); // +++
app.use('/order', orderRouter); // +++
app.use('/message', messageRouter); // +++
左側菜單添加 鏈接
依次添加所有頁面相應選項卡的連接,這樣當你點擊的時候才能跳轉到你想要的頁面
高亮選中左側菜單欄
要想讓點擊的選項卡高亮顯示就要告訴他什么時候應該高亮,此時我們可以在頁面加載的時候通過路由給頁面傳來一個數據,來說明當前頁面是哪個頁面,當點擊一個頁面的選項卡的時候跳轉到該頁面之后可以通過傳來的值告訴頁面此時哪個選項啊改高亮了
大題語法是這樣的
res.render('activity', { index: 順序(從0開始,注意和menu對應) });
在剛剛生成側邊欄nav的循環中通過傳來的index值來判斷是否高亮,判斷是否高亮的代碼
<% for(var i = 0; i < arr.length; i++) { %>
<li class="<%- index === i ? 'active' : ''%>"><a href="<%- arr[i].path %>"><i class="fa fa-link"></i> <span>
<%- arr[i].title %>
</span></a></li>
<% } %>
為商品添加數據表格
現在我們開始給頁面添加內容,應為是后台管理系統,所以以數據表格的形勢在頁面顯示更加直觀,我們可以在我們的模板 - 表格 - 數據表格 中找到總計中意的表格,右鍵- 審查元素 - 右鍵 - copy - copy outerhtml,賦值好后粘貼到views/product.ejs (放在| Your Page Content Here |這段注釋之后),刪除不需要的數據。我們商品管理頁面的數據表格就完成了
點擊添加產品 進入 添加產品的頁面
有了表格之后我們還需要數據才算算得上是管理,所以我們需要一個添加商品的功能
新建頁面views/product_add.ejs,和之前一樣后頁面要請求數據就要設置路由,因為是product的子頁面,所以我們只需要配置二級路由就可以啊
routes/product.js
router.get('/', function(req, res, next) {
res.render('product', { index: 2 });
});
// +++++++++++++++
router.get('/add', function(req, res, next) {
res.render('product_add', { index: 2 })
})
點擊按鈕跳轉到添加頁面
product.ejs
<a href="/product/add"> <button type="button" class="btn btn-block btn-info btn-lg">添加產品</button> </a>
設計商品屬性
要添加數據我們總要知道我們要添加什么樣的數據吧,所以現在我們要對產品的屬性進行設置
為此我們可以做一個excel表格用來批量導入數據
設計產品表單
<div class="box-header with-border"> <h3 class="box-title">Horizontal Form</h3> </div> <!-- /.box-header --> <!-- form start --> <form class="form-horizontal" action="/product/addAction" method="POST"> <div class="box-body"> <div class="form-group"> <label for="proname" class="col-sm-2 control-label">產品名稱</label> <div class="col-sm-10"> <input type="text" class="form-control" name="proname" id="proname" placeholder="產品名稱"> </div> </div> <div class="form-group"> <label for="probrand" class="col-sm-2 control-label">產品品牌</label> <div class="col-sm-10"> <input type="text" class="form-control" name="probrand" id="probrand" placeholder="產品品牌"> </div> </div> <div class="form-group"> <label for="brandimg" class="col-sm-2 control-label">logo地址</label> <div class="col-sm-10"> <input type="text" class="form-control" name="brandimg" id="brandimg" placeholder="logo地址"> </div> </div> <div class="form-group"> <label for="porimg" class="col-sm-2 control-label">產品圖片</label> <div class="col-sm-10"> <input type="text" class="form-control" name="proimg" id="proimg" placeholder="產品圖片"> </div> </div> <div class="form-group"> <label for="price" class="col-sm-2 control-label">價格</label> <div class="col-sm-10"> <input type="text" class="form-control" name="price" id="price" placeholder="價格"> </div> </div> <div class="form-group"> <label for="stock" class="col-sm-2 control-label">庫存</label> <div class="col-sm-10"> <input type="text" class="form-control" name='stock' id="stock" placeholder="庫存"> </div> </div> <div class="form-group"> <label for="sales" class="col-sm-2 control-label">銷量</label> <div class="col-sm-10"> <input type="text" class="form-control" name="sales" id="sales" placeholder="銷量"> </div> </div> <div class="form-group"> <label for="detail" class="col-sm-2 control-label">詳情</label> <div class="col-sm-10"> <input type="text" class="form-control" name="detail" id="detail" placeholder="詳情"> </div> </div> </div> <!-- /.box-body --> <div class="box-footer"> <label class="col-sm-2 control-label"></label> <button type="submit" class="btn btn-info ">提交</button> </div> <!-- /.box-footer --> </form> </div>
獲取表單提交的信息
<form class="form-horizontal" action="/product/addAction" method="POST"></form>
設計post提交的表單路由 product.js
router.post('/addAction', (req, res, next) => { // get req.query // post req.body res.send(req.body) })
創建相關數據庫
在數據庫連接中輸入以下指令來創建商品的數據庫集合
use sh2001 switched to db sh2001 db.createCollection('products') { "ok" : 1 } db.createCollection('users') { "ok" : 1 } db.createCollection('carts') { "ok" : 1 } db.createCollection('orders') { "ok" : 1 } db.createCollection('banners') { "ok" : 1 } db.createCollection('messages') { "ok" : 1 } db.createCollection('activitys') { "ok" : 1 }
使用mongoose
安裝指令cnpm i mongoose -S (要連接mongodb數據庫所需的插件)
數據庫連接
創建db.js文件(連接數據庫的模板)
const mongoose = require('mongoose'); const DB_URL = "mongodb://127.0.0.1:27017/sh2001" // 后面兩個不需要記憶,會自動提示 mongoose.connect(DB_URL, { useNewUrlParser: true, useUnifiedTopology: true }); mongoose.connection.on('connected', () => { console.log('數據庫鏈接成功') }) mongoose.connection.on('disconnected', () => { console.log('數據庫鏈接失敗') }) mongoose.connection.on('error', () => { console.log('數據庫鏈接異常') }) module.exports = mongoose;
創建數據庫的集合
collection/Product.js
const mongoose = require('./../db'); const Schema = mongoose.Schema; const productSchema = new Schema({ proid: { type: String }, proname: { type: String }, probrand: { type: String }, brandimg: { type: String }, proimg: { type: Array }, price: { type: Number }, detail: { type: String }, stock: { type: Number }, sales: { type: Number } }) // 就會自動創建一個 數據庫集合products module.exports = mongoose.model('Product', productSchema);
封裝增刪改查以及分頁功能
// 增刪改查的封裝 module.exports = { //插入 insert(collectionName, insertData) { return new Promise((resolve, reject) => { collectionName.insertMany(insertData, (err) => { if (err) { reject(err) } else { resolve() } }) }) }, /* 刪除 */ delete(collectionName, whereData, deleteNum) { const deleteType = deleteNum === 1 ? 'deleteMany' : 'deleteOne'//判斷是一條數據還是多條數據 return new Promise((resolve, reject) => { collectionName[deleteType](whereData, (err) => { if (err) { reject(err) } else { resolve() } }) }) }, /* 修改 */ update(collectionName, whereData, updateData, updateNum) { const updateType = updateNum === 1 ? 'updateMany' : 'updateOne'//判斷是一條數據還是多條 return new Promise((resolve, reject) => { collectionName[updateType](whereData, updateData, (err) => { if (err) { reject(err) } else { resolve() } }) }) }, /* 查詢 */ find(collectionName, whereData, showData) { return new Promise((resolve, reject) => { collectionName.find(whereData, showData, (err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) }, /* 排序 */ sort(collectionName, whereData, showData, sortData) { return new Promise((resolve, reject) => { collectionName.find(whereData, showData).sort(sortData).exec((err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) }, //封裝的分頁功能,有bug paging (collectionName, whereData, showData, limitnum, count) { return new Promise((resolve, reject) => { collectionName.find(whereData, showData).limit(limitnum).skip(count * limitnum).exec((err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) }, //頁碼路由 count (collectionName) { return new Promise((resolve, reject) => { return collectionName.count((err, len) => { if (err) throw err resolve(len) }) }) }, /* 排序 */ paging2 (collectionName, whereData, showData,sortData,limitnum, count) { return new Promise((resolve, reject) => { collectionName.find(whereData, showData).sort(sortData).limit(limitnum).skip(count * limitnum).exec((err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) } }
其他管理功能大致和product差不多,在此不一一贅述
登錄功能
首先創建登陸功能
在routes/index.js中配置登錄的路由
創建登錄頁面
新建登錄頁面views/login.ejs(頁面樣式可以參照,AdminLTE-2.4.10中登錄的界面設計)
設計管理員賬號數據庫
//管理員數據庫 const mongoose = require('./../db') const Schema = mongoose.Schema; const adminSchema = new Schema({ adminid: { type: String }, admin: { type: String }, password: { type: String }, role: { type: Number } // 角色 - 權限 }) // 就會自動創建一個 數據庫集合products module.exports = mongoose.model('Admin', adminSchema);