10-大事件

资源地址

  1. 线上 DEMO 项目地址:http://www.escook.cn:8086/
  2. 项目的 API 接口地址: https://www.showdoc.cc/escook?page_id=3707158761215217
  3. Layui : https://layui.itze.cn/index.html
  4. 项目的 API 接口文档地址: https://www.showdoc.cc/escook?page_id=3707158761215217

项目前期的准备工作

初始化项目结构

  • 素材 目录下的 assetshome 文件夹,拷贝到 code 目录下
    • assets > css 文件夹 自己编写的css代码
    • assets > fonts 字体图标文件夹
    • assets > images 存放图标文件夹
    • assets > js 自己js代码的文件夹
    • assets > lib 第三方依赖的文件夹
    • home > dashboard.html 后台首页的页面效果
  • code 目录下新建 login.htmlindex.html 页面

使用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.登录注册

1.登录和注册表单的切换

注册单击事件,切换表单点击了对应按钮,让对应的div进行显示,另外一个进行隐藏

  // 1.点击注册,显示注册框,隐藏登录框
  $("#link_reg").on("click", function () {
    $(".reg-box").show();
    $(".login-box").hide();
  });
  // 2.点击登录,显示注登录框,隐藏注册
  $("#link_login").on("click", function () {
    $(".reg-box").hide();
    $(".login-box").show();
  });

2.发起注册用户的Ajax请求

1实现登录表单的验证
  • layui中,默认有帮我们验证表单元素的逻辑

  • 导入 layuijs 文件

  • 为需要验证的表单项添加 lay-verify 属性,同时指定具体的校验规则即可。

  • 并且可以添加多个校验规则,规则名用|隔开

verify()里面要传一个对象,属性名是校验规则名,属性值可以是一个回调函数,也可以是一个数组。
**function(value, item){ }//参数value:表单的值;参数item:表单的DOM对象
**数组的两个值分别代表:[正则匹配、匹配不符时的提示文字]
  // 自定义表单校验规则
  layui.form.verify({
    // 规则的名称:规则定义
    pass: [/^[\S]{6,12}$/, "密码必须6到12位,且不能出现空格"],
    // 判断密码框和确认密码框的值是否一样
    regpwd: function (value, item) {
      var pwd = $("#form_reg input[name='password']").val();
      if (pwd !== value) {
        // value 使用此规则表单的value 的值
        // item 使用此规则表单的元素
        return "两次输入结果不一样";
      }
    },
  });
2.发起注册用户的Ajax请求

查阅接口文档,关注以下几个重点信息

  • 请求URL
  • 请求方式
  • 参数名
  • 响应数据
/* 
3.1)注册表单submit 事件
2).阻止表单默认行为
3)收集表单事件 (使用layui内置的表单验证功能)
4)发送ajax 请求
*/
  $("#form_reg").on("submit", function (e) {
    e.preventDefault();
    console.log($(this).serialize());
    $.ajax({
      method: "post",
      url: "/api/reguser",
      data: $(this).serialize(),
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          //   return alert("注册失败");
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // alert("注册成功");
        layui.layer.msg(res.message, { icon: 6 });
        // 手动点击
        $("#link_login").click();
      },
    });
  });

3.发起登录的Ajax请求

  • 查阅接口文档,关注几个重点要(请求URL,请求方式,请求参数,响应数据)
  • 请求成功之后提示用户,保存token信息到本地存储,跳转到后台主页
token 用来标识用户是否登录的令牌。

后台的页面需要用户登录之后才能查阅,那么权限校验的机制也就出来了,需要检验权限的页面后台先判断请求头里面是否有token,以此来判断是否是登录状态。
  // 登录功能
  $("#form_login").on("submit", function (e) {
    e.preventDefault(); // 阻止跳转
    // 获取表单数据
    var data = $(this).serialize();
    console.log(data);
    // 发送ajax请求
    $.ajax({
      method: "post",
      url: "/api/login",
      data: data,
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          // 不通过时设置 layui.layer的提示信息
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // 保留用户的授权接口信息,后面操作数据时需要用
        // 登录成功之后 ,返回的token数据保存到本地存储中,为以后调用其他接口准备
        localStorage.setItem("token", res.token);
        layui.layer.msg(res.message, { icon: 6 }, function () {
          // 跳转到后台首页
          location.href = "/index.html";
        });
      },
    });
  });
`$.ajax() > ajaxPrefilter过滤器 -> 发送请求给服务器`
  • jQuery.ajaxPrefilter()函数用于指定预先处理Ajax参数选项的回调函数
  • 在所有参数选项被jQuery.ajax()函数处理之前,你可以使用该函数设置的回调函数来预先更改任何参数选项。
$.ajaxPrefilter( function(options){
	// options:(对象)当前AJAX请求的所有参数选项,包含:url、contentType等
 options.url = ''; // 修改ajax请求的地址
});
// 通过ajax的预处理函数,给请求的url拼接根地址
// 发送ajax前进行配置的一些属性,url设置全局改变一处,所有跟随改变
$.ajaxPrefilter(function (options) {
  // 拼接跟地址
  // options ajax发送请求前配置的参数
  options.url = "http://www.liulongbin.top:3007" + options.url;
  // 给有权限的接口,设置请求头
  // 判断当前的请求地址 , 是否需要验证(url 地址中是否包含'/my/')
  if (options.url.indexOf("/my/") !== -1) {
    options.headers = { Authorization: localStorage.getItem("token") };
  }
});

4.提交login分支的代码到GitHub

  • 运行 git add . 命令
  • 运行 git commit -m "完成了登录和注册的功能" 命令
  • 运行 git push -u origin login 命令 (把本地的login分支推送到远程的login分支)
  • 运行 git checkout master 命令(切换到master分支)
  • 运行 git merge login 命令(把本地的login分支合并到master分支)
  • 运行 git push 命令(把本地的master分支推送到远程master分支)
  • 运行 git checkout -b index 命令(创建index分支,用于开发后台index页面)

5.iframe标签

iframe标签的用法
// 1.默认选中首页 layui-this
<li class="layui-nav-item layui-this">
   <a href="/home/dashboard.html" target="fm"> <span class="iconfont icon-home"></span>首页 </a>
</li>

// 2.默认显示首页
<div class="layui-body">
   <!-- 内容主体区域 -->
   <iframe name="fm" src="/home/dashboard.html" frameborder="0"></iframe>
</div>

// 3.去掉动画,隐藏滚动条
.layui-body {
    overflow: hidden;
}

a {
    transition: none !important;
}

6.获取用户基本信息

  • 定义一个 getUserInfo 函数(用来获取用户信息),当页面加载完毕之后调用这个函数
  • 利用 $.ajax() 进行网络请求,查阅文档,获取关键信息
  • 我们请求的时候就需要设置请求头信息,把我们获取到的 token 传递给后台
  • 数据获取失败提示用户
  // 调用获取用户信息的函数
  getUserInfo();

  // 1.封装获取用户信息的函数
  function getUserInfo() {
    $.ajax({
      method: "get",
      url: "/my/userinfo",
      // 设置请求头携带 token 数据
      //   headers: { Authorization: localStorage.getItem("token") },
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        layui.layer.msg(res.message, { icon: 6 });
        // 调用渲染用户信息的函数
        renderAvatar(res.data);
      },
    });
  }

7.渲染用户头像和名称

如果请求成功,我们根据服务器返回的数据来渲染页面

  • 定义 renderAvatar 函数,接收服务器返回的用户数据
  • 获取用户的名称
  • 设置欢迎的文本,找到关键元素进行设置
  • 按需渲染用户的头像,如果用户有头像,那么就直接设置图片头像,如果没有设置文本头像
  // 1.1封装一个渲染用户信息的函数
  function renderAvatar(user) {
    console.log(user);
    // 渲染欢迎语 ,如果有名称就显示名称,没有就显示原来的
    var name = user.nickname || user.username;
    $("#welcome").html(`欢迎 ${name}`);
    // 判断用户是否有头像
    if (user.user_pic) {
      // 隐藏文字框,设置图片的src并显示
      $(".text-avatar").hide();
      $(".layui-nav-img").attr("src", user.user_pic);
    } else {
      // 隐藏头像,设置文字头像的内容大写并显示
      $(".layui-nav-img").hide();
      var first = name[0].toUpperCase();
      $(".text-avatar").html(first);
    }
  }

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

  • baseAPIajaxPrefilter 中添加如下代码
  • 判断url 里面是否携带 /my/
  • 如果携带,那么我们就设置 options.headers
 // 给有权限的接口,设置请求头
  // 判断当前的请求地址 , 是否需要验证(url 地址中是否包含'/my/')
  if (options.url.indexOf("/my/") !== -1) {
    options.headers = { Authorization: localStorage.getItem("token") };
  }

9.实现退出功能

  • 给退出按钮绑定点击事件,取消a标签的默认行为
  • 用户点击后,弹出提示框(layui中有弹出层的相关代码),如果用户点击确认
  • https://www.layui.com/doc/modules/layer.html#layer.confirm
  • 移除本地缓存的 token,并且跳转到登录页面
  // 点击按钮,实现退出功能
  $('#btnLogout').on('click', function() {
    // 提示用户是否确认退出
    layer.confirm('确定退出登录?', { icon: 3, title: '提示' }, function(index) {
      // 1. 清空本地存储中的 token
      localStorage.removeItem('token')
      // 2. 重新跳转到登录页面
      location.href = '/login.html'

      // 关闭 confirm 询问框
      layer.close(index)
    })
  })

10.控制用户的访问权限

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

  // 限制用户的访问权限(未登录直接强制跳转到登录页面)
  // 不论成功还是失败,最终都会调用 complete 回调函数
  options.complete = function (xhr) {
    if (xhr.responseJSON.status == 1 && xhr.responseJSON.message === "身份认证失败!") {
      // 强制清空 token 数据
      localStorage.removeItem("token");
      // 跳转到登录页
      location.href = "/login.html";
    }
  };

11.优化权限控制的代码

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

// 通过ajax的预处理函数,给请求的url拼接根地址
// 发送ajax前进行配置的一些属性,url设置全局改变一处,所有跟随改变
$.ajaxPrefilter(function (options) {
  // 拼接跟地址
  // options ajax发送请求前配置的参数
  options.url = "http://www.liulongbin.top:3007" + options.url;
  // 给有权限的接口,设置请求头
  // 判断当前的请求地址 , 是否需要验证(url 地址中是否包含'/my/')
  if (options.url.indexOf("/my/") !== -1) {
    options.headers = { Authorization: localStorage.getItem("token") };
  }
  // 限制用户的访问权限(未登录直接强制跳转到登录页面)
  options.complete = function (xhr) {
    if (xhr.responseJSON.status === 1 && xhr.responseJSON.message === "身份认证失败!") {
      // 强制清空 token 数据
      localStorage.removeItem("token");
      // 跳转到登录页
      location.href = "/login.html";
    }
  };
});

提交GIT代码

2.基本资料

隐藏的和只读的输入框

// 隐藏的输入框
<input type="hidden" name="id">

// 只读的不能修改值的输入框 readonly(只读) disabled(禁用)
<input type="text" name="username" required disabled  class="layui-input" readonly />

1.获取用户的基本信息

  // 1.获取渲染用户信息
  initUserinfo();
  function initUserinfo() {
    $.ajax({
      method: "get",
      url: "/my/userinfo",
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // 快速为表单赋值
        layui.form.val("formUserInfo", res.data);
      },
    });
  }

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

// 为表单达快速赋值 layui.form.val()
<form class="layui-form" action="" lay-filter="formUserInfo">
</form>

// 为表单达快速赋值 ("表单名称",数据)
layui.form.val("formUserInfo", res.data);

3.发起请求更新用户的信息,验证昵称规则

  // 2.验证昵称规则
  layui.form.verify({
    nickname: function (value) {
      if (value.length > 6) return "昵称的长度不能超过六位";
    },
  });

  // ------------------------------------
  // 2.修改表单的数据
  $(".layui-form").on("submit", function (e) {
    e.preventDefault();
    var data = $(this).serialize();
    // 发起 ajax 数据请求
    $.ajax({
      method: "post",
      url: "/my/userinfo",
      data: data,
      success: function (res) {
        if (res.status != 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }

        layui.layer.msg(res.message, { icon: 6 });
        // 修改完表单数据自动更新欢迎语
        // 调用父页面index.js 中的全局函数getUserInfo
        // user_info.html 和 indexedDB.html 是父子关系,需要调用父类的方法
        // 把index.html 中的获取信息和渲染信息提到全局作用域中
        // 调用父页面中的方法,重新渲染用户的头像和用户的信息
        window.parent.getUserInfo();
      },
    });
  });

注意:<iframe> 中的子页面,如果想要调用父页面中的方法,使用 window.parent 即可。

3.重置密码

1.为密码框定义校验规则

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

  // 验证密码的格式(6-12)
  layui.form.verify({
    pwd: [/^\S{6,12}$/, "密码必须是6到12位非空字符"],

    // 新密码不能和原始密码一样
    samPwd: function (value) {
      var oldPwd = $("input[name=oldPwd]").val().trim();
      console.log(oldPwd);
      if (value === oldPwd) {
        return "新旧密码不能一样";
      }
    },

    // 新密码和确认新密码一致的规则
    rePwd: function (value) {
      var newPwd = $("input[name=newPwd]").val().trim();
      if (newPwd !== value) {
        return "两次密码不一致";
      }
    },
  });

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

  // 修改密码重置
  $(".layui-form").on("submit", function (e) {
    e.preventDefault();
    let data = $(this).serialize();
    $.ajax({
      method: "post",
      url: "/my/updatepwd",
      data: data,
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        layui.layer.msg(res.message, { icon: 6 });
        // 重置表单,reset只能用于DOM元素[0]
        $(".layui-form")[0].reset();
      },
    });
  });

4.更换头像

cropper基本用法.pdf

  • 通过 accept 属性,可以指定,允许用户选择什么类型的文件
// 通过 accept 属性,可以指定,允许用户选择什么类型的文件
<input type="file" id="file" accept="image/png,image/jpeg" />
  • 获取拿到用户选择的文件 e.target.files
function (e)
// 获取用户选择的文件
var filelist = e.target.files;
    
// 拿到用户选择的文件
var file = e.target.files[0];
  • 将文件转化为文件路径 ( URL.createObjectURL )
  • 减少向服务器发送请求次数
var newImgURL = URL.createObjectURL(file)

1.实现裁剪区域图片的替换

实现基本裁剪效果:

  // 1.1 获取裁剪区域的 DOM 元素
  var $image = $('#image')
  // 1.2 配置选项
  const options = {
    // 纵横比
    aspectRatio: 1,
    // 指定预览区域
    preview: '.img-preview'
  }

  // 1.3 创建裁剪区域
  $image.cropper(options)
  • 单击上传按钮弹出文件选择框
  // 单击上传按钮弹出文件选择框
  $("#btnChooseImage").on("click", function () {
    $("#file").click();
  });
  • 为文件选择框绑定 change 事件
  // 为文件选择框绑定 change 事件
  $("#file").on("change", function (e) {
    // 获取用户选择的文件
    var filelist = e.target.files;
    if (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); // 重新初始化裁剪区域
  });

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

将裁剪后的图片,输出为 base64 格式的字符串

文件转base64的网址

  // 为确定按钮,绑定点击事件
  $('#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()
      }
    })
  })

本地代码推送到 Git Hub

  • user 分支推送到 Git Hub 上 git push -u origin user
  • user 分支和 master 合并 git merge user
  • master 推送到 Git Hub 上 git push

5.文章分类

1.获取并使用模板引擎渲染表格的数据(查)

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

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

    <!-- 表格数据的模板 -->
    <script type="text/html" id="tpl-cate">
        {{each data}}
        <tr>
            <td>{{$value.name}}</td>
            <td>{{$value.alias}}</td>
            <td>
                <button type="button" class="layui-btn layui-btn-xs btn-edit" data-id='{{$value.Id}}'>编辑</button>
                <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id='{{$value.Id}}'>删除</button>
            </td>
        </tr>
        {{/each}}
    </script>
  1. 发起请求获取数据:
  //!【1】封装一个获取分类数据的函数,渲染到页面 (查)
  initArtCateList();
  function initArtCateList() {
    $.ajax({
      url: "/my/article/cates",
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        console.log(res);
        // layui.layer.msg(res.message, { icon: 6 });
        // 调用模版
        var htmlStr = template("tpl-cate", res);
        // 数据渲染到页面
        $("tbody").html(htmlStr);
      },
    });
  }

2.点击按钮弹出模态框,添加分类 (增)

  1. 点击按钮弹出模态框
  // 定义全局变量.保存 添加分类 模态框的索引
  var indexAdd;
  $("#btnAddCate").on("click", function () {
    indexAdd = layer.open({
      type: 1,
      title: "类别添加",
      area: ["500px", "300px"],
      // 模版内容拿到设为 content 的值
      content: $("#dialog-add").html(),
    });
  });
  1. 获取表单数据,添加分类
  // 添加分类的表单是通过模态框渲染到页面的
  // 通过事件委托动态给表单祖册 submit 事件
  $("body").on("submit", "#form-add", function (e) {
    e.preventDefault();
    // 获取表单数据
    let data = $(this).serialize();
    console.log(data);
    // 发送ajax请求
    $.ajax({
      method: "post",
      url: "/my/article/addcates",
      data: data,
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // layui.layer.msg(res.message, { icon: 6 });
        // 关闭模态框
        layui.layer.close(indexAdd);
        // 重新渲染页面
        initArtCateList();
      },
    });
  });

3.点击按钮弹出模态框,编辑分类 (改)

  1. 点击按钮弹出模态框,点击事件委托给tbody
  // 定义关闭模态框的索引
  var indexEdit;
  // 1.点击按钮弹出模态框,点击事件委托给tbody
  $("tbody").on("click", ".btn-edit", function () {
    indexEdit = layer.open({
      type: 1,
      title: "类别添加",
      area: ["500px", "300px"],
      // 模版内容拿到设为 content 的值
      content: $("#dialog-edit").html(),
    });
    // 获取分类的id,获取分类的数据
    let id = $(this).attr("data-id");
    // 发送ajax请求渲染页面数据
    $.ajax({
      url: "/my/article/cates/" + id,
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // layui.layer.msg(res.message, { icon: 6 });
        // 给表单赋值(layui中可以一键赋值);(要赋值的表单,数据)
        layui.form.val("form-edit", res.data);
      },
    });
  });
  1. 编辑的表单赋值(事件委托body)
  $("body").on("submit", "#form-edit", function (e) {
    e.preventDefault();
    // 获取表单数据
    let data = $(this).serialize();
    $.ajax({
      method: "post",
      url: "/my/article/updatecate",
      data: data,
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        layui.layer.msg(res.message, { icon: 6 });
        // 关闭模态框
        layui.layer.close(indexEdit);
        // 数据编辑成功重新渲染页面
        initArtCateList();
      },
    });
  });

4.删除分类 (删)

  1. 给删除按钮注册 click 事件,事件委托
  $("body").on("click", ".btn-delete", function () {
    // 获取分类的id,获取分类的数据
    let id = $(this).attr("data-id");
    // 询问是否确定要删除
    layer.confirm("确定要删除?", { icon: 3, title: "提示" }, function (index) {
      $.ajax({
        url: "/my/article/deletecate/" + id,
        success: function (res) {
          if (res.status !== 0) {
            return layui.layer.msg(res.message, { icon: 5 });
          }
          layui.layer.msg(res.message, { icon: 6 });
          // 数据删除成功重新渲染页面
          initArtCateList();
        },
      });
      // 关闭弹框
      layer.close(index);
    });
  });

6.发布文章

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

  1. 获取分类数据(封装一个函数并调用)
  // 1.获取分类数据(封装一个函数并调用)
  initCate();
  function initCate() {
    $.ajax({
      url: "/my/article/cates",
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.status, { icon: 5 });
        }
        // 2.渲染数据到下拉列表
        var htmlStr = template("tpl-cate", res);
        $("select").html(htmlStr); // 更新渲染表单元素(因为是动态插入到页面的)
        // 更新渲染表单元素(因为是动态插入到页面的)
        layui.form.render();
      },
    });
  }
  1. 定义列表数据的模板结构
    <!-- 定义列表数据的模板结构 -->
    <script type="text/html" id="tpl-cate">
        <select name="cate_id" lay-verify="required">
            {{each data }}
            <option value="{{$value.Id}}">{{$value.name}}</option>
            {{/each}}
        </select>
    </script>

2.渲染封面裁剪区域

参考 富文本和封面.pdf

  //! 【2】初始化富文本编辑器
  initEditor();

  //! 【3】 初始化图片裁剪区(插件)
  // 1. 初始化图片裁剪器
  var $image = $("#image");

  // 2. 裁剪选项
  var options = {
    aspectRatio: 400 / 280,
    preview: ".img-preview",
  };

  // 3. 初始化裁剪区域
  $image.cropper(options);

3.更换裁剪区域的图片

  1. 单击"选择封面",弹出文件选择框
  // 1.单击"选择封面",弹出文件选择框
  $("#btnChooseImage").on("click", function () {
    // 隐藏的文件框打开
    $("#coverFile").click();
  });
  1. 监听 coverFilechange 事件,获取用户选择的文件列表:
  // 用户选择了新文件则更换裁剪区
  $("#coverFile").on("change", function () {
    // 获取选中的文件列表
    let fileList = this.files;
    // 判断有没有选择文件
    if (fileList.length <= 0) {
      return "没有选中文件";
    }
    // 获取到选择的文件
    let file = fileList[0];
    // 根据选择的文件,创建一个对应的 URL 地址:
    let newImgURL = URL.createObjectURL(file);
    $image
      .cropper("destroy") // 销毁旧的裁剪区域
      .attr("src", newImgURL) // 重新设置图片路径
      .cropper(options); // 重新初始化裁剪区域
  });

4.定义文章的发布状态

  // 全局变量,保存转态的值
  var state = "已发布";
  $("#btnSave2").on("click", function () {
    state = "草稿";
  });

5.基于Form表单创建FormData对象

  1. 基于Form表单创建FormData对象,绑定submit事件
  $("#form-pub").on("submit", function (e) {
    e.preventDefault();
    // 1.收集数据(FormData对象)
    // var fd = new FormData(form表单dom对象);
    var fd = new FormData(this);
    // 2.追加文章转态的数据
    fd.append("state", state);
    // 3.裁剪封面,转成二进制文件,追加到fd中
    $image
      .cropper("getCroppedCanvas", {
        // 创建一个 Canvas 画布
        width: 400,
        height: 280,
      })
      .toBlob(function (blob) {
        // 将 Canvas 画布上的内容,转化为文件对象
        // 得到文件对象后,进行后续的操作
        // 裁剪完毕后,调用此回调函数,参数blob就是裁剪后的二进制文件
        fd.append("cover_img", blob);
        // fd.forEach(function (value, item) {
        //   console.log(item, value);
        // });
        // 调用发布文章的方法;
        publishArticle(fd);
      });
  });

6.发起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 layui.layer.msg(res.message, { icon: 5 });
        }
        // 提示框关闭后自哦动自动执行此函数
        // 跳转到文章列表
        // 获取父页面index.html中“文章列表”按钮标签
        layui.layer.msg(res.message, { icon: 6 }, function () {
          window.parent.$("#article-list").click();
          // 发布文章成功后,跳转到文章列表页面
          //   location.href = "/article/art_list.html";
        });
      },
    });
  }

7.将开发完成的项目代码推送到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 命令

7.文章列表

1.获取文章数据,展示到页面(查)

  1. 封装一个函数,获取文章数据

  2. 调用函数

    // 定义一个全局变量,保存参数
    var p = {
    pagenum: 1, // 页码值,默认请求第一页的数据
    pagesize: 2, // 每页显示多少条数据
    cate_id: "", // 文章分类的 Id
    state: "", // 文章的状态
  };

  getArticeList();
  function getArticeList() {
    $.ajax({
      url: "/my/article/list",
      data: p,
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        var htmlStr = template("tpl-list", res);
        $("tbody").html(htmlStr);
        renderPage(res.total);
      },
    });
  }
  1. 把文章渲染到页面(模版引擎)
    <!-- 列表模版 -->
    <script type="text/html" id="tpl-list">
        {{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 btn-edit" article_id="{{$value.Id}}">编辑</button>
                <button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
            </td>
        </tr>  
        {{/each}}
    </script>

2.定义过滤器函数,对发布时间进行格式化

  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;
  }

3.根据文章的分类和转态筛选数据

  1. 把所有数据展示到下拉列表中
  initCate();
  function initCate() {
    $.ajax({
      url: "/my/article/cates",
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        var htmlStr = template("tpl-cate", res);
        $("select[name=cate_id]").html(htmlStr);
        layui.form.render();
      },
    });
  }
  1. 给筛选表单,绑定submit提交事件
  $("#form-search").on("submit", function (e) {
    e.preventDefault();
    // 获取分类的id ,获取文章的转态
    var cate_id = $("[name=cate_id]").val();
    var state = $("[name=state]").val();
    // 修改查询参数对象 p
    p.cate_id = cate_id;
    p.state = state;
    // 调用函数获取文章
    getArticeList();
  });

4.渲染分页按钮

  function renderPage(total) {
    layui.laypage.render({
      elem: "pageBox", // 存放按钮的容器,没有#
      count: total, // 数据的总量
      limit: p.pagesize, // 每页显示的条数
      curr: p.pagenum, // 当前是第几页
      // 自定义页面按钮的排版
      layout: ["page", "next", "prev", "count", "limit", "skip"],
      limits: [2, 4, 6, 8, 10], // 每页显示条数的选项
      // 1)当第一次渲染分页按钮时,jump回调函数就会被调用一次
      // 2)当切换分页时,jump 回调函数就会被执行
      jump: function (obj, first) {
        // obj.分页的配置对象,(obj.limit, obj.curr 当前点击的页码)
        // first(true,undefined)
        // 判断一下是否被点击,避免无限循环
        if (!first) {
          // 获取当前的最新页码,更改查询参数,调用函数重新获取文章数据
          p.pagenum = obj.curr;
          // 获取当前最新的每页的条数,更改查询参数,调用函数重新获取文章数据
          p.pagesize = obj.limit;
          getArticeList();
        }
      },
    });
  }

5.删除文章(删)

1.给删除按钮绑定click事件(事件委托)

2.获取文章id

3.询问

4.调接口删除文章

5.重新渲染(判断当前是否在第一页)

  $("tbody").on("click", ".btn-delete", function () {
    var id = $(this).attr("data-id");
    // 单击删除按钮时,统计删除按钮的数量,并保存
    var len = $(".btn-delete").length;
    layer.confirm("是否要删?", { icon: 3, title: "提示" }, function (index) {
      $.ajax({
        url: "/my/article/delete/" + id,
        success: function (res) {
          if (res.status !== 0) {
            return layui.layer.msg(res.message, { icon: 5 });
          }
          layui.layer.msg(res.message, { icon: 6 });
          // 判断一下是否是当前页最后一条数据
          if (len === 1) {
            // 大于一页的时候再减
            p.pagenum > 1 && p.pagenum--;
          }
          getArticeList();
        },
      });
      // 关闭提示框
      layer.close(index);
    });
  });

6.单击编辑按钮跳到编辑页面

  // 1.编辑按钮是动态添加的,用事件委托
  $("tbody").on("click", ".btn-edit", function () {
    // 2.存储文章的id 本地存储
    localStorage.setItem("article_id", $(this).attr("article_id"));
    // 3.跳转到编辑页
    location.href = "/article/art_edit.html";
  });

8.文章编辑

1.页面初始化操作(查)

  1. 分类的下拉列表
  initCate();
  function initCate() {
    // 获取所有分类数据
    $.ajax({
      url: "/my/article/cates",
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        // 渲染数据到下拉列表
        var htmlStr = template("tpl-cate", res);
        // console.log(htmlStr);
        $("select").html(htmlStr);
        // 更新渲染表单元素(因为是动态插入到页面的)
        layui.form.render();
      },
    });
  }
  1. 初始化富文本编辑器

  2. 初始化裁剪区域

  // 2.初始化富文本编辑器
  initEditor();
  // 初始化图片裁剪区(插件)
  // 1. 初始化图片裁剪器
  var $image = $("#image");

  // 2. 裁剪选项
  var options = {
    aspectRatio: 400 / 280,
    preview: ".img-preview",
  };

  // 3. 初始化裁剪区域
  $image.cropper(options);

2.根据id获取文章数据,并渲染到表单中

  geteditData();
  function geteditData() {
    $.ajax({
      url: "/my/article/" + id,
      success: function (res) {
        console.log(res);
        if (res.status !== 0) {
          return layui.layer.msg(res, message, { icon: 5 });
        }

        // 拼接服务器中的图片地址
        $image
          .cropper("destroy") // 销毁旧的裁剪区域
          .attr("src", "http://www.liulongbin.top:3007" + res.data.cover_img) // 重新设置图片路径
          .cropper(options); // 重新初始化裁剪区域
        // 3).给表单赋值(layui中可以一键赋值)
        layui.form.val("form-edit", res.data);
      },
    });
  }

3.获取表单数据,上传服务器

  // 点击选择封面上传文件框打开
  $("#btnChooseImage").on("click", function () {
    $("#coverFile").click();
  });

  // 用户选择了新文件则更换裁剪区
  $("#coverFile").on("change", function () {
    // 获取选中的文件列表
    var fileList = this.files;
    // 判断有没有选择文件
    if (fileList.length <= 0) {
      return layui.layer.msg("请选择文件", { icon: 5 });
    }
    var file = fileList[0];
    // 根据选择的文件,创建一个对应的 URL 地址:
    var newImgURL = URL.createObjectURL(file);
    $image
      .cropper("destroy") // 销毁旧的裁剪区域
      .attr("src", newImgURL) // 重新设置图片路径
      .cropper(options); // 重新初始化裁剪区域
  });

获取数据

  $("#form-edit").on("submit", function (e) {
    e.preventDefault();
    // 收集数据(FormData对象)
    // var fd = new FormData(form表单dom对象);
    var fd = new FormData(this);
    $image
      .cropper("getCroppedCanvas", {
        // 创建一个 Canvas 画布
        width: 400,
        height: 280,
      })
      .toBlob(function (blob) {
        // 将 Canvas 画布上的内容,转化为文件对象
        // 得到文件对象后,进行后续的操作
        // 裁剪完毕后,调用此回调函数,参数blob就是裁剪后的二进制文件
        // 裁剪文章图片,并追加到fd 中
        fd.append("cover_img", blob);
        fd.forEach(function (value, item) {
          console.log(item, value);
        });
        ediltlishArticle(fd);
      });
  });

封装一个调用发布文章的接口

  // 封装一个调用发布文章的接口
  function ediltlishArticle(fd) {
    $.ajax({
      method: "post",
      url: "/my/article/edit",
      data: fd,
      // 数据是FormData对象需要配置两个额外参数
      contentType: false,
      processData: false,
      success: function (res) {
        if (res.status !== 0) {
          return layui.layer.msg(res.message, { icon: 5 });
        }
        layui.layer.msg(res.message, { icon: 6 }, function () {
          // 提示框关闭后自哦动自动执行此函数
          // 跳转到文章列表
          // 获取父页面index.html中“文章列表”按钮标签
          window.parent.document.getElementById("article-list").click();
        });
      },
    });
  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值