五、删除文章
1、实现删除文章的功能
为删除按钮绑定 btn-delete
类名和 data-id
自定义属性
html 结构( /article/art_list.html )
<button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
通过代理的形式,为删除按钮绑定点击事件处理函数
- 弹出确认取消框提示用户
- 用户点击确认,发送请求,删除当前文章,携带文章
id
- 请求成功之后,获取最新的文章列表信息
- 关闭当前弹出层
js 代码( /assets/js/article/art_list.js )
$('tbody').on('click', '.btn-delete', function() { // 获取到文章的 id var 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) }) })
2、解决删除文章时的小 Bug
问题:删除后,页码值虽然正常,但是当前页码的数据没有渲染出来
解决:
- 判断删除后,页面上是否还有数据
- 判断当前页面的删除按钮的长度是否等于1
- 如果等于1,那么我们让当前页码-1即可,如果不等于1,不用处理
js 代码( /assets/js/article/art_list.js )
$('tbody').on('click', '.btn-delete', function() { // 获取删除按钮的个数 var len = $('.btn-delete').length // 获取到文章的 id var 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 方法 // 4 if (len === 1) { // 如果 len 的值等于1,证明删除完毕之后,页面上就没有任何数据了 // 页码值最小必须是 1 q.pagenum = q.pagenum === 1 ? 1 : q.pagenum - 1 } initTable() } }) layer.close(index) }) })
六、发布文章
1、创建文章发布页面的基本结构
新建 /article/art_pub.html
页面结构
利用卡片区域进行结构布局
html 结构( /article/art_pub.html )
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <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> </body> <script src="/assets/lib/layui/layui.all.js"></script> <script src="/assets/lib/jquery.js"></script> <script src="/assets/js/baseAPI.js"></script> <script src="/assets/js/article/art_pub.js"></script> </html>
新建 /assets/css/article/art_pub.css
样式文件
css 样式( /assets/css/article/art_pub.css )
html, body { margin: 0; padding: 0; } body { padding: 15px; background-color: #f2f3f5; }
新建 /assets/js/article/art_pub.js
脚本文件
2、新建基本的表单结构
自上而下 文章标题 → 文章类别 → 文章内容 → 文章封面 → 表单操作按钮
html 结构( /article/art_pub.html )
<!-- 发布文章的表单 --> <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>
3、渲染文章类别对应的下拉选择框结构
第二行右侧内容应该是下拉选择框 select
,必填项,里面的内容是动态进行获取的
html 结构( /article/art_pub.html )
<!-- 第二行 --> <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>
导入 art-template
html 结构( /article/art_pub.html )
<script src="/assets/lib/template-web.js"></script>
定义模板结构,多个条目,利用列表渲染
html 结构( /article/art_pub.html )
<script type="text/html" id="tpl-cate"> <option value="">请选择文章类别</option> {{each data}} <option value="{{$value.Id}}">{{$value.name}}</option> {{/each}} </script>
定义 initCate
方法,请求文章类别的列表,利用模板引擎渲染到页面
js 代码( /assets/js/article/art_pub.js )
$(function() { const form = layui.form; const layer = layui.layer; // 获取文章分类 const initCate = () => { $.ajax({ type: "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(); }, }); }; initCate(); })
4、渲染富文本编辑器
添加如下的 layui
表单行
html 结构( /article/art_pub.html )
<div class="layui-form-item"> <!-- 左侧的 label --> <label class="layui-form-label">文章内容</label> <!-- 为富文本编辑器外部的容器设置高度 --> <div class="layui-input-block" style="height: 400px;"> <!-- 重要:将来这个 textarea 会被初始化为富文本编辑器 --> <textarea name="content"></textarea> </div> </div>
导入富文本必须的 script
脚本
html 结构( /article/art_pub.html )
<!-- 富文本 --> <script src="/assets/lib/tinymce/tinymce.min.js"></script> <script src="/assets/lib/tinymce/tinymce_setup.js"></script>
调用 initEditor()
方法,初始化富文本编辑器
js 代码( /assets/js/article/art_pub.js )
// 初始化富文本编辑器 initEditor()
5、渲染封面裁剪区域
在 <head>
中导入 cropper.css
样式表
html 结构( /article/art_pub.html )
<link rel="stylesheet" href="/assets/lib/cropper/cropper.css" />
在 <body>
的结束标签之前,按顺序导入如下的 js
脚本
html 结构( /article/art_pub.html )
<script src="/assets/lib/jquery.js"></script> <script src="/assets/lib/cropper/Cropper.js"></script> <script src="/assets/lib/cropper/jquery-cropper.js"></script>
在表单中,添加如下的表单行结构
html 结构( /article/art_pub.html )
<div class="layui-form-item"> <!-- 左侧的 label --> <label class="layui-form-label">文章封面</label> <!-- 选择封面区域 --> <div class="layui-input-block cover-box"> <!-- 左侧裁剪区域 --> <div class="cover-left"> <img id="image" src="/assets/images/sample2.jpg" alt="" /> </div> <!-- 右侧预览区域和选择封面区域 --> <div class="cover-right"> <!-- 预览的区域 --> <div class="img-preview"></div> <!-- 选择封面按钮 --> <button type="button" class="layui-btn layui-btn-danger">选择封面</button> </div> </div> </div>
美化的样式
css 样式( /assets/css/article/art_pub.css )
/* 封面容器的样式 */ .cover-box { display: flex; } /* 左侧裁剪区域的样式 */ .cover-left { width: 400px; height: 280px; overflow: hidden; margin-right: 20px; } /* 右侧盒子的样式 */ .cover-right { display: flex; flex-direction: column; align-items: center; } /* 预览区域的样式 */ .img-preview { width: 200px; height: 140px; background-color: #ccc; margin-bottom: 20px; overflow: hidden; }
实现基本裁剪效果
js 代码( /assets/js/article/art_pub.js )
// 1. 初始化图片裁剪器 var $image = $('#image') // 2. 裁剪选项 var options = { aspectRatio: 400 / 280, preview: '.img-preview' } // 3. 初始化裁剪区域 $image.cropper(options)
6、渲染提交按钮区域
html 结构( /article/art_pub.html )
<!-- 第五行 --> <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>
7、点击选择封面按钮打开文件选择框
修改 UI
结构,为 选择封面 按钮添加 id
,并且在按钮后面添加 文件选择框
html 结构( /article/art_pub.html )
<!-- 选择封面按钮 --> <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" />
为选择封面的按钮,绑定点击事件处理函数
js 代码( /assets/js/article/art_pub.js )
$('#btnChooseImage').on('click', function() { $('#coverFile').click() })
8、将选择的图片设置到裁剪区域中
- 监听
coverFile
的change
事件,获取用户选择的文件列表 - 跟进文件,创建对应的 URL 地址
- 为裁剪区域重新设置图片
- 销毁旧的裁剪区域
- 重新设置图片路径
- 重新初始化裁剪区域
js 代码( /assets/js/article/art_pub.js )
// 监听 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) // 重新初始化裁剪区域 })
9、分析发布文章的实现步骤
为 存为草稿 按钮添加 id
属性
html 结构( /article/art_pub.html )
<button class="layui-btn layui-btn-primary" lay-submit id="btnSave2"> 存为草稿 </button>
定义文章的发布状态
js 代码( /assets/js/article/art_pub.js )
let art_state = '已发布'
为存为草稿按钮,绑定点击事件处理函数
js 代码( /assets/js/article/art_pub.js )
$('#btnSave2').on('click', function() { art_state = '草稿' })
10、基于Form
表单创建FormData
对象
为发布文章的 Form 表单添加 id
属性
html 结构( /article/art_pub.html )
<form class="layui-form" id="form-pub"></form>
为表单绑定 submit
提交事件
- 阻止表单默认提交行为
- 基于
form
表单,快速创建一个FormData
对象 - 将文章的发布状态,存到
FormData
对象中
js 代码( /assets/js/article/art_pub.js )
$('#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) })
11、将裁剪后的封面追加到FormData
对象中
- 将裁剪后的图片输出成一个文件
- 把文件追加到
formData
中即可
js 代码( /assets/js/article/art_pub.js )
// 为表单绑定 submit 提交事件 $('#form-pub').on('submit', function(e) { ... // 4. 将封面裁剪过后的图片,输出为一个文件对象 $image .cropper('getCroppedCanvas', { // 创建一个 Canvas 画布 width: 400, height: 280 }) .toBlob(function(blob) { // 将 Canvas 画布上的内容,转化为文件对象 // 得到文件对象后,进行后续的操作 // 5. 将文件对象,存储到 fd 中 fd.append('cover_img', blob) // 6. 发起 ajax 数据请求 }) })
12、发起Ajax
请求实现发布文章的功能
- 定义一个发布文章的方法
- 注意:如果是提交的是
FormData
格式数据,需要添加contentType:false ,processData:false
js 代码( /assets/js/article/art_pub.js )
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' } }) }
把裁剪的图片追加到 FormData
对象中之后,调用 publishArticle
方法
js 代码( /assets/js/article/art_pub.js )
// 为表单绑定 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) }) })
13、将开发完成的项目代码推送到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成文章管理相关功能的开发"
命令 - 运行
git push -u origin article
命令 - 运行
git checkout master
命令 - 运行
git merge article
命令 - 运行
git push
命令