在 admin
目录下新建一个 post-delete.php
文件,专门处理文章的删除业务。
<!-- 约定这个页面处理两种类型的删除业务:
1if (!empty($_GET['id'])) {
2 // 接收到要删除的 ID
3}
1$sql = sprintf('delete from posts where id = %d', $_GET['id']);
提示:如果需要做软删除可以通过将指定文章的状态设置为
trashed
1$sql = sprintf("update posts set status='trashed' where id = %d", $items);
由于之前封装的 xiu_query()
函数只适用于查询操作,对于增删改一类非查询的操作还是需要重新封装一个函数,具体代码如下:
1/**
2 * 执行一个非查询语句,返回执行语句后受影响的行数
3 * @param string $sql 非查询语句
4 * @return integer 受影响的行数
5 */
6function xiu_execute ($sql) {
7 // 获取与数据库之间的连接
8 $connection = xiu_connect();
9
10 // 执行 SQL 语句,获取一个查询对象
11 if ($result = mysqli_query($connection, $sql)) {
12 // 查询成功,获取执行语句后受影响的行数
13 $affected_rows = mysqli_affected_rows($connection);
14 }
15
16 // 关闭数据库连接
17 mysqli_close($connection);
18
19 // 返回受影响的行数
20 return isset($affected_rows) ? $affected_rows : 0;
21}
xiu_execute()
函数执行 SQL 语句 1if (!empty($_GET['id'])) {
2 // 拼接 SQL 并执行
3 xiu_execute(sprintf('delete from posts where id = %d', $_GET['id']));
4}
post.php
1<td class="text-center">
2 <a href="javascript:;" class="btn btn-default btn-xs">编辑</a>
3 <a href="/admin/post-delete.php?id=<?php echo $item['id']; ?>" class="btn btn-danger btn-xs">删除</a>
4</td>
🚩 源代码: step-34
目前这种情况,用户在点击删除链接删除指定内容后,需要手动返回到之前的页面,体验不佳,最好是能在 post-delete.php
执行完成过后,自动跳转到之前访问的页面,也就是来源页面。
那么如何获取来源页面的地址,就是我们接下来的重点:
在 HTTP 协议中约定:在请求头中包含一个 Referer
字段,值就是上一次访问的 URL
在 PHP 中可以通过 $_SERVER['HTTP_REFERER']
获取到 Referer
1// 获取删除后跳转到的目标链接,优先跳转到来源页面,否则跳转到文章列表
2$target = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'posts.php';
3// 跳转
4header('Location: ' . $target);
🚩 源代码: step-35
post-delete.php
支持批量删除目前 post-delete.php
只能删除指定的单个数据,如果需要支持批量删除,可以稍加改造:
id
参数是一个以英文半角逗号分隔的 IDwhere
子句改为 where id in (%s)
1// $id => 22 / 22,23,24
2xiu_execute(sprintf('delete from posts where id in (%s)', $_GET['id']));
3// $sql => delete from posts where id in (22)
4// $sql => delete from posts where id in (22,23,24)
🚩 源代码: step-36
对于界面功能需求,可以通过 JavaScript 实现,具体逻辑如下:
以下是我提供的一种实现,在页面中加入一段 JavaScript 完成上述逻辑:
1// 获取所需操作的界面元素
2var $btnDelete = $('.btn-delete')
3var $tdCheckbox = $('td > input[type=checkbox]')
4
5// 用于记录界面上选中行的数据 ID
6var checked = []
7
8/**
9 * 表格中的复选框选中发生改变时控制删除按钮的链接参数和显示状态
10 */
11$tdCheckbox.on('change', function () {
12 var $this = $(this)
13
14 // 为了可以在这里获取到当前行对应的数据 ID
15 // 在服务端渲染 HTML 时,给每一个 tr 添加 data-id 属性,记录数据 ID
16 // 这里通过 data-id 属性获取到对应的数据 ID
17 var id = parseInt($this.parent().parent().data('id'))
18
19 // ID 如果不合理就忽略
20 if (!id) return
21
22 if ($this.prop('checked')) {
23 // 选中就追加到数组中
24 checked.push(id)
25 } else {
26 // 未选中就从数组中移除
27 checked.splice(checked.indexOf(id), 1)
28 }
29
30 // 有选中就显示操作按钮,没选中就隐藏
31 checked.length ? $btnDelete.fadeIn() : $btnDelete.fadeOut()
32
33 // 批量删除按钮链接参数
34 // search 是 DOM 标准属性,用于设置或获取到的是 a 链接的查询字符串
35 $btnDelete.prop('search', '?id=' + checked.join(','))
36})
1/**
2 * 全选 / 全不选
3 */
4$thCheckbox.on('change', function () {
5 var checked = $(this).prop('checked')
6 // 设置每一行的选中状态并触发 上面 👆 的事件
7 $tdCheckbox.prop('checked', checked).trigger('change')
8})
🚩 源代码: step-37
✏️ 作业: 完成上述功能模块的实现,思考如何改进上述功能的体验?