0. 资源地址

  1. 线上 DEMO 项目地址:http://www.escook.cn:8086/
  2. 项目的 API 接口地址: https://www.showdoc.cc/escook?page_id=3707158761215217

1. 项目前期的准备工作

1.1 初始化项目结构

  1. 素材 目录下的 assetshome 文件夹,拷贝到 code 目录下
  2. code 目录下新建 login.htmlindex.html 页面

1.2 使用GitHub管理大事件的项目

  1. code 目录中运行 git init 命令
  2. code 目录中运行 git add . 命令
  3. code 目录下运行 git commit -m "init project" 命令
  4. 新建 Github 仓库 web_bigevent
  5. 将本地仓库和Github仓库建立关联关系
  6. 将本地仓库的代码推送到Github仓库中
  7. 运行 git checkout -b login 命令,创建并切换到 login 分支

1.3 安装VSCode的Live Server插件辅助开发

  1. 在插件市场,搜索 Live Server 并安装
  2. 在页面上鼠标右键,选择 Open With Live Server 即可快速使用 http 协议访问页面

2. 登录注册

2.1 绘制login页面的基本结构

  1. 编写 HTML 结构:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>大事件-登录/注册</title><!-- 导入 LayUI 的样式 --><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><!-- 导入自己的样式表 --><link rel="stylesheet" href="/assets/css/login.css" /></head><body><!-- 头部的 Logo 区域 --><div class="layui-main"><img src="/assets/images/logo.png" alt="" /></div><!-- 登录注册区域 --><div class="loginAndRegBox"><div class="title-box"></div></div></body>
    </html>
  2. 美化样式:

    html,
    body {margin: 0;padding: 0;height: 100%;width: 100%;background: url('/assets/images/login_bg.jpg') no-repeat center;background-size: cover;
    }.loginAndRegBox {width: 400px;height: 310px;background-color: #fff;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%);
    }.title-box {height: 60px;background: url('/assets/images/login_title.png') no-repeat center;
    }
    

2.2 实现登录和注册的按需切换

  1. 编写 HTML 结构:

        <!-- 登录注册区域 --><div class="loginAndRegBox"><div class="title-box"></div><!-- 登录的div --><div class="login-box"></div><!-- 注册的div --><div class="reg-box"></div></div>
    
  2. 编写样式:

    .reg-box {display: none;
    }
    
  3. 编写 JavaScript 代码:

    $(function() {// 点击“去注册账号”的链接$('#link_reg').on('click', function() {$('.login-box').hide()$('.reg-box').show()})// 点击“去登录”的链接$('#link_login').on('click', function() {$('.login-box').show()$('.reg-box').hide()})
    })
    

2.3 绘制登录表单的基本结构

  1. 编写 HTML 结构:

      <!-- 登录的div --><div class="login-box"><!-- 登录的表单 --><form class="layui-form" action=""><!-- 用户名 --><div class="layui-form-item"><i class="layui-icon layui-icon-username"></i><input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input" /></div><!-- 密码 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input" /></div><!-- 登录按钮 --><div class="layui-form-item"><!-- 注意:表单提交按钮和普通按钮的区别,就是 lay-submit 属性 --><button class="layui-btn layui-btn-fluid layui-btn-normal" lay-submit>登录</button></div><div class="layui-form-item links"><a href="javascript:;" id="link_reg">去注册账号</a></div></form></div>
    

2.4 美化登录表单的样式

  1. 编写样式:

    .layui-form {padding: 0 30px;
    }.links {display: flex;justify-content: flex-end;
    }.links a {font-size: 12px;
    }
    

2.5 绘制文本框前面的小图标

  1. 在用户名的文本框之前,添加如下的标签结构:

    <i class="layui-icon layui-icon-username"></i>
    
  2. 在密码框之前,添加如下的标签结构:

    <i class="layui-icon layui-icon-password"></i>
    
  3. 美化样式:

    .layui-form-item {position: relative;
    }.layui-icon {position: absolute;left: 10px;top: 10px;
    }.layui-input {padding-left: 32px;
    }
    

2.6 快速绘制注册的表单

  1. 将登录的表单复制一份,并修改为注册的表单即可:

      <!-- 注册的div --><div class="reg-box"><!-- 注册的表单 --><form class="layui-form" action=""><!-- 用户名 --><div class="layui-form-item"><i class="layui-icon layui-icon-username"></i><input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input" /></div><!-- 密码 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input" /></div><!-- 密码确认框 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="repassword" required lay-verify="required" placeholder="再次确认密码" autocomplete="off" class="layui-input" /></div><!-- 注册按钮 --><div class="layui-form-item"><!-- 注意:表单提交按钮和普通按钮的区别,就是 lay-submit 属性 --><button class="layui-btn layui-btn-fluid layui-btn-normal" lay-submit>注册</button></div><div class="layui-form-item links"><a href="javascript:;" id="link_login">去登录</a></div></form></div>
    

2.7 实现登录表单的验证

  1. 导入 layui 的 js 文件:

    <script src="/assets/lib/layui/layui.all.js"></script>
    
  2. 为需要验证的表单项添加 lay-verify 属性,同时指定具体的校验规则即可。

2.8 自定义校验规则

  1. 从 layui 中获取 form 对象:

    var form = layui.form
    
  2. 通过 form.verify() 函数自定义校验规则:

      form.verify({// 自定义了一个叫做 pwd 校验规则pwd: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格'],// 校验两次密码是否一致的规则repwd: function(value) {// 通过形参拿到的是确认密码框中的内容// 还需要拿到密码框中的内容// 然后进行一次等于的判断// 如果判断失败,则return一个提示消息即可var pwd = $('.reg-box [name=password]').val()if (pwd !== value) {return '两次密码不一致!'}}})
    
  3. 按需为表单项添加校验规则:

    <input type="password" name="repassword" required lay-verify="required|pwd|repwd" placeholder="再次确认密码" autocomplete="off" class="layui-input" />
    

2.9 发起注册用户的Ajax请求

  1. 为注册表单添加Id:

    <!-- 注册的表单 -->
    <form class="layui-form" id="form_reg"></form>
    
  2. 监听提交事件:

    // 监听注册表单的提交事件$('#form_reg').on('submit', function(e) {// 1. 阻止默认的提交行为e.preventDefault()// 2. 发起Ajax的POST请求var data = {username: $('#form_reg [name=username]').val(),password: $('#form_reg [name=password]').val()}$.post('http://ajax.frontend.itheima.net/api/reguser', data, function(res) {if (res.status !== 0) {return layer.msg(res.message)}layer.msg('注册成功,请登录!')// 模拟人的点击行为$('#link_login').click()})})
    

2.10 使用layer提示消息

  1. 导入 layer:

    var layer = layui.layer
    
  2. 调用 layer.msg() 提示消息:

    layer.msg('注册成功,请登录!')
    

2.11 发起登录的Ajax请求

  1. 为登录表单添加id:

    <form class="layui-form" id="form_login"></form>
    
  2. 监听提交事件:

      // 监听登录表单的提交事件$('#form_login').submit(function(e) {// 阻止默认提交行为e.preventDefault()$.ajax({url: '/api/login',method: 'POST',// 快速获取表单中的数据data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('登录失败!')}layer.msg('登录成功!')// 将登录成功得到的 token 字符串,保存到 localStorage 中localStorage.setItem('token', res.token)// 跳转到后台主页location.href = '/index.html'}})})
    

2.12 在ajaxPrefilter中统一拼接请求的根路径

  1. /assets/js 目录中新建 baseAPI.js

  2. 编写如下代码:

    // 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候,
    // 会先调用 ajaxPrefilter 这个函数
    // 在这个函数中,可以拿到我们给Ajax提供的配置对象
    $.ajaxPrefilter(function(options) {// 在发起真正的 Ajax 请求之前,统一拼接请求的根路径options.url = 'http://ajax.frontend.itheima.net' + options.url
    })

2.13 提交login分支的代码到GitHub

  1. 运行 git add . 命令
  2. 运行 git commit -m "完成了登录和注册的功能" 命令
  3. 运行 git push -u origin login 命令
  4. 运行 git checkout master 命令
  5. 运行 git merge login 命令
  6. 运行 git push 命令
  7. 运行 git checkout -b index 命令

3. 后台主页

3.1 快速实现后台主页的布局效果

  1. 从 layUI 官方文档中粘贴布局的主要代码,并修改如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>后台主页</title><!-- 导入 layui 的样式表 --><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /></head><body class="layui-layout-body"><div class="layui-layout layui-layout-admin"><div class="layui-header"><div class="layui-logo"><img src="/assets/images/logo.png" alt="" /></div><!-- 头部区域(可配合layui已有的水平导航) --><ul class="layui-nav layui-layout-right"><li class="layui-nav-item"><a href="javascript:;"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" />个人中心</a><dl class="layui-nav-child"><dd><a href="">基本资料</a></dd><dd><a href="">更换头像</a></dd><dd><a href="">重置密码</a></dd></dl></li><li class="layui-nav-item"><a href="">退出</a></li></ul></div><div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-filter="test"><li class="layui-nav-item layui-nav-itemed"><a class="" href="javascript:;">所有商品</a><dl class="layui-nav-child"><dd><a href="javascript:;">列表一</a></dd><dd><a href="javascript:;">列表二</a></dd><dd><a href="javascript:;">列表三</a></dd><dd><a href="">超链接</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">解决方案</a><dl class="layui-nav-child"><dd><a href="javascript:;">列表一</a></dd><dd><a href="javascript:;">列表二</a></dd><dd><a href="">超链接</a></dd></dl></li><li class="layui-nav-item"><a href="">云市场</a></li><li class="layui-nav-item"><a href="">发布商品</a></li></ul></div></div><div class="layui-body"><!-- 内容主体区域 --><div style="padding: 15px;">内容主体区域</div></div><div class="layui-footer"><!-- 底部固定区域 -->© layui.com - 底部固定区域</div></div><!-- 导入 layui 的JS文件 --><script src="/assets/lib/layui/layui.all.js"></script></body>
    </html>
    

3.2 修改侧边栏的结构

<div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree"><li class="layui-nav-item"><a href="/">首页</a></li><li class="layui-nav-item"><a class="" href="javascript:;">文章管理</a><dl class="layui-nav-child"><dd><a href="javascript:;">文章类别</a></dd><dd><a href="javascript:;">文章列表</a></dd><dd><a href="javascript:;">发布文章</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">个人中心</a><dl class="layui-nav-child"><dd><a href="javascript:;">基本资料</a></dd><dd><a href="javascript:;">更换头像</a></dd><dd><a href="javascript:;">重置密码</a></dd></dl></li></ul></div></div>

3.3 使用lay-shrink实现左侧菜单互斥效果

      <div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-shrink="all"><!-- 省略其他代码 --></ul></div></div>

3.4 为菜单项添加图标

  1. 导入第三方的图标库:

    <!-- 导入第三方图标库 -->
    <link rel="stylesheet" href="/assets/fonts/iconfont.css" />
    
  2. 修改左侧菜单的结构:

      <div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-shrink="all"><li class="layui-nav-item"><a href=""><span class="iconfont icon-home"></span>首页</a></li><li class="layui-nav-item"><a class="" href="javascript:;"><span class="iconfont icon-16"></span>文章管理</a><dl class="layui-nav-child"><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>文章类别</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>文章列表</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>发布文章</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;"><span class="iconfont icon-user"></span>个人中心</a><dl class="layui-nav-child"><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>基本资料</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>更换头像</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>重置密码</a></dd></dl></li></ul></div></div>
    
  3. 修改头部“退出”按钮的结构:

    <li class="layui-nav-item"><a href=""><span class="iconfont icon-tuichu"></span>退出</a>
    </li>
    
  4. 导入自己的样式表文件:

    <link rel="stylesheet" href="/assets/css/index.css" />
    
  5. 编写自己的样式:

    .layui-footer {text-align: center;font-size: 12px;
    }.iconfont {margin-right: 8px;
    }.layui-icon {margin-right: 8px;margin-left: 20px;
    }
    

3.5 使用iframe标签在内容主体区域显示网页内容

  1. 在页面主体的 div 中添加 iframe

      <div class="layui-body"><!-- 内容主体区域 --><iframe name="fm" src="" frameborder="0"></iframe></div>
    
  2. 首页链接添加hreftarget属性:

    <a href="/home/dashboard.html" target="fm"><span class="iconfont icon-home"></span>首页</a>
    
  3. 美化样式:

    iframe {width: 100%;height: 100%;
    }.layui-body {overflow: hidden;
    }
    

3.6 解决3个小问题

  1. iframe 指定默认页面:

    <iframe name="fm" src="/home/dashboard.html" frameborder="0"></iframe>
    
  2. 首页 对应的导航 Item 项添加 layui-this 属性:

    <li class="layui-nav-item layui-this"><a href="/home/dashboard.html" target="fm"><span class="iconfont icon-home"></span>首页</a>
    </li>
    
  3. 强制清除 <a> 链接的 CSS3 动画:

    a {transition: none !important;
    }
    

3.7 渲染图片头像和文字头像

  1. 修改头部区域的的头像结构如下:

    <a href="javascript:;" class="userinfo"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" /><span class="text-avatar">A</span>个人中心
    </a>
    
  2. 在左侧导航区域的 ul 之前添加如下头像结构:

    <div class="userinfo"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" /><span class="text-avatar">A</span><span id="welcome">欢迎 ***</span>
    </div>
    
  3. 添加样式美化 UI 结构:

    .userinfo {height: 60px;line-height: 60px;text-align: center;font-size: 12px;user-select: none;
    }.layui-side-scroll .userinfo {border-bottom: 1px solid #282b33;
    }.layui-nav-img {width: 40px;height: 40px;
    }.text-avatar {display: inline-block;width: 40px;height: 40px;background-color: #009688;border-radius: 50%;line-height: 40px;text-align: center;font-size: 20px;color: #fff;position: relative;top: 4px;margin-right: 10px;
    }
    

1. 后台主页

1.1 获取用户的基本信息

  1. 导入需要的脚本:

        <!-- 导入 jQuery --><script src="/assets/lib/jquery.js"></script><!-- 导入自己封装的 baseAPI --><script src="/assets/js/baseAPI.js"></script><!-- 导入自己的 js 文件 --><script src="/assets/js/index.js"></script>
    
  2. 定义 getUserInfo 函数:

    // 获取用户的基本信息
    function getUserInfo() {$.ajax({method: 'GET',url: '/my/userinfo',// headers 就是请求头配置对象headers: {Authorization: localStorage.getItem('token') || ''},success: function(res) {if (res.status !== 0) {return layui.layer.msg('获取用户信息失败!')}// 调用 renderAvatar 渲染用户的头像renderAvatar(res.data)}})
    }
    

1.2 渲染用户头像

  1. 定义 renderAvatar 函数:

    // 渲染用户的头像
    function renderAvatar(user) {// 1. 获取用户的名称var name = user.nickname || user.username// 2. 设置欢迎的文本$('#welcome').html('欢迎&nbsp;&nbsp;' + name)// 3. 按需渲染用户的头像if (user.user_pic !== null) {// 3.1 渲染图片头像$('.layui-nav-img').attr('src', user.user_pic).show()$('.text-avatar').hide()} else {// 3.2 渲染文本头像$('.layui-nav-img').hide()var first = name[0].toUpperCase()$('.text-avatar').html(first).show()}
    }
    

1.3 统一为有权限的接口设置headers请求头

  1. 在 baseAPI的 ajaxPrefilter 中添加如下代码:

      // 统一为有权限的接口,设置 headers 请求头if (options.url.indexOf('/my/') !== -1) {options.headers = {Authorization: localStorage.getItem('token') || ''}}
    

1.4 实现退出功能

  1. 修改退出的<a> 链接如下:

    <a href="javascript:;" id="btnLogout"><span class="iconfont icon-tuichu"></span>退出</a>
    
  2. 实现退出功能:

      var layer = layui.layer// 点击按钮,实现退出功能$('#btnLogout').on('click', function() {// 提示用户是否确认退出layer.confirm('确定退出登录?', { icon: 3, title: '提示' }, function(index) {//do something// 1. 清空本地存储中的 tokenlocalStorage.removeItem('token')// 2. 重新跳转到登录页面location.href = '/login.html'// 关闭 confirm 询问框layer.close(index)})})
    

1.5 控制用户的访问权限

  1. 在调用有权限接口的时候,指定complete回调函数:

        // 不论成功还是失败,最终都会调用 complete 回调函数complete: function(res) {// console.log('执行了 complete 回调:')// console.log(res)// 在 complete 回调函数中,可以使用 res.responseJSON 拿到服务器响应回来的数据if (res.responseJSON.status === 1 && res.responseJSON.message === '身份认证失败!') {// 1. 强制清空 tokenlocalStorage.removeItem('token')// 2. 强制跳转到登录页面location.href = '/login.html'}}
    

1.6 优化权限控制的代码

  1. 将权限控制的代码,从每个请求中,抽离到 ajaxPrefilter 中:

    // 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候,
    // 会先调用 ajaxPrefilter 这个函数
    // 在这个函数中,可以拿到我们给Ajax提供的配置对象
    $.ajaxPrefilter(function(options) {// 在发起真正的 Ajax 请求之前,统一拼接请求的根路径options.url = 'http://ajax.frontend.itheima.net' + options.url// 统一为有权限的接口,设置 headers 请求头if (options.url.indexOf('/my/') !== -1) {options.headers = {Authorization: localStorage.getItem('token') || ''}}// 全局统一挂载 complete 回调函数options.complete = function(res) {// console.log('执行了 complete 回调:')// console.log(res)// 在 complete 回调函数中,可以使用 res.responseJSON 拿到服务器响应回来的数据if (res.responseJSON.status === 1 && res.responseJSON.message === '身份认证失败!') {// 1. 强制清空 tokenlocalStorage.removeItem('token')// 2. 强制跳转到登录页面location.href = '/login.html'}}
    })

2. 基本资料

2.1 创建基本资料对应的页面

  1. 新建 /user/user_info.html 并初始化如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><!-- 导入 layui 的样式 --><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><!-- 导入自己的样式 --><link rel="stylesheet" href="/assets/css/user/user_info.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">修改用户信息</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div></body>
    </html>
    
  2. 新建 /assets/css/user/user_info.css 并初始化如下:

    html,
    body {margin: 0;padding: 0;
    }body {background-color: #f2f3f5;padding: 15px;
    }
    
  3. 修改 index.html 中对应的 <a> 链接:

    <a href="/user/user_info.html" target="fm"><i class="layui-icon layui-icon-app"></i>基本资料</a>
    

2.2 绘制基本资料对应的表单

  1. 编写如下的表单结构:

    <!-- form 表单区域 --><form class="layui-form" action=""><div class="layui-form-item"><label class="layui-form-label">登录名称</label><div class="layui-input-block"><input type="text" name="username" required lay-verify="required" placeholder="请输入登录名称" autocomplete="off" class="layui-input" readonly /></div></div><div class="layui-form-item"><label class="layui-form-label">用户昵称</label><div class="layui-input-block"><input type="text" name="nickname" required lay-verify="required|nickname" placeholder="请输入用户昵称" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">用户邮箱</label><div class="layui-input-block"><input type="text" name="email" required lay-verify="required|email" placeholder="请输入用户邮箱" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">提交修改</button><button type="reset" class="layui-btn layui-btn-primary">重置</button></div></div></form>
    
  2. 在页面底部导入如下的脚本:

        <!-- 导入 layui 的 js --><script src="/assets/lib/layui/layui.all.js"></script><!-- 导入 jquery --><script src="/assets/lib/jquery.js"></script><!-- 导入自己的 js --><script src="/assets/js/user/user_info.js"></script>
    
  3. user_info.js 中编写如下的代码:

    $(function() {var form = layui.formform.verify({nickname: function(value) {if (value.length > 6) {return '昵称长度必须在 1 ~ 6 个字符之间!'}}})
    })
    

2.3 获取用户的基本信息

  1. 导入 baseAPI

    <script src="/assets/js/baseAPI.js"></script>
    
  2. user_info.js 中定义并调用 initUserInfo 函数:

      initUserInfo()// 初始化用户的基本信息function initUserInfo() {$.ajax({method: 'GET',url: '/my/userinfo',success: function(res) {if (res.status !== 0) {return layer.msg('获取用户信息失败!')}console.log(res)}})}
    

2.4 使用form.val方法快速为表单赋值

  1. 为表单指定 lay-filter 属性:

    <form class="layui-form" lay-filter="formUserInfo"></form>
    
  2. 调用 form.val() 方法为表单赋值:

    form.val('formUserInfo', res.data)
    
  3. 使用隐藏域保存用户的 id 值:

    <!-- form 表单区域 -->
    <form class="layui-form" lay-filter="formUserInfo"><!-- 这是隐藏域 --><input type="hidden" name="id" value="" /><!-- 省略其他代码 -->
    </form>
    

2.5 实现表单的重置效果

  1. 阻止表单的默认重置行为,再重新获取用户信息即可:

      // 重置表单的数据$('#btnReset').on('click', function(e) {// 阻止表单的默认重置行为e.preventDefault()initUserInfo()})
    

2.6 发起请求更新用户的信息

  1. 阻止表单的默认提交行为,并发起数据请求:

      // 监听表单的提交事件$('.layui-form').on('submit', function(e) {// 阻止表单的默认提交行为e.preventDefault()// 发起 ajax 数据请求$.ajax({method: 'POST',url: '/my/userinfo',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('更新用户信息失败!')}layer.msg('更新用户信息成功!')// 调用父页面中的方法,重新渲染用户的头像和用户的信息window.parent.getUserInfo()}})})
    
  2. 注意:<iframe> 中的子页面,如果想要调用父页面中的方法,使用 window.parent 即可。

3. 重置密码

3.1 渲染重置密码的页面结构

  1. /user/user_pwd.html 页面中编写如下的结构:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/user/user_pwd.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">修改密码</div><div class="layui-card-body"><form class="layui-form"><div class="layui-form-item"><label class="layui-form-label">原密码</label><div class="layui-input-block"><input type="password" name="oldPwd" required lay-verify="required" placeholder="请输入原密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">新密码</label><div class="layui-input-block"><input type="password" name="newPwd" required lay-verify="required" placeholder="请输入新密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">确认新密码</label><div class="layui-input-block"><input type="password" name="rePwd" required lay-verify="required" placeholder="请再次确认密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">修改密码</button><button type="reset" class="layui-btn layui-btn-primary">重置</button></div></div></form></div></div></body>
    </html>
    
  2. /assets/css/user/user_pwd.css 中编写如下的样式:

    html,
    body {margin: 0;padding: 0;
    }body {padding: 15px;background-color: #f2f3f5;
    }.layui-form {width: 500px;
    }
    

3.2 为密码框定义校验规则

  1. 定义如下的三个校验规则:

    $(function() {var form = layui.formform.verify({pwd: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格'],samePwd: function(value) {if (value === $('[name=oldPwd]').val()) {return '新旧密码不能相同!'}},rePwd: function(value) {if (value !== $('[name=newPwd]').val()) {return '两次密码不一致!'}}})
    })
    
  2. 在 body 结束标签之前导入如下的 script 标签:

    <!-- 导入 layui 的 js -->
    <script src="/assets/lib/layui/layui.all.js"></script>
    <!-- 导入 jQuery -->
    <script src="/assets/lib/jquery.js"></script>
    <!-- 导入 baseAPI -->
    <script src="/assets/js/baseAPI.js"></script>
    <!-- 导入自己的 js -->
    <script src="/assets/js/user/user_pwd.js"></script>
    
  3. 为密码框分别添加对应的校验规则:

    <form class="layui-form"><div class="layui-form-item"><label class="layui-form-label">原密码</label><div class="layui-input-block"><input type="password" name="oldPwd" required lay-verify="required|pwd" placeholder="请输入原密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">新密码</label><div class="layui-input-block"><input type="password" name="newPwd" required lay-verify="required|pwd|samePwd" placeholder="请输入新密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><label class="layui-form-label">确认新密码</label><div class="layui-input-block"><input type="password" name="rePwd" required lay-verify="required|pwd|rePwd" placeholder="请再次确认密码" autocomplete="off" class="layui-input" /></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">修改密码</button><button type="reset" class="layui-btn layui-btn-primary">重置</button></div></div>
    </form>
    

3.3 发起请求实现重置密码的功能

  $('.layui-form').on('submit', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/updatepwd',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layui.layer.msg('更新密码失败!')}layui.layer.msg('更新密码成功!')// 重置表单$('.layui-form')[0].reset()}})})

4. 更换头像

4.1 初步渲染更换头像页面的结构

  1. 创建 /user/user_avatar.html 页面:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/user/user_avatar.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">更换头像</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div></body>
    </html>
  2. 美化基本样式:

    html,
    body {margin: 0;padding: 0;
    }body {padding: 15px;background-color: #f2f3f5;
    }
  3. 修改 index.html 中对应链接的属性:

    <a href="/user/user_avatar.html" target="fm"><i class="layui-icon layui-icon-app"></i>更换头像</a>
    

4.2 实现裁剪区域图片的替换

  // 为文件选择框绑定 change 事件$('#file').on('change', function(e) {// 获取用户选择的文件var filelist = e.target.filesif (filelist.length === 0) {return layer.msg('请选择照片!')}// 1. 拿到用户选择的文件var file = e.target.files[0]// 2. 将文件,转化为路径var imgURL = URL.createObjectURL(file)// 3. 重新初始化裁剪区域$image.cropper('destroy') // 销毁旧的裁剪区域.attr('src', imgURL) // 重新设置图片路径.cropper(options) // 重新初始化裁剪区域})

4.3 将裁剪后的头像上传到服务器

  // 为确定按钮,绑定点击事件$('#btnUpload').on('click', function() {// 1. 要拿到用户裁剪之后的头像var dataURL = $image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 100,height: 100}).toDataURL('image/png') // 将 Canvas 画布上的内容,转化为 base64 格式的字符串// 2. 调用接口,把头像上传到服务器$.ajax({method: 'POST',url: '/my/update/avatar',data: {avatar: dataURL},success: function(res) {if (res.status !== 0) {return layer.msg('更换头像失败!')}layer.msg('更换头像成功!')window.parent.getUserInfo()}})})

4.4 设置头部区域的快捷方式

  1. 打开 index.html,修改头部 个人中心 下的三个快捷方式如下:

    <dl class="layui-nav-child"><dd><a href="/user/user_info.html" target="fm">基本资料</a></dd><dd><a href="/user/user_avatar.html" target="fm">更换头像</a></dd><dd><a href="/user/user_pwd.html" target="fm">重置密码</a></dd>
    </dl>
    

5. 文章分类

5.1 创建并显示文章分类页面

  1. 创建 /article/art_cate.html 页面,并初始化如下的UI结构:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_cate.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header"><span>文章类别管理</span><button type="button" class="layui-btn layui-btn-normal layui-btn-sm">添加类别</button></div><div class="layui-card-body"><table class="layui-table"><colgroup><col /><col /><col width="200" /></colgroup><thead><tr><th>分类名称</th><th>分类别名</th><th>操作</th></tr></thead><tbody><tr><td>贤心</td><td>2016-11-29</td><td>人生就像是一场修行</td></tr><tr><td>许闲心</td><td>2016-11-28</td><td>于千万人之中遇见你所遇见的人,于千万年之中,时间的无涯的荒野里…</td></tr></tbody></table></div></div></body>
    </html>
    
  2. 定义 /assets/css/article/art_cate.css 美化样式:

    html,
    body {margin: 0;padding: 0;
    }body {padding: 15px;background-color: #f2f3f5;
    }.layui-card-header {display: flex;justify-content: space-between;align-items: center;
    }
  3. 修改 index.html 中对应的 <a> 链接:

    <a href="/article/art_cate.html" target="fm"><i class="layui-icon layui-icon-app"></i>文章类别</a>
    

5.2 获取并使用模板引擎渲染表格的数据

  1. 在页面底部导入模板引擎:

    <script src="/assets/lib/template-web.js"></script>
    
  2. 定义模板:

        <!-- 表格数据的模板 --><script type="text/html" id="tpl-table">{{each data}}<tr><td>{{$value.name}}</td><td>{{$value.alias}}</td><td><button type="button" class="layui-btn layui-btn-xs">编辑</button><button type="button" class="layui-btn layui-btn-danger layui-btn-xs">删除</button></td></tr>{{/each}}</script>
    
  3. 发起请求获取数据:

      initArtCateList()// 获取文章分类的列表function initArtCateList() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)}})}
    

5.3 使用layer.open实现弹出层效果

  1. 导入 layer

    var layer = layui.layer
    
  2. 为按钮添加 id 属性:

    <button type="button" class="layui-btn layui-btn-normal layui-btn-sm" id="btnAddCate">添加类别</button>
    
  3. 在按钮的点击事件中,通过 layer.open() 展示弹出层:

      // 为添加类别按钮绑定点击事件$('#btnAddCate').on('click', function() {layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: 'ABC'})})
    

5.4 在弹出层中渲染form表单结构

  1. 在页面中定义如下的 script 标签:

        <script type="text/html" id="dialog-add"><form class="layui-form" id="form-add"><div class="layui-form-item"><label class="layui-form-label">分类名称</label><div class="layui-input-block"><input type="text" name="name" required  lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">分类别名</label><div class="layui-input-block"><input type="text" name="alias" required  lay-verify="required" placeholder="请输入分类别名" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">确认添加</button><button type="reset" class="layui-btn layui-btn-primary">重置</button></div></div></form></script>
    
  2. 通过 content 属性指定内容:

        layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: $('#dialog-add').html()})
    

5.5 实现添加文章分类的功能

  1. 发起Ajax请求:

      // 通过代理的形式,为 form-add 表单绑定 submit 事件$('body').on('submit', '#form-add', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/article/addcates',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('新增分类失败!')}initArtCateList()layer.msg('新增分类成功!')// 根据索引,关闭对应的弹出层layer.close(indexAdd)}})})
    
  2. 预先保存弹出层的索引:

      // 为添加类别按钮绑定点击事件var indexAdd = null$('#btnAddCate').on('click', function() {indexAdd = layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: $('#dialog-add').html()})})
    

1. 文章类别

1.1 点击编辑按钮展示修改文章分类的弹出层

  1. 为编辑按钮添加 btn-edit 类名如下:

    <button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">编辑</button>
    
  2. 定义 修改分类 的弹出层:

    <script type="text/html" id="dialog-edit"><form class="layui-form" id="form-edit" lay-filter="form-edit"><!-- 隐藏域,保存 Id 的值 --><input type="hidden" name="Id"><div class="layui-form-item"><label class="layui-form-label">分类名称</label><div class="layui-input-block"><input type="text" name="name" required  lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">分类别名</label><div class="layui-input-block"><input type="text" name="alias" required  lay-verify="required" placeholder="请输入分类别名" autocomplete="off" class="layui-input"></div></div><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="formDemo">确认修改</button></div></div></form></script>
    
  3. 通过 代理 的形式,为 btn-edit 按钮绑定点击事件:

      var indexEdit = null$('tbody').on('click', '.btn-edit', function() {// 弹出一个修改文章分类信息的层indexEdit = layer.open({type: 1,area: ['500px', '250px'],title: '修改文章分类',content: $('#dialog-edit').html()})})
    

1.2 为修改文章分类的弹出层填充表单数据

  1. 为编辑按钮绑定 data-id 自定义属性:

    <button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">编辑</button>
    
  2. 在展示弹出层之后,根据 id 的值发起请求获取文章分类的数据,并填充到表单中:

    var id = $(this).attr('data-id')
    // 发起请求获取对应分类的数据
    $.ajax({method: 'GET',url: '/my/article/cates/' + id,success: function(res) {form.val('form-edit', res.data)}
    })
    

1.3 更新文章分类的数据

  1. 通过代理的形式,为修改分类的表单绑定 submit 事件:

    $('body').on('submit', '#form-edit', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/article/updatecate',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('更新分类数据失败!')}layer.msg('更新分类数据成功!')layer.close(indexEdit)initArtCateList()}})
    })
    

1.4 删除文章分类

  1. 为删除按钮绑定 btn-delete 类名,并添加 data-id 自定义属性:

    <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
    
  2. 通过代理的形式,为删除按钮绑定点击事件:

    $('tbody').on('click', '.btn-delete', function() {var id = $(this).attr('data-id')// 提示用户是否要删除layer.confirm('确认删除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/deletecate/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('删除分类失败!')}layer.msg('删除分类成功!')layer.close(index)initArtCateList()}})})
    })
    

2. 文章列表

2.1 创建文章列表页面

  1. 新建 /article/art_list.html 页面结构如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_list.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">文章列表</div><div class="layui-card-body"></div></div><!-- 导入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 导入自己的 JS 脚本 --><script src="/assets/js/article/art_list.js"></script></body>
    </html>
  2. 新建 /assets/css/article/art_list.css 样式表如下:

    html,
    body {margin: 0;padding: 0;
    }body {padding: 15px;background-color: #f2f3f5;
    }
    
  3. 新建 /assets/js/article/art_list.js 脚本文件。

2.2 定义查询参数对象q

  1. 定义一个查询的参数对象如下:

      // 定义一个查询的参数对象,将来请求数据的时候,// 需要将请求参数对象提交到服务器var q = {pagenum: 1, // 页码值,默认请求第一页的数据pagesize: 2, // 每页显示几条数据,默认每页显示2条cate_id: '', // 文章分类的 Idstate: '' // 文章的发布状态}
    

2.3 请求文章列表数据并使用模板引擎渲染列表结构

  1. 定义获取文章列表数据的方法如下:

    initTable()  // 获取文章列表数据的方法
    function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('获取文章列表失败!')}// 使用模板引擎渲染页面的数据var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)}})
    }
    
  2. 在页面中添加表格结构如下:

    <!-- 列表区域 -->
    <table class="layui-table"><colgroup><col /><col width="150" /><col width="180" /><col width="150" /><col width="150" /></colgroup><thead><tr><th>文章标题</th><th>分类</th><th>发表时间</th><th>状态</th><th>操作</th></tr></thead><tbody></tbody>
    </table>
    
  3. 定义列表数据的模板结构:

    <script type="text/html" id="tpl-table">{{each data}}<tr><td>{{$value.title}}</td><td>{{$value.cate_name}}</td><td>{{$value.pub_date|dataFormat}}</td><td>{{$value.state}}</td><td><button type="button" class="layui-btn layui-btn-xs">编辑</button><button type="button" class="layui-btn layui-btn-danger layui-btn-xs">删除</button></td></tr>{{/each}}</script>
    

2.4 定义美化时间格式的过滤器

  1. 通过 template.defaults.imports 定义过滤器:

      // 定义美化时间的过滤器template.defaults.imports.dataFormat = function(date) {const dt = new Date(date)var y = dt.getFullYear()var m = padZero(dt.getMonth() + 1)var d = padZero(dt.getDate())var hh = padZero(dt.getHours())var mm = padZero(dt.getMinutes())var ss = padZero(dt.getSeconds())return y + '-' + m + '-' + d + ' ' + hh + ':' + mm + ':' + ss}// 定义补零的函数function padZero(n) {return n > 9 ? n : '0' + n}
    
  2. 在模板引擎中使用过滤器:

    <td>{{$value.pub_date|dataFormat}}</td>
    

2.5 绘制筛选区域的UI结构

  1. 绘制 UI 结构:

    <!-- 筛选区域 -->
    <form class="layui-form" id="form-search"><div class="layui-form-item layui-inline"><select name="cate_id"></select></div><div class="layui-form-item layui-inline"><select name="state"><option value="">所有状态</option><option value="已发布">已发布</option><option value="草稿">草稿</option></select></div><div class="layui-form-item layui-inline"><button class="layui-btn" lay-submit lay-filter="formDemo">筛选</button></div>
    </form>
    

2.6 发起请求获取并渲染文章分类的下拉选择框

  1. 定义 initCate 函数请求文章分类的列表数据:

      initCate()// 初始化文章分类的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('获取分类数据失败!')}// 调用模板引擎渲染分类的可选项var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 通过 layui 重新渲染表单区域的UI结构form.render()}})}
    
  2. 定义分类可选项的模板结构:

    <script type="text/html" id="tpl-cate"><option value="">所有分类</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</script>
    

2.7 实现筛选的功能

  1. 为筛选表单绑定 submit 事件:

    $('#form-search').on('submit', function(e) {e.preventDefault()// 获取表单中选中项的值var cate_id = $('[name=cate_id]').val()var state = $('[name=state]').val()// 为查询参数对象 q 中对应的属性赋值q.cate_id = cate_idq.state = state// 根据最新的筛选条件,重新渲染表格的数据initTable()
    })
    

3. 分页

3.1 定义渲染分页的 renderPage 方法

  1. 定义渲染分页的方法:

    function renderPage(total) {console.log(total)
    }
    
  2. initTable 中调用 renderPage 方法:

    function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('获取文章列表失败!')}// 使用模板引擎渲染页面的数据var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)// 调用渲染分页的方法renderPage(res.total)}})
    }
    

3.2 调用 laypage.render 方法渲染分页的基本结构

  1. 在页面中定义分页的区域:

    <!-- 分页区域 -->
    <div id="pageBox"></div>
    
  2. 调用 laypage.render() 方法来渲染分页的结构:

    // 定义渲染分页的方法
    function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum // 设置默认被选中的分页})
    }
    

3.3 在jump回调函数中通过obj.curr获取到最新的页码值

// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页// 分页发生切换的时候,触发 jump 回调jump: function(obj) {console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr}})
}

3.4 解决 jump 回调函数发生死循环的问题

  // 定义渲染分页的方法function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})}

3.5 自定义分页的功能项

// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})
}

3.6 实现切换每页展示多少条数据的功能

// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 把最新的条目数,赋值到 q 这个查询参数对象的 pagesize 属性中q.pagesize = obj.limit// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})
}

4. 删除文章

4.1 实现删除文章的功能

  1. 为删除按钮绑定 btn-delete 类名和 data-id 自定义属性:

    <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
    
  2. 通过代理的形式,为删除按钮绑定点击事件处理函数:

    $('tbody').on('click', '.btn-delete', function() {// 获取到文章的 idvar id = $(this).attr('data-id')// 询问用户是否要删除数据layer.confirm('确认删除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/delete/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('删除文章失败!')}layer.msg('删除文章成功!')initTable()}})layer.close(index)})
    })
    

4.2 解决删除文章时的小 Bug

$('tbody').on('click', '.btn-delete', function() {// 获取删除按钮的个数var len = $('.btn-delete').length// 获取到文章的 idvar id = $(this).attr('data-id')// 询问用户是否要删除数据layer.confirm('确认删除?', { icon: 3, title: '提示' }, function(index) {$.ajax({method: 'GET',url: '/my/article/delete/' + id,success: function(res) {if (res.status !== 0) {return layer.msg('删除文章失败!')}layer.msg('删除文章成功!')// 当数据删除完成后,需要判断当前这一页中,是否还有剩余的数据// 如果没有剩余的数据了,则让页码值 -1 之后,// 再重新调用 initTable 方法// 4if (len === 1) {// 如果 len 的值等于1,证明删除完毕之后,页面上就没有任何数据了// 页码值最小必须是 1q.pagenum = q.pagenum === 1 ? 1 : q.pagenum - 1}initTable()}})layer.close(index)})
})

5. 发布文章

5.1 创建文章发布页面的基本结构

  1. 新建 /article/art_pub.html 页面结构如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/article/art_pub.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">写文章</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div><!-- 导入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 导入自己的 JS --><script src="/assets/js/article/art_pub.js"></script></body>
    </html>
  2. 新建 /assets/css/article/art_pub.css 样式文件如下:

    html,
    body {margin: 0;padding: 0;
    }body {padding: 15px;background-color: #f2f3f5;
    }
    
  3. 新建 /assets/js/article/art_pub.js 脚本文件如下:

    $(function() { })
    

5.2 新建基本的表单结构

<!-- 发布文章的表单 -->
<form class="layui-form"><div class="layui-form-item"><label class="layui-form-label">文章标题</label><div class="layui-input-block"><input type="text" name="title" required lay-verify="required" placeholder="请输入标题" autocomplete="off" class="layui-input" /></div></div>
</form>

5.3 渲染文章类别对应的下拉选择框结构

  1. 定义 UI 结构:

      <!-- 第二行 --><div class="layui-form-item"><label class="layui-form-label">文章类别</label><div class="layui-input-block"><select name="cate_id" lay-verify="required"></select></div></div>
    
  2. 导入 art-template:

    <script src="/assets/lib/template-web.js"></script>
    
  3. 定义模板结构:

    <script type="text/html" id="tpl-cate"><option value="">请选择文章类别</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</script>
    
  4. 定义 initCate 方法:

    $(function() {var layer = layui.layervar form = layui.forminitCate()// 定义加载文章分类的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('初始化文章分类失败!')}// 调用模板引擎,渲染分类的下拉菜单var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 一定要记得调用 form.render() 方法form.render()}})}
    })
    

5.4 渲染富文本编辑器

参考 素材/富文本和封面.md 中的实现步骤

5.5 渲染封面裁剪区域

参考 素材/富文本和封面.md 中的实现步骤

5.6 渲染提交按钮区域

  <!-- 第五行 --><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn" lay-submit>发布</button><button class="layui-btn layui-btn-primary" lay-submit>存为草稿</button></div></div>

5.7 点击选择封面按钮打开文件选择框

  1. 修改 UI 结构,为 选择封面 按钮添加 id,并且在按钮后面添加 文件选择框

    <!-- 选择封面按钮 -->
    <button type="button" class="layui-btn layui-btn-danger" id="btnChooseImage">选择封面</button>
    <!-- 隐藏的文件选择框 -->
    <input type="file" id="coverFile" style="display: none;" accept="image/png,image/jpeg,image/gif" />
    
  2. 为选择封面的按钮,绑定点击事件处理函数:

    $('#btnChooseImage').on('click', function() {$('#coverFile').click()
    })
    

5.8 将选择的图片设置到裁剪区域中

  1. 监听 coverFilechange 事件,获取用户选择的文件列表:

      // 监听 coverFile 的 change 事件,获取用户选择的文件列表$('#coverFile').on('change', function(e) {// 获取到文件的列表数组var files = e.target.files// 判断用户是否选择了文件if (files.length === 0) {return}// 根据文件,创建对应的 URL 地址var newImgURL = URL.createObjectURL(files[0])// 为裁剪区域重新设置图片$image.cropper('destroy') // 销毁旧的裁剪区域.attr('src', newImgURL) // 重新设置图片路径.cropper(options) // 重新初始化裁剪区域})
    

5.9 分析发布文章的实现步骤

  1. 存为草稿 按钮添加 id 属性:

    <button class="layui-btn layui-btn-primary" lay-submit id="btnSave2">存为草稿</button>
    
  2. 定义文章的发布状态:

    var art_state = '已发布'
    
  3. 为存为草稿按钮,绑定点击事件处理函数:

    $('#btnSave2').on('click', function() {art_state = '草稿'
    })
    

5.10 基于Form表单创建FormData对象

  1. 为发布文章的 Form 表单添加 id 属性:

    <form class="layui-form" id="form-pub"></form>
    
  2. 为表单绑定 submit 提交事件:

      $('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)})
    

5.11 将裁剪后的封面追加到FormData对象中

  // 为表单绑定 submit 提交事件$('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)// 4. 将封面裁剪过后的图片,输出为一个文件对象$image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 400,height: 280}).toBlob(function(blob) {// 将 Canvas 画布上的内容,转化为文件对象// 得到文件对象后,进行后续的操作// 5. 将文件对象,存储到 fd 中fd.append('cover_img', blob)// 6. 发起 ajax 数据请求})})

5.12 发起Ajax请求实现发布文章的功能

  1. 定义一个发布文章的方法:

    function publishArticle(fd) {$.ajax({method: 'POST',url: '/my/article/add',data: fd,// 注意:如果向服务器提交的是 FormData 格式的数据,// 必须添加以下两个配置项contentType: false,processData: false,success: function(res) {if (res.status !== 0) {return layer.msg('发布文章失败!')}layer.msg('发布文章成功!')// 发布文章成功后,跳转到文章列表页面location.href = '/article/art_list.html'}})
    }
    
  2. 把裁剪的图片追加到 FormData 对象中之后,调用 publishArticle 方法:

    // 为表单绑定 submit 提交事件
    $('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)// 4. 将封面裁剪过后的图片,输出为一个文件对象$image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 400,height: 280}).toBlob(function(blob) {// 将 Canvas 画布上的内容,转化为文件对象// 得到文件对象后,进行后续的操作// 5. 将文件对象,存储到 fd 中fd.append('cover_img', blob)// 6. 发起 ajax 数据请求publishArticle(fd)})
    })
    

5.13 将开发完成的项目代码推送到GitHub

  1. 运行 git add . 命令
  2. 运行 git commit -m "完成文章管理相关功能的开发" 命令
  3. 运行 git push -u origin article 命令
  4. 运行 git checkout master 命令
  5. 运行 git merge article 命令
  6. 运行 git push 命令

前端基础第三天项目 大事件后台管理系统相关推荐

  1. 大事件后台管理系统开发实战(下)

    文章目录 续前篇:大事件后台管理系统开发实战(中) 1. 文章类别 1.1 点击编辑按钮展示修改文章分类的弹出层 1.2 为修改文章分类的弹出层填充表单数据 1.3 更新文章分类的数据 1.4 删除文 ...

  2. 大事件后台管理系统开发实战(上)

    文章目录 前言 0. 资源地址 1. 项目前期的准备工作 1.1 初始化项目结构 1.2 使用GitHub管理大事件的项目 1.3 安装VSCode的Live Server插件辅助开发 2. 登录注册 ...

  3. 大事件后台管理系统——个人中心

    1.创建验证规则函数 个人中心--基本资料:用来修改用户信息 针对表单不同类型的数据需要设定验证规则函数,只有输入正确才能提交表单 form.verify({nickname: function(va ...

  4. 大事件后台管理系统——文章管理

    1.文章类别模块 1.1获取文章分类的列表 利用模版引擎快速渲染表格数据 <!-- 表格数据的模板 --><script type="text/html" id= ...

  5. 大事件后台管理系统开发实战(中)

    文章目录 3. 后台主页 3.8 获取用户的基本信息 3.9 渲染用户头像 3.10为有权限的接口统一设置headers请求头 3.11 实现退出功能 3.12 控制用户的访问权限 3.13 优化权限 ...

  6. 第三代半导体项目大事件盘点

    如果说以硅为代表的第一代半导体是集成电路的基石,第二代半导体如砷化镓促成了信息高速公路的崛起的话,那么第三代半导体材料技术正在成为抢占下一代信息技术.节能减排及国防安全制高点的最佳途径之一,是战略性新 ...

  7. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框

    文章目录 目标 代码 0.结构 1.按钮-删除 2.按钮-编辑 3.debug 4.样式 5.分页Pagination:功能 6.分页Pagination:样式 7.搜索框:功能 8.搜索框:样式 总 ...

  8. 【JavaWeb】JavaWeb项目实战——品牌后台管理系统

    JavaWeb项目实战--品牌后台管理系统 项目概述 功能介绍 成果展示 项目实现 使用Maven构建项目 Maven介绍 具体操作 使用Mybatis封装对数据库的操作 在Mysql中建表,并添加数 ...

  9. 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出

    文章目录 目标 代码 0.页面结构 1.新增按钮和弹出表单:结构 2.新增按钮和弹出表单:点击新增弹出表单 3.表单样式 4.表单验证 5.表单的提交和取消功能:接口.mock相关准备 6.表单的提交 ...

最新文章

  1. Fedora 15 安装与配置一览
  2. SQLLite (一)基本介绍
  3. 我们再也看不到“Win 10 破解版下载”
  4. 查询mysql临时表空间_查看临时表空间使用情况
  5. vue中cookie的使用——将cookie放在请求头header中
  6. linux服务器学习笔记:linux忘记密码怎么办?
  7. 连接服务器打印机文件名无效,excel服务器-办公室常识——共享服务器文件报错,共享打印机无法打印的解决办法(解决word、excel不能打印))...
  8. R语言及Rstudio入门小建议(一)
  9. 计算机审计中级培训班,计算机审计中级培训心得体会
  10. 代码编辑器CodeMirror及其简单的配置
  11. excel删除无尽空白行_批量删除空白行其实很简单,这3中方法都能快速搞定,简单易学...
  12. 10015---技术栈
  13. WeWork上演宫斗大戏,这个市还上吗?
  14. 关于外卖骑手被困在算法里的问题解决方法浅析
  15. 7-2 后序+中序序列构造二叉树
  16. java校验商品价格的正则表达式
  17. i html设置为不倾斜,css如何不让字体倾斜?
  18. a15仿生芯片和骁龙8gen1 哪个好
  19. PLC学习第一篇:PLC程序架构
  20. codesign想要访问您的钥匙串中的密钥

热门文章

  1. 目标检测模型——One stage(YOLO v5的模型解析及应用)
  2. 常用遥感卫星数据汇总
  3. 关于能连上网却打不开网页的问题
  4. 复数计算 [(8+6i)*(4+3i)]/[(8+6i)+(4+3i)]= ?
  5. 关于jsp中java代码的使用;
  6. chocolatey 在国内使用
  7. 移动互联网系统架构特点及实践--手机凤凰网
  8. linux服务器校对和手动修改时间
  9. “藤”缠“树”,腾讯安全与青藤云安全发力主机安全
  10. 学习随记三十一——递归实现二叉查找树