layui下载

官网下载,解压到项目文件夹下的public目录下

layui使用

资源引入注意,通常入口文件中会配置静态资源根目录为/public
当服务器开启时,通过 地址+/(localhost:8080/) 就是到public目录下
所以引入资源就像这样

layui里面有两个js文件,layui.js小一点,使用到一些功能时,可以另外引入(使用layui.use())

使用mongodb的一个小坑

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 里了!

注意 `

  • collection名称应该为第三个参数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>

分类列表页分页功能

<!DOCTYPE html>
<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

  1. 分页切换再次发送请求,携带参数(curr:切换的目标页,pageSize:每页数量)
  2. 第一次请求时,它没带参数,记得要设置默认值
const router = require('express').Router()
const { getCatesList, getCatesNum } = require('../model/models/cateModel')router.get('/cateList',async (req,res)=>{// 没传的话,设置当前页为1,页面尺寸为2var { 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

删除功能实现

  1. 通过自定义属性将要操作的_id传递过去
  2. 发请求让后端操作数据库
  3. 知道删除成功后,刷新页面
<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.bodydelCate(_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">&#xe67c;</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

增加分类功能实现

  1. 对于父级元素option项,应该请求获取所有的类
  2. option当不写value的时候,value默认等于元素的文本内容;第一条作提示时,可以让value值为"",layui有表单验证

使用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;
});
})
  1. 添加页面渲染(要携带父级分类所需数据)
  2. 提交添加请求操作数据库
    pro/routes/cate.js
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:"添加失败"});})})
  1. 查询所有分类操作
  2. 插入数据操作
    pro/model/models/cate.js
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"> <option value="0" <%= cate.catePId==="0"?'selected':'' %>>顶层分类</option><% for(var i in cates) { %><option value="<%= cates[i]._id %>" <%= cate.catePId===cates[i]._id?'selected':'' %>><%= cates[i].cateName %></option><% } %></select></div>
</div>

注意图片因为是想用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;// 创建一个 编辑modeleditCate(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值为空,过期时间为0res.cookie('user','',{maxAge:0})res.send({msg: '退出成功',code: 0})
})// 账号密码提交
router.post("/login",(req,res)=>{var user = req.bodygetUser({userName: user.userName}).then(re=>{if (re){// 数据库有这个用户,判断密码对不对if(re.psw === user.psw){// 登录成功时种cookieres.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): nullif(loginState){// 如果登陆过了next()}else{res.redirect('/login')}}
}module.exports = loginCheck

全局使用登录验证中间件,记住要放在cookie-parser下面
pro/app.js

// 导入自定义中间件
var loginCheck = require('./middleware/loginCheck')// 使用中间件,记住要在cookie-parser下面使用
app.use(loginCheck);

合肥千峰前端培训---使用layui写传统mvc模式后台管理相关推荐

  1. 合肥千峰前端培训---React写后台管理注意点(使用AntDesign)

    基础姿势要过一遍吗?请点这里! react常用的ui组件库 pc antdesign 移动 antdesignMobile 蚂蚁金服 快速上手 cnpm i antd redux redux-thun ...

  2. 合肥千峰前端培训---vue-cli移动端实战项目所遇问题

    vue-cli更改默认下载方式(用什么包管理器) 找到C:\Users\Administrator/.vuerc文件 Yarn/npm node.sass下载失败 npm install -g mir ...

  3. 合肥千峰前端培训---React知识点梳理

    基础知识整理开源仓库 :)欢迎star VSCode React插件 ES7 React/Redux/GraphQL/React-Native snippets react特点 灵活,功能都要自己写, ...

  4. 合肥千峰前端培训---npm和nrm的使用

    npm和nrm的使用 npm node package manager(node包管理工具) npm安装:在安装node时默认安装了npm,可以通过npm -v查看版本号 作用: (1).管理项目中的 ...

  5. 千峰python 培训南京千锋教育IT培训赋能人才

    10月31日,中国正式开启第五代移动通信网络(5G)商用时代,这也标志着中国通信发展史进入了一个新的里程碑.中国移动.联通.电信三大运营商纷纷推出5G套餐,超快的网速使得许多市民跃跃欲试.显然,5G商 ...

  6. 开源推荐:.Net Core3.1 + EF Core + LayUI 封装的MVC版后台管理系统

    ASP.NET Core是一个由微软创建的,用于构建Web应用程序,API,微服务的Web框架.它使用常见的模式,例如MVC(模型-视图-控制器),依赖注入,和一个由中间件构成它基于Apache 2. ...

  7. 千峰python培训机构

    在数字化经济时代下,推动数字化进程的IT技术成为众多企业竞相掌握的核心技术,编程语言也成为企业研发人员深度学习和研究技术的加速器.Python编辑语言因其高效的数据结构和简单有效的面向编程对象,而成为 ...

  8. 武汉千峰python培训

    随着互联网行业的发展与大热,很多人都想学习好相关技术,比如Python.之所以选择学习Python技术不仅是因为它拥有广阔的行业发展前景,还因为拥有薪资的诱惑力.那怎样才能在较短的时间内高效掌握Pyt ...

  9. 字节跳动面试官:千峰java培训多少钱

    并发编程三大特性 原子性 一个操作或者多次操作,要么所有的操作全部都得到执行并且不会受到任何因素的干扰而中断,要么所有的操作都执行,要么都不执行. 对于基本数据类型的访问,读写都是原子性的[long和 ...

最新文章

  1. 2021-10-20 Speaking Class
  2. could not open parameter file init**.ora
  3. android比较常用的布局,Android_九宫图比较常用的多控件布局(GridView)使用介绍,GridView跟ListView都是比较常用的 - phpStudy...
  4. 时间触发以太网TTEthernet技术
  5. JIT编译器,内联和转义分析
  6. 后台系统可扩展性学习笔记(十三)缓存
  7. gps有几个轨道面_同样是精准定位,为何GPS只用24颗卫星,北斗却需要55颗卫星?...
  8. android 浮层菜单弹出,Android PopupWindow实现微信右上角的弹出菜单
  9. 操作系统中死锁的概念
  10. Golang教程:(十五)指针
  11. 解决UE4 Launcher启动速度极慢的方法
  12. RED-Net神经网络
  13. 功夫小子实践开发-基本工具类的分析和实现
  14. Ubuntu20.04 在anaconda上,opencv-python支持h264编码
  15. 纯前端canvas手绘海报
  16. 关于Flume断点续传(防止重复消费)的解决方案
  17. 胡晓曼:MindSpore 开源运营与治理 | DEV. Together 2021 中国开发者生态峰会
  18. 共享办公室,推送企业紧密合作
  19. BIOS怎么开启UEFI模式|电脑设置UEFI启动的方法
  20. 使用@media screen解决分web不同分辨率问题

热门文章

  1. 破世界纪录了,用Python实现自动扫雷
  2. java jxbroswer---创建浏览器实例
  3. IDEA 编译报错Compilation completed with 1 error and 0 warnings
  4. SpringCloud多环境配置Profiles
  5. PTA L2-2 冰岛人 (25分)
  6. python——炸金花
  7. 网页样式——各种炫酷效果持续更新ing...
  8. 最强蜗牛击败毁灭机器人_最强蜗牛恶魔形态怎么解锁 恶魔形态所有阶级详解[多图]...
  9. iPhone手机装机必备的5个APP,每个都让你欲罢不能,瞬间逼格满满!
  10. 如何使用MATLAB对任意三维数据绘制三维曲面