TP6简单实现书籍阅读网
- 实现功能
1-登录/注册
2-首页书籍展示
3-指定书籍章节展示
4-指定章节的章节内容展示
- 项目配置
开发环境:phpstudy 版本:8.1.1.3
Phpstudy下载网址:phpStudy-phpStudy下载-php环境集成包-2024最新版
Phpstudy配置信息:
Mysql:5.7.26
Apache:2.4.39
php:7.4.3
PHP框架:ThinkPHP6
前端框架:layui、jQuery
项目所处文件夹:\phpstudy_pro\WWW\novel
- 搭建网站
数据库名字 数据库账号 数据库密码
伪静态:
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /index.php?s=$1 last; break;
}
}
- 配置文件及项目目录
数据库配置文件:\novel\config\database.php
数据库sql文件:\novel\novels.sql
控制器接口:\novel\app\controller\
路由文件:\novel\route\app.php
前端文件:\novel\app\view
首页:\novel\app\view\index\index.html
CSS文件:\novel\public\static\css\
JS文件:\novel\public\static\js
- 代码展示
0.打开TP6的Session,开启TP6的多应用
1.\novel\config\database.php
// 数据库类型
'type' => env('mysql', 'mysql'),
// 服务器地址
'hostname' => env('', '127.0.0.1'),
// 数据库名
'database' => env('', 'novels'),
// 用户名
'username' => env('', 'novels'),
// 密码
'password' => env('', '123456'),
// 端口
'hostport' => env('', '3306'),
2.\novel\route\app.php
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;
Route::rule('doRegister', 'register/doRegister');
Route::rule('doLogin', 'login/doLogin');
Route::rule('logout', 'login/logout');
3.\novel\app\view\index\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>书籍阅读网</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/css/layui.css" />
<link rel="stylesheet" href="/static/css/style.css" />
<script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container">
<div class="header-buttons">
<?php if ($username): ?>
<span>欢迎,<?php echo $username; ?></span>
<a href="/logout">退出</a>
<?php else: ?>
<a href="/login">登录</a>
<a href="/register">注册</a>
<?php endif; ?>
</div>
<h1 class="layui-text-center">红色书籍阅读网</h1>
<div class="novel-list">
<!-- 遍历所有小说 -->
<div class="layui-row layui-col-space15">
<?php if (!empty($novels)): ?>
<?php foreach ($novels as $novel): ?>
<div class="member_item" style="height: auto;">
<div class="member_right">
<a href="<?= url('/chapters', ['novel_id' => $novel['id']]) ?>">
<p class="textoverflow"><?= htmlspecialchars($novel['title']) ?></p>
</a>
<p class="description"><?= htmlspecialchars($novel['description']) ?></p>
<div class="tips">
<span class="date"><?= date('Y-m-d H:i', strtotime($novel['created_at'])) ?></span>
<a href="<?= url('/chapters', ['novel_id' => $novel['id']]) ?>" class="view-chapter">查看章节 ></a>
</div>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<p>当前没有任何小说可供展示。</p>
<?php endif; ?>
</div>
</div>
</div>
</body>
</html>
4.\novel\app\view\Register.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>书籍阅读网 - 用户注册</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/css/style.css" />
<script src="/static/js/layui.js"></script>
<style>
body {
background-color: #f5f5f5;
font-family: '微软雅黑', Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>
</head>
<body>
<div class="container">
<h2 style="text-align: center;">用户注册</h2>
<form class="layui-form" action="" method="POST">
<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" placeholder="请输入邮箱" 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="username" required lay-verify="required" placeholder="请输入用户名" 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="password" required lay-verify="required" placeholder="请输入密码" 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="confirm_password" required lay-verify="required" placeholder="请确认密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn layui-btn-normal" lay-submit lay-filter="formSubmit">注册</button>
</div>
</div>
</form>
<div style="text-align: center;">
<p style="display: flex;justify-content: space-between;">
<a href="/index">返回首页</a>
<span>已有账号?<a href="/login">去登录</a></span>
</p>
</div>
</div>
<script>
layui.use('form', function() {
var form = layui.form;
form.on('submit(formSubmit)', function(data){
$.ajax({
url: '/doRegister', // 后端接口地址
type: 'POST',
data: data.field, // 表单数据
success: function(response) {
if(response.status === "error"){
alert(response.message);
}else{
alert(response.message);
window.location.href = "/login"
}
},
error: function(error) {
console.error(error); // 错误信息
alert('提交失败');
}
});
return false; // 阻止表单默认提交
});
});
</script>
</body>
</html>
5.\novel\app\view\Login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>书籍阅读网 - 用户登录</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/css/style.css" />
<script src="/static/js/layui.js"></script>
<style>
body {
background-color: #f5f5f5;
font-family: '微软雅黑', Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>
</head>
<body>
<div class="container">
<h2 style="text-align: center;">用户登录</h2>
<form class="layui-form" action="/doLogin" method="POST">
<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="请输入用户名" 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="password" required lay-verify="required" placeholder="请输入密码" class="layui-input">
</div>
</div>
<p style="color: red;"><?php echo $error ?></p>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn layui-btn-normal">登录</button>
</div>
</div>
</form>
<div style="text-align: center;">
<p style="display: flex;justify-content: space-between;">
<a href="/index">返回首页</a>
<span>没有账号?<a href="/register">去注册</a></span>
</p>
</div>
</div>
</body>
</html>
6.\novel\app\view\chapters.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>书籍阅读网</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/css/layui.css" />
<link rel="stylesheet" href="/static/css/style.css" />
<script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container" style="position: relative;">
<a href="index">首页</a>
<div class="header-buttons">
<?php if ($username): ?>
<span>欢迎,<?php echo $username; ?></span>
<a href="/logout">退出</a>
<?php else: ?>
<a href="/login">登录</a>
<a href="/register">注册</a>
<?php endif; ?>
</div>
<h2 class="layui-text-center"><?php print_r($novel['title']) ?></h2>
<div class="novel-list">
<!-- 这本小说所有的章节 -->
<div class="layui-row layui-col-space15">
<?php if (!empty($chapters)): ?>
<div class="chapters_item" style="height: auto;">
<?php foreach ($chapters as $chapter): ?>
<div class="member_right">
<a href="<?= url('/show', ['novel_id' => $novel['id'],'chapter_id' => $chapter['id']]) ?>">
<p class="textoverflow"><?= htmlspecialchars($chapter['chapter_title']) ?></p>
</a>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<p>当前没有任何章节可供展示。</p>
<?php endif; ?>
</div>
</div>
</div>
</body>
</html>
7.\novel\app\view\show.html
<?php
// 当前章节ID为 currentChapterId,最大章节ID为 maxChapterId,最小章节ID为 maxChapterId
$currentChapterId = $content[0]['id'];
$prevChapterId = ($currentChapterId > $minChapterId) ? $currentChapterId - 1 : null;
$nextChapterId = ($currentChapterId < $maxChapterId) ? $currentChapterId + 1 : null;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>书籍阅读网</title>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="/static/css/layui.css" />
<link rel="stylesheet" href="/static/css/style.css" />
<script src="/static/js/layui.js"></script>
</head>
<body>
<div class="layui-container" style="position: relative;">
<a href="<?= url('/chapters', ['novel_id' => $novelId]) ?>">返回章节</a>
<div class="header-buttons">
<?php if ($username): ?>
<span>欢迎,<?php echo $username; ?></span>
<a href="/logout">退出</a>
<?php else: ?>
<a href="/login">登录</a>
<a href="/register">注册</a>
<?php endif; ?>
</div>
<?php if (!empty($content) && isset($content[0])): ?>
<h3 class="layui-text-center"><?= htmlspecialchars($content[0]['chapter_title']) ?></h3>
<!-- 上一章和下一章按钮 -->
<div class="chapter-navigation">
<?php if ($prevChapterId): ?>
<a href="<?= url('/show', ['novel_id' => $novelId, 'chapter_id' => $prevChapterId]) ?>">上一章</a>
<?php else: ?>
<a href="#" class="disabled">上一章</a>
<?php endif; ?>
<?php if ($nextChapterId): ?>
<a href="<?= url('/show', ['novel_id' => $novelId, 'chapter_id' => $nextChapterId]) ?>">下一章</a>
<?php else: ?>
<a href="#" class="disabled">下一章</a>
<?php endif; ?>
</div>
<div class="novel-list">
<div class="layui-con layui-col-space15" style="">
<div class="chapters_item" style="height: auto;">
<p class="textoverflow"><?= htmlspecialchars($content[0]['content']) ?></p>
</div>
</div>
</div>
<?php else: ?>
<p>当前没有任何内容可供展示。</p>
<?php endif; ?>
</div>
</body>
</html>
<style>
.disabled {
color: #ccc;
pointer-events: none;
text-decoration: none;
}
</style>
8.\novel\app\controller\Index.php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;
class Index extends BaseController
{
// 显示小说首页
public function index()
{
// 获取所有小说列表
$novels = Db::name('novels')->select();
$username = Session::get('username');
return View::fetch('index', ['username' => $username,'novels' => $novels]);
}
}
9.\novel\app\controller\register.php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
class register extends BaseController
{
public function index()
{
return View::fetch('/register');
}
// 处理注册请求
public function doRegister()
{
// 获取表单数据
$email = Request::post('email');
$username = Request::post('username');
$password = Request::post('password');
$confirm_password = Request::post('confirm_password');
// 表单验证
if (empty($email) || empty($username) || empty($password) || empty($confirm_password)) {
return json(['status' => 'error', 'message' => '所有字段都不能为空']);
}
if ($password !== $confirm_password) {
return json(['status' => 'error', 'message' => '密码和确认密码不匹配']);
}
// 检查用户名或邮箱是否已存在
$existingUser = Db::name('users')->where('username', $username)->find();
if ($existingUser) {
return json(['status' => 'error', 'message' => '用户名已存在']);
}
$existingEmail = Db::name('users')->where('email', $email)->find();
if ($existingEmail) {
return json(['status' => 'error', 'message' => '邮箱已注册']);
}
// 插入用户信息到数据库
try {
$result = Db::name('users')->insert([
'username' => $username,
'password' => $password,
'email' => $email
]);
if ($result) {
return json(['status' => 'success', 'message' => '注册成功']);
} else {
return json(['status' => 'error', 'message' => '注册失败,请稍后重试']);
}
} catch (\Exception $e) {
return json(['status' => 'error', 'message' => '系统错误: ' . $e->getMessage()]);
}
}
}
10.\novel\app\controller\login.php
<?php
namespace app\controller;
use app\BaseController;
// 添加引用
use think\facade\Session;
use think\facade\View;
use think\facade\Request;
use think\facade\Db;
class login extends BaseController
{
public function index()
{
return View::fetch('/login', ['error' => '']);
}
// 处理登录请求
public function doLogin()
{
$username = Request::param('username');
$password = Request::param('password');
//验证用户
$user = Db::name('users')->where('username', $username)->where('password', $password)->find();
if ($user) {
// 登录成功:保存用户信息到 Session
Session::set('userid', $user['id']);
Session::set('username', $user['username']);
// 重定向到首页
return redirect((string) url('/',['username' => $user['username']]));
} else {
// 登录失败:返回错误信息
return View::fetch('/login', ['error' => '用户名或密码错误']);
}
}
public function logout()
{
Session::delete('userid');
Session::delete('username');
return redirect('/');
}
}
11.\novel\app\controller\chapters.php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;
class chapters extends BaseController
{
// 显示小说首页
public function index()
{
// 获取该小说章节
$novelId = input('novel_id');
$chapters = Db::name('chapters')->where('novel_id',$novelId)->select();
// 获取小说的详细信息(如果需要展示)
$novel = Db::name('novels')->where('id', $novelId)->find();
$username = Session::get('username');
return View::fetch('/chapters', [
'username' => $username,
'novel' => $novel,
'chapters' => $chapters
]);
}
}
12.\novel\app\controller\show.php
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Db;
use think\facade\Session;
use think\facade\View;
class show extends BaseController
{
// 显示小说首页
public function index()
{
// 获取该小说章节
$novelId = input('novel_id');
$chapter_id = input('chapter_id');
$content = Db::name('chapters')->where('novel_id',$novelId)->where('id',$chapter_id)->select();
$maxChapterId = Db::name('chapters')->where('novel_id', $novelId)->max('id');
$minChapterId = Db::name('chapters')->where('novel_id', $novelId)->min('id');
$username = Session::get('username');
// 获取小说的详细信息(如果需要展示)
return View::fetch('/show', [
'username' => $username,
'novelId' => $novelId,
'content' => $content,
'maxChapterId' => $maxChapterId,
'minChapterId' => $minChapterId
]);
}
}
13.\novel\novels.sql
CREATE DATABASE novel_site;
USE novel_site;
-- 用户表
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) NOT NULL
);
-- 小说表
CREATE TABLE novels (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
author VARCHAR(50),
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 小说章节表
CREATE TABLE chapters (
id INT AUTO_INCREMENT PRIMARY KEY,
novel_id INT NOT NULL,
chapter_title VARCHAR(100) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (novel_id) REFERENCES novels(id) ON DELETE CASCADE
);
14.\novel\public\static\css\style.css
body {
background-color: #f2f2f2; /* 浅灰色背景 */
font-family: "微软雅黑", Arial, sans-serif;
color: #333;
}
.layui-container {
background-color: white;
min-height: 100vh; /* 最小高度 100% 的视口高度 */
height: auto;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
background-image: url('/static/img/dq1.jpg');
background-repeat: no-repeat; /* 防止背景图重复 */
}
/* 红色主题标题 */
h1.layui-text-center {
color: black; /* 红色标题 */
font-size: 2.5rem;
font-weight: bold;
text-align: center;
}
h2.layui-text-center {
color: black;
font-size: 2rem;
font-weight: bold;
text-align: center;
}
h3.layui-text-center {
color: black;
font-size: 1.5rem;
font-weight: bold;
text-align: center;
}
/* 小说列表的样式 */
.novel-list .layui-row {
margin-top: 20px;
}
.member_item {
border: 1px solid #d90000; /* 红色边框 */
border-radius: 10px;
margin-bottom: 15px;
padding: 15px;
display: flex;
align-items: center;
height: auto;
transition: transform 0.3s ease;
}
.member_item:hover {
transform: translateY(-5px); /* 鼠标悬停时上移 */
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}
.member_right {
flex: 1;
}
.member_right a {
text-decoration: none;
color: #d90000; /* 红色链接 */
}
.member_right p.textoverflow {
font-size: 1.2rem;
font-weight: bold;
color: black; /* 红色标题 */
margin-bottom: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.description {
color: #666;
font-size: 1rem;
margin-bottom: 15px;
}
.tips {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: #888;
}
.tips .date {
color: #999;
}
.tips .view-chapter {
color: #777777; /* 红色按钮 */
font-weight: bold;
}
.view-chapter:hover {
text-decoration: underline;
}
/* 样式调整 - 页面底部和响应式布局 */
.layui-row {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.member_item {
flex: 0 0 48%; /* 每行两个项目 */
margin-bottom: 20px;
}
.member_item:nth-child(2n) {
margin-right: 0;
}
.header-buttons {
position: absolute;
top: 20px;
right: 20px;
}
.header-buttons a {
margin-left: 15px;
padding: 10px 20px;
color: black;
text-decoration: none;
border-radius: 5px;
font-size: 1rem;
}
@media (max-width: 768px) {
.member_item {
flex: 0 0 100%; /* 小屏幕时每行一个项目 */
}
}
/*登录注册*/
.container {
background-color: #fff;
border-radius: 8px;
padding: 30px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 400px;
}
h2 {
color: #d90000;
font-size: 1.8rem;
margin-bottom: 20px;
}
.layui-form-item {
margin-bottom: 20px;
}
.layui-form-label {
width: 90px;
text-align: right;
font-weight: bold;
}
.layui-input {
border-radius: 5px;
padding: 10px;
border: 1px solid #ddd;
width: 100%;
font-size: 1rem;
box-sizing: border-box;
}
.layui-btn {
background-color: #d90000;
color: white;
border: none;
border-radius: 5px;
padding: 10px 20px;
width: 100%;
font-size: 1.2rem;
}
.layui-btn:hover {
background-color: #b30000;
}
.layui-form-item .layui-input-block {
display: flex;
justify-content: center;
}
/* 其他文字样式 */
.container p {
font-size: 1rem;
color: #666;
}
.container a {
color: #d90000;
text-decoration: none;
}
.container a:hover {
text-decoration: underline;
}
/* 响应式设计 */
@media (max-width: 768px) {
.container {
width: 90%;
padding: 20px;
}
}
.chapters_item{
flex: 0 0 48%; /* 每行两个项目 */
background-color: #fff;
border: 1px solid #d90000; /* 红色边框 */
border-radius: 10px;
margin-bottom: 15px;
padding: 15px;
transition: transform 0.3s ease;
}
.layui-con{
margin-top: 20px;
}
.layui-con p {
text-indent: 2em;
}
.chapter-navigation{
margin-top: 2%;
display: flex;
justify-content: space-around;
}
一个很简单的书籍阅览网站就做好了,以后还可以添加用户评论、收藏、浏览数、追读人数等功能。
完结撒花。