官网下载,解压到项目文件夹下的public目录下
资源引入注意,通常入口文件中会配置静态资源根目录为/public
当服务器开启时,通过 地址+/(localhost:8080/) 就是到public目录下
所以引入资源就像这样
layui里面有两个js文件,layui.js小一点,使用到一些功能时,可以另外引入(使用layui.use())
var schema = new mongoose.Schema({ name: 'string', size: 'string' });
var Tank = mongoose.model('Tank', schema);
// 第一个参数是跟 model 对应的集合( collection )名字的 单数 形式。 Mongoose 会自动找到名称是 model 名字 复数 形式的 collection 。 对于上例,Tank 这个 model 就对应数据库中 tanks 这个 collection。.model() 这个函数是对 schema 做了拷贝(生成了 model)。 你要确保在调用 .model() 之前把所有需要的东西都加进 schema 里了!
注意 `
var Tank = mongoose.model('Tank', schema,my_db)
,若为缺省,会自动根据参数name的值以复数形式生成collection(Tank
对应的是tanks
的集合,它会自动加上s,还有他会转小写,数据库起名最好是下划线命名法my_db
)iframe标签实现局部更新
目录选项更改iframe的src属性值
<div class="layui-body" style="overflow: hidden;">
<iframe src="/main" id="frame" frameborder="0" height="100%" width="100%" >iframe>
div>
<html>
<body>
<div id="test1">div>
<script>
layui.use('laypage', function(){
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
elem: 'laypage' //注意,这里的 test1 是 ID,不用加 # 号
,count: <%= count %> //数据总数,从服务端得到
,limit: 2 //每页显示的条数。laypage将会借助 count 和 limit 计算出分页数。
,curr: <%= curr %> //当前页
,jump: function(obj, first){
//obj包含了当前分页的所有参数,比如:
// console.log(obj.curr); //得到当前页,以便向服务端请求对应页的数据。
// console.log(obj.limit); //得到每页显示的条数
//首次不执行
if(!first){
location.href = `/cateList?curr=${obj.curr}&pageSize=${obj.limit}`
}
}
});
});
script>
body>
html>
需要获得分类总数方法和获取指定页数的分类的方法
pro/model/models
const mongoose = require('mongoose')
const { cateSchema } = require('../schemas')
var cateModel = mongoose.model("cate",cateSchema)
// 获取分类列表
var getCatesList = (params={}) => cateModel.find().limit(params.pageSize).skip((params.curr-1)*params.pageSize)
// 获取分类数量
var getCatesNum = () => cateModel.find().count()
module.exports = {
getCatesList,
getCatesNum
}
路由处理业务逻辑
pro/routes/cate.js
const router = require('express').Router()
const { getCatesList, getCatesNum } = require('../model/models/cateModel')
router.get('/cateList',async (req,res)=>{
// 没传的话,设置当前页为1,页面尺寸为2
var { curr=1 ,pageSize=2 } = req.query
// 注意传过来的是字符串
curr = parseInt(curr)
pageSize = parseInt(pageSize)
var cates = await getCatesList({ curr, pageSize })
var count = await getCatesNum()
res.render('cateList',{
cates,
count,
curr
})
})
module.exports = router
_id
传递过去<button class="del layui-btn layui-btn-danger" _id="<%= cates[i]._id %>">删除button>
// 删除按钮
$(".del").click(function(){
layer.confirm('确定删除吗?', {icon: 3, title:'提示'},(index)=>{
$.ajax({
url: '/cateDel',
type: 'POST',
data: {
_id: $(this).attr('_id')
},
success(res){
if(res.code===0){
layer.msg(res.msg,{time: 200},function(){
history.go(0)
})
}else{
layer.msg(res.msg)
}
}
});
layer.close(index);
});
});
pro/routes/cate.js
const router = require('express').Router()
const { delCate } = require('../model/models/cateModel')
// 删除分类
router.post('/cateDel',(req,res)=>{
let { _id } = req.body
delCate(_id).then(re=>{
res.send({
code: 0,
msg: '删除成功'
})
}).catch(err=>{
res.send({
code: 1,
msg: '删除失败'
})
})
})
module.exports = router
pro/model/models/cateModel.js
const mongoose = require('mongoose')
const { cateSchema } = require('../schemas')
var cateModel = mongoose.model("cate",cateSchema)
// 删除分类
var delCate = (_id) => cateModel.remove({_id})
module.exports = {
delCate
}
layui 里面有文件上传
<div class="layui-form-item">
<label class="layui-form-label">分类图标label>
<div class="layui-input-block">
<div class="preview_img" style="margin-bottom: 10px;">
<img src="" alt="预览图片" style="max-width: 390px;">
div>
<button type="button" class="layui-btn" id="picUpload">
<i class="layui-icon">i>选择图片
button>
div>
div>
layui.use(["form","element","upload","jquery","layer"], function(){
var form = layui.form
var element = layui.element
var upload = layui.upload
var layer = layui.layer
var $ = layui.jquery
// 保存上传图片的绝对路径,之后合并
var _data = {}
//执行实例
var uploadInst = upload.render({
elem: '#picUpload' //绑定元素
,url: '/upload' //上传接口
,multiple: false //只允许上传单个文件
,auto: true //选择文件后自动上传
,field: "img" //**设定文件域的字段名(后台根据字段名获取)
,choose: function(obj) {
// 选择文件后的回调函数
//将每次选择的文件追加到文件队列
var files = obj.pushFile();
//预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
obj.preview(function(index, file, result){
// console.log(result); //得到文件base64编码,比如图片
$(".preview_img img").attr('src',result);
});
}
,done: function(res){
//上传完毕回调
layer.msg('code:'+res.code+",msg:"+res.msg)
_data.cateIcon = '/uploads/'+res.data
}
,error: function(){
//请求异常回调
layer.msg("图片上传失败")
}
});
multer中间件使用
pro/utils/upload.js
const multer = require('multer')
// 最后路由文件都会挂到index.js上,所以路径·
// var upload = multer({dest: './public/uploads/'})
// single里的参数是上传文件的表单元素的name属性值
var storage = multer.diskStorage({
destination: function (req, file, cb) {
// 最后路由文件都会挂到index.js上,所以路径·
cb(null, './public/uploads')
},
filename: function (req, file, cb) {
var extName = file.mimetype.split('/').reverse()[0]
cb(null, file.fieldname + '-' + Date.now()+"."+extName)
}
})
var upload = multer({ storage: storage })
module.exports = upload
文件上传接口处理
pro/routes/upload.js
var router = require('express').Router()
var upload = require('../utils/upload')
router.post('/upload',upload.single('img'),(req,res)=>{
res.send({
code: 0,
msg: '图片上传成功',
data: req.file.filename
})
})
module.exports = router
使用layui里提供的表单元素
<div class="layui-form-item">
<label class="layui-form-label">父级分类label>
<div class="layui-input-block">
<select name="catePId" lay-verify="required">
<option value="">请选择option>
<option value="0">顶层分类option>
<% for(var i in cates) { %>
<option value="<%= cates[i]._id %>"><%= cates[i].cateName %>option>
<% } %>
select>
div>
div>
//监听提交
form.on('submit(formDemo)', function(data){
// data.field获取表单提交内容
// console.log(data.field)
$.ajax({
url:'/cateAdd',
type: 'POST',
dataType: 'JSON',
data: Object.assign(_data,data.field),
success: function(res){
// 上传成功清空表单
// $(".layui-form")[0].reset();
// $(".preview_img img").attr('src','');
layer.msg(res.msg,{
time: 200
},function(){
// 添加成功后跳转到列表页
location.href="/cateList"
})
// console.log(res)
}
})
// 取消默认表单提交事件
return false;
});
})
var express = require('express');
var router = express.Router();
const { getAllCates,addCates } = require('../model/models/cate')
// 添加分类页面渲染
router.get('/cateAdd', async function(req, res, next) {
let cates = await getAllCates();
res.render('cateAdd',{
cates
});
});
// 添加分类
router.post('/cateAdd',(req,res)=>{
console.log(req.body);
// 调用 增加数据 model函数
addCates(req.body).then(re=>{
res.send({
code:0,
msg:"添加成功"
});
}).catch(err=>{
console.log(err)
res.send({
code:1,
msg:"添加失败"
});
})
})
const cateModel = mongoose.model("qf_cate",cateSchema);
// 获取分类
const getAllCates = ()=>cateModel.find()
// 添加分类
const addCates = (params)=> cateModel.insertMany(params)
module.exports = {
getAllCates,
addCates
};
布局渲染基本跟添加分类一致,但请求携带除了目前所有分类之外,还要知道渲染的是哪个
下拉菜单选项的预选通过设置selected属性实现
<div class="layui-form-item">
<label class="layui-form-label">父级分类label>
<div class="layui-input-block">
<select name="catePId" lay-verify="required">
注意图片因为是想用img
字段,而数据库中的字段是cateIcon
,不一样,且它的值是保存在服务器静态资源目录下的,要改一下,所以把它单独拎form外面了,layui的data.field数据是来自from里面的表单元素的name和值
那么就要单独判断有没有修改图片
form.on('submit(formDemo)', function(data){
// JSON.stringify(_data) 有问题
_data = _data.cateIcon?_data:{cateIcon: $(".preview_img img").attr('src')}
$.ajax({
url:'/cateEdit',
type: 'POST',
dataType: 'JSON',
data: Object.assign(_data,data.field),
success: function(res){
// 上传成功清空表单
// $(".layui-form")[0].reset();
// $(".preview_img img").attr('src','');
layer.msg(res.msg,{
time: 200
},function(){
location.href="/cateList"
})
// console.log(res)
}
})
// 取消默认表单提交事件
return false;
});
编辑分类的接口
pro/routes/cate.js
var express = require('express');
var router = express.Router();
const { getAllCates,getCateById,editCate} = require('../model/models/cate')
// 编辑分类页面渲染
router.get('/cateEdit', async function(req, res, next) {
let cates = await getAllCates();
let cate = await getCateById(req.query.id);
console.log(req.query.id);
res.render('cateEdit',{
cates,
_id:req.query.id,
cate
});
});
// 修改数据库请求
router.post('/cateEdit', async function(req, res, next) {
let cate = req.body;
// 创建一个 编辑model
editCate(cate).then(re=>{
res.send({
code:0,
msg:'修改成功'
});
}).catch(err=>{
res.send({
code:-1,
msg:'修改失败'
});
})
});
module.exports = router;
操作数据库,修改数据
const mongoose = require('mongoose');
const {cateSchema} = require("../schemas");
const cateModel = mongoose.model("qf_cate",cateSchema);
// 获取分类
const getAllCates = ()=>cateModel.find()
// 根据id 获取这条分类数据
const getCateById = (_id)=>cateModel.findById(_id);
// 修改model
const editCate = (params)=>cateModel.update({
_id:params._id
},params);
module.exports = {
getAllCates,
getCateById,
editCate
};
登录成功时种cookie,退出时移除cookie
res.cookie("user",JSON.stringify({
"userName":re.userName,
"isLogin":true
}));
res.cookie('user','',{maxAge:0});
pro/routes/user.js
const router = require("express").Router()
const { getUser } = require('../model/models/loginModel')
// 登录页渲染
router.get("/login",(req,res)=>{
res.render('login')
})
// 退出登录
router.post("/loginOut",(req,res)=>{
// 设置cookie值为空,过期时间为0
res.cookie('user','',{maxAge:0})
res.send({
msg: '退出成功',
code: 0
})
})
// 账号密码提交
router.post("/login",(req,res)=>{
var user = req.body
getUser({userName: user.userName}).then(re=>{
if (re){
// 数据库有这个用户,判断密码对不对
if(re.psw === user.psw){
// 登录成功时种cookie
res.cookie("user",JSON.stringify({
"userName": re.userName,
"isLogin": true
}))
res.send({
code: 0,
msg: '登录成功'
})
}else{
res.send({
code: -1,
msg: '用户名或密码错误'
})
}
}else {
// 数据库没有这用户名,返回null
// 用户名错误
res.send({
code: -1,
msg: '用户名或密码错误'
})
}
}).catch(err=>{
res.send({
code: 1,
msg: '登录失败'
})
})
})
module.exports = router
登录鉴权
通过中间来进行全局路由拦截
pro/middleware/loginCheck.js
function loginCheck (req,res,next) {
if(req.url === '/login'){
next()
}else{
var loginState = req.cookies.user? JSON.parse(req.cookies.user): null
if(loginState){
// 如果登陆过了
next()
}else{
res.redirect('/login')
}
}
}
module.exports = loginCheck
全局使用登录验证中间件,记住要放在cookie-parser下面
pro/app.js
// 导入自定义中间件
var loginCheck = require('./middleware/loginCheck')
// 使用中间件,记住要在cookie-parser下面使用
app.use(loginCheck);