本文目录导读:

我来帮您解答如何在PHP中创建看板(Kanban Board)。
PHP看板创建方式
纯PHP后端 + 前端HTML/CSS/JavaScript
<?php
// task_board.php
class KanbanBoard {
private $tasks = [
'todo' => [],
'in_progress' => [],
'done' => []
];
public function addTask($column, $task) {
if (isset($this->tasks[$column])) {
$this->tasks[$column][] = $task;
}
}
public function moveTask($from, $to, $taskIndex) {
if (isset($this->tasks[$from][$taskIndex])) {
$task = $this->tasks[$from][$taskIndex];
unset($this->tasks[$from][$taskIndex]);
$this->tasks[$to][] = $task;
}
}
public function getBoard() {
return $this->tasks;
}
}
$board = new KanbanBoard();
$board->addTask('todo', '开发登录功能');
$board->addTask('todo', '设计数据库');
$board->addTask('in_progress', '编写API文档');
?>
使用PHP框架+Laravel
// 使用Laravel框架
// web.php 路由
Route::get('/kanban', [KanbanController::class, 'index']);
Route::post('/kanban/task', [KanbanController::class, 'store']);
Route::put('/kanban/task/{id}/move', [KanbanController::class, 'move']);
// KanbanController.php
class KanbanController extends Controller {
public function index() {
$tasks = Task::all()->groupBy('status');
return view('kanban.index', compact('tasks'));
}
public function store(Request $request) {
$task = Task::create([
'title' => $request->title,
'status' => 'todo',
'order' => Task::where('status', 'todo')->count() + 1
]);
return response()->json($task);
}
}
完整的前后端示例
<!-- kanban.html -->
<!DOCTYPE html>
<html>
<head>PHP Kanban Board</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
<style>
.kanban-column {
min-height: 400px;
background: #f4f5f7;
border-radius: 3px;
padding: 10px;
}
.task-card {
background: white;
padding: 10px;
margin: 5px 0;
border-radius: 3px;
cursor: pointer;
box-shadow: 0 1px 0 rgba(9,30,66,.25);
}
</style>
</head>
<body>
<div class="container mt-5">
<h2>PHP Kanban Board</h2>
<div class="row">
<div class="col-md-4">
<div class="kanban-column" data-column="todo">
<h5>待办 (Todo)</h5>
<div id="todo-tasks">
<?php foreach($board['todo'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="kanban-column" data-column="in_progress">
<h5>进行中 (In Progress)</h5>
<div id="in_progress-tasks">
<?php foreach($board['in_progress'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="col-md-4">
<div class="kanban-column" data-column="done">
<h5>已完成 (Done)</h5>
<div id="done-tasks">
<?php foreach($board['done'] as $task): ?>
<div class="task-card" draggable="true">
<?php echo $task; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
</div>
<div class="mt-3">
<input type="text" id="new-task" placeholder="输入新任务" class="form-control w-25 d-inline">
<button onclick="addTask()" class="btn btn-primary">添加任务</button>
</div>
</div>
<script>
// 拖拽功能
document.addEventListener('dragstart', function(e) {
if (e.target.classList.contains('task-card')) {
e.dataTransfer.setData('text/plain', e.target.textContent);
e.dataTransfer.setData('source-column', e.target.parentElement.id);
}
});
document.querySelectorAll('.kanban-column').forEach(column => {
column.addEventListener('dragover', function(e) {
e.preventDefault();
});
column.addEventListener('drop', function(e) {
e.preventDefault();
const taskText = e.dataTransfer.getData('text/plain');
const sourceColumn = e.dataTransfer.getData('source-column');
const targetColumn = this.dataset.column;
// PHP Ajax请求更新任务状态
updateTaskStatus(taskText, sourceColumn, targetColumn);
const taskElement = document.createElement('div');
taskElement.className = 'task-card';
taskElement.draggable = true;
taskElement.textContent = taskText;
this.querySelector('div').appendChild(taskElement);
});
});
function addTask() {
const task = document.getElementById('new-task').value;
if (task.trim() !== '') {
// 发送Ajax请求到PHP后端保存任务
fetch('save_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'task=' + encodeURIComponent(task) + '&column=todo'
})
.then(response => response.text())
.then(data => {
const taskElement = document.createElement('div');
taskElement.className = 'task-card';
taskElement.draggable = true;
taskElement.textContent = task;
document.getElementById('todo-tasks').appendChild(taskElement);
document.getElementById('new-task').value = '';
});
}
}
function updateTaskStatus(task, from, to) {
fetch('update_task.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'task=' + encodeURIComponent(task) +
'&from=' + from +
'&to=' + to
});
}
</script>
</body>
</html>
PHP后端API示例
<?php
// save_task.php
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$task = $_POST['task'] ?? '';
$column = $_POST['column'] ?? 'todo';
// 存储到数据库
$db = new PDO('mysql:host=localhost;dbname=kanban', 'root', '');
$stmt = $db->prepare("INSERT INTO tasks (title, status) VALUES (?, ?)");
$stmt->execute([$task, $column]);
echo json_encode(['success' => true, 'id' => $db->lastInsertId()]);
}
?>
数据库表结构
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,VARCHAR(255) NOT NULL,
status ENUM('todo', 'in_progress', 'done') DEFAULT 'todo',
priority INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
推荐工具和库
- Packagist包:
jorelanbo/kanban- PHP看板库 - 前端库: SortableJS + PHP后端
- 全栈方案: Laravel + Vue.js + Dragula
简单实现例子
// 最简单的看板存储方式
$tasks = [
'todo' => ['任务1', '任务2'],
'in_progress' => ['任务3'],
'done' => ['任务4']
];
// 保存到文件
file_put_contents('tasks.json', json_encode($tasks));
// 读取
$tasks = json_decode(file_get_contents('tasks.json'), true);
需要具体的哪一种实现方式,我可以提供更详细的代码示例。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播