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

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,页面尺寸为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

删除功能实现

  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.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">&#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;
  // 创建一个 编辑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);
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
千峰kerwen前端插件是一款功能强大的前端开发工具,能够帮助开发者更高效地开发网页和应用程序。该插件拥有丰富的功能和扩展,能够满足各种前端开发需求。 首先,千峰kerwen前端插件提供了一系列实用的代码生成和编辑功能。开发者可以通过插件快速生成常见的HTML、CSS和JavaScript代码,减少手代码的工作量。同时,插件支持代码高亮、代码提示和错误检查等功能,帮助开发者编无错的代码。 其次,千峰kerwen前端插件还提供了丰富的调试和性能优化功能。开发者可以通过插件方便地调试JavaScript代码,查找和修复错误。同时,插件还能够对网页进行性能优化,减少加载时间和提升用户体验。 此外,千峰kerwen前端插件还支持主题和样式的定制。用户可以选择不同的主题和样式,为网页和应用程序添加独特的外观和风格。插件还提供了一些常用的UI组件和效果,方便开发者快速构建漂亮的界面。 最后,千峰kerwen前端插件还具备良好的兼容性和扩展性。插件支持主流的浏览器和操作系统,能够在不同平台上稳定运行。同时,插件还提供了丰富的扩展接口和文档,方便开发者根据需要进行功能扩展和定制。 总之,千峰kerwen前端插件是一款强大而实用的前端开发工具,为开发者提供了丰富的功能和便利的开发环境。无论是初学者还是经验丰富的开发者,都可以通过该插件提升开发效率,实现更好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值