PHP+JS+CSS+JSON 单页新闻系统实现方案

PHP+JS+CSS+JSON 单页新闻系统实现方案

下面我将为您实现一个单页新闻系统,包含以下功能:

  • 使用JSON存储新闻数据
  • 支持翻页功能
  • 兼容IIS和宝塔伪静态
  • 每个新闻页面独立URL

目录结构

bash 复制代码
/news-system/
│── /data/
│   └── news.json          # 存储所有新闻数据
│── /news/
│   └── {id}.html          # 独立新闻页面
├── index.php              # 首页
├── api.php                # 新闻API接口
├── style.css              # 样式文件
└── script.js              # 前端交互

1. 新闻数据存储 (news.json)

json 复制代码
{
  "total": 2,
  "per_page": 5,
  "current_page": 1,
  "data": [
    {
      "id": 1,
      "title": "这是第一篇新闻标题",
      "content": "这是第一篇新闻的详细内容...",
      "created_at": "2023-01-01",
      "image": "news1.jpg"
    },
    {
      "id": 2,
      "title": "这是第二篇新闻标题",
      "content": "这是第二篇新闻的详细内容...",
      "created_at": "2023-01-02",
      "image": "news2.jpg"
    }
  ]
}

2. API接口 (api.php)

php 复制代码
<?php
header('Content-Type: application/json');

// 允许跨域请求
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");

// 获取新闻数据
function getNewsData() {
    $json = file_get_contents('data/news.json');
    return json_decode($json, true);
}

// 保存新闻数据
function saveNewsData($data) {
    file_put_contents('data/news.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}

// 获取分页新闻
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'get_news') {
    $page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
    $perPage = 5; // 每页显示数量
    
    $newsData = getNewsData();
    $total = count($newsData['data']);
    $totalPages = ceil($total / $perPage);
    
    $offset = ($page - 1) * $perPage;
    $pagedData = array_slice($newsData['data'], $offset, $perPage);
    
    echo json_encode([
        'success' => true,
        'data' => $pagedData,
        'pagination' => [
            'total' => $total,
            'per_page' => $perPage,
            'current_page' => $page,
            'total_pages' => $totalPages
        ]
    ]);
    exit;
}

// 获取单条新闻
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'get_single_news') {
    $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
    
    if ($id <= 0) {
        echo json_encode(['success' => false, 'message' => 'Invalid news ID']);
        exit;
    }
    
    $newsData = getNewsData();
    $newsItem = null;
    
    foreach ($newsData['data'] as $item) {
        if ($item['id'] == $id) {
            $newsItem = $item;
            break;
        }
    }
    
    if ($newsItem) {
        echo json_encode(['success' => true, 'data' => $newsItem]);
    } else {
        echo json_encode(['success' => false, 'message' => 'News not found']);
    }
    exit;
}
?>

3. 首页 (index.php)

php 复制代码
<?php
// 读取新闻数据用于SEO优化
$newsData = json_decode(file_get_contents('data/news.json'), true);
$latestNews = array_slice($newsData['data'], 0, 5);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新闻中心</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>新闻中心</h1>
        </header>
        
        <div class="news-list" id="newsList">
            <!-- 新闻列表将通过JS动态加载 -->
        </div>
        
        <div class="pagination" id="pagination">
            <!-- 分页将通过JS动态加载 -->
        </div>
    </div>
    
    <!-- 为SEO提供基础内容,JS会覆盖这些内容 -->
    <noscript>
        <div class="news-list">
            <?php foreach ($latestNews as $item): ?>
            <div class="news-item">
                <h2><a href="news/<?php echo $item['id']; ?>.html"><?php echo htmlspecialchars($item['title']); ?></a></h2>
                <p class="date"><?php echo $item['created_at']; ?></p>
                <div class="excerpt"><?php echo mb_substr(strip_tags($item['content']), 0, 100); ?>...</div>
            </div>
            <?php endforeach; ?>
        </div>
    </noscript>
    
    <script src="script.js"></script>
</body>
</html>

4. 独立新闻页面 (/news/{id}.html)

php 复制代码
<?php
$id = basename($_SERVER['SCRIPT_NAME'], '.html');
if (!is_numeric($id)) {
    header("HTTP/1.0 404 Not Found");
    exit;
}

// 获取新闻数据
$newsData = json_decode(file_get_contents('../data/news.json'), true);
$newsItem = null;

foreach ($newsData['data'] as $item) {
    if ($item['id'] == $id) {
        $newsItem = $item;
        break;
    }
}

if (!$newsItem) {
    header("HTTP/1.0 404 Not Found");
    exit;
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo htmlspecialchars($newsItem['title']); ?> - 新闻中心</title>
    <link rel="stylesheet" href="../style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1><a href="../">新闻中心</a></h1>
        </header>
        
        <article class="news-detail">
            <h2><?php echo htmlspecialchars($newsItem['title']); ?></h2>
            <p class="date">发布日期: <?php echo $newsItem['created_at']; ?></p>
            
            <?php if (!empty($newsItem['image'])): ?>
            <div class="news-image">
                <img src="../images/<?php echo htmlspecialchars($newsItem['image']); ?>" alt="<?php echo htmlspecialchars($newsItem['title']); ?>">
            </div>
            <?php endif; ?>
            
            <div class="news-content">
                <?php echo nl2br(htmlspecialchars($newsItem['content'])); ?>
            </div>
        </article>
    </div>
</body>
</html>

5. 样式文件 (style.css)

css 复制代码
/* 基础样式 */
body {
    font-family: 'Microsoft YaHei', Arial, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
    color: #333;
    background-color: #f5f5f5;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

header {
    background-color: #1e88e5;
    color: white;
    padding: 20px;
    margin-bottom: 30px;
    border-radius: 5px;
}

header h1 {
    margin: 0;
}

header h1 a {
    color: white;
    text-decoration: none;
}

/* 新闻列表样式 */
.news-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

.news-item {
    background: white;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    transition: transform 0.3s ease;
}

.news-item:hover {
    transform: translateY(-5px);
    box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}

.news-item h2 {
    margin-top: 0;
    margin-bottom: 10px;
}

.news-item h2 a {
    color: #1e88e5;
    text-decoration: none;
}

.news-item .date {
    color: #757575;
    font-size: 0.9em;
    margin-bottom: 10px;
}

.news-item .excerpt {
    color: #616161;
}

/* 新闻详情页样式 */
.news-detail {
    background: white;
    padding: 30px;
    border-radius: 5px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.news-detail h2 {
    margin-top: 0;
    color: #1e88e5;
}

.news-detail .date {
    color: #757575;
    font-size: 0.9em;
    margin-bottom: 20px;
}

.news-image {
    margin-bottom: 20px;
}

.news-image img {
    max-width: 100%;
    height: auto;
    border-radius: 5px;
}

.news-content {
    line-height: 1.8;
}

/* 分页样式 */
.pagination {
    display: flex;
    justify-content: center;
    margin-top: 30px;
    padding: 20px 0;
}

.pagination a, .pagination span {
    display: inline-block;
    padding: 8px 16px;
    margin: 0 5px;
    border: 1px solid #ddd;
    text-decoration: none;
    color: #1e88e5;
    border-radius: 5px;
}

.pagination a:hover {
    background-color: #1e88e5;
    color: white;
    border-color: #1e88e5;
}

.pagination .current {
    background-color: #1e88e5;
    color: white;
    border-color: #1e88e5;
}

.pagination .disabled {
    color: #ddd;
    pointer-events: none;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .container {
        padding: 10px;
    }
    
    header {
        padding: 15px;
    }
    
    .news-item, .news-detail {
        padding: 15px;
    }
}

6. 前端交互 (script.js)

javascript 复制代码
document.addEventListener('DOMContentLoaded', function() {
    // 加载新闻列表
    loadNews(1);
    
    // 如果是新闻详情页,加载新闻内容
    if (window.location.pathname.includes('/news/')) {
        const newsId = window.location.pathname.split('/').pop().replace('.html', '');
        loadSingleNews(newsId);
    }
});

// 加载新闻列表
function loadNews(page) {
    fetch(`api.php?action=get_news&page=${page}`)
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                renderNewsList(data.data);
                renderPagination(data.pagination);
            } else {
                console.error('Failed to load news:', data.message);
            }
        })
        .catch(error => {
            console.error('Error loading news:', error);
        });
}

// 渲染新闻列表
function renderNewsList(newsItems) {
    const newsListContainer = document.getElementById('newsList');
    
    if (!newsListContainer) return;
    
    newsListContainer.innerHTML = '';
    
    newsItems.forEach(item => {
        const excerpt = item.content.replace(/<[^>]*>/g, '').substring(0, 100) + '...';
        
        const newsItem = document.createElement('div');
        newsItem.className = 'news-item';
        newsItem.innerHTML = `
            <h2><a href="news/${item.id}.html">${item.title}</a></h2>
            <p class="date">${item.created_at}</p>
            <div class="excerpt">${excerpt}</div>
        `;
        
        newsListContainer.appendChild(newsItem);
    });
}

// 渲染分页
function renderPagination(pagination) {
    const paginationContainer = document.getElementById('pagination');
    
    if (!paginationContainer) return;
    
    paginationContainer.innerHTML = '';
    
    const { current_page, total_pages } = pagination;
    
    // 上一页按钮
    const prevLink = document.createElement('a');
    prevLink.href = '#';
    prevLink.textContent = '上一页';
    prevLink.addEventListener('click', (e) => {
        e.preventDefault();
        if (current_page > 1) {
            loadNews(current_page - 1);
            window.scrollTo(0, 0);
        }
    });
    
    if (current_page === 1) {
        prevLink.classList.add('disabled');
    }
    
    paginationContainer.appendChild(prevLink);
    
    // 页码按钮
    for (let i = 1; i <= total_pages; i++) {
        const pageLink = document.createElement(i === current_page ? 'span' : 'a');
        
        if (i !== current_page) {
            pageLink.href = '#';
            pageLink.addEventListener('click', (e) => {
                e.preventDefault();
                loadNews(i);
                window.scrollTo(0, 0);
            });
        } else {
            pageLink.className = 'current';
        }
        
        pageLink.textContent = i;
        paginationContainer.appendChild(pageLink);
    }
    
    // 下一页按钮
    const nextLink = document.createElement('a');
    nextLink.href = '#';
    nextLink.textContent = '下一页';
    nextLink.addEventListener('click', (e) => {
        e.preventDefault();
        if (current_page < total_pages) {
            loadNews(current_page + 1);
            window.scrollTo(0, 0);
        }
    });
    
    if (current_page === total_pages) {
        nextLink.classList.add('disabled');
    }
    
    paginationContainer.appendChild(nextLink);
}

// 加载单条新闻 (用于未来可能的AJAX加载)
function loadSingleNews(id) {
    fetch(`api.php?action=get_single_news&id=${id}`)
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                // 可以在这里处理AJAX加载的新闻详情
                console.log('News loaded:', data.data);
            } else {
                console.error('Failed to load news:', data.message);
            }
        })
        .catch(error => {
            console.error('Error loading news:', error);
        });
}

7. 伪静态配置

IIS 伪静态规则 (web.config)

xml 复制代码
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <!-- 首页 -->
                <rule name="Main Page" stopProcessing="true">
                    <match url="^$" />
                    <action type="Rewrite" url="index.php" />
                </rule>
                
                <!-- 新闻详情页 -->
                <rule name="News Detail" stopProcessing="true">
                    <match url="^news/([0-9]+)\.html$" />
                    <action type="Rewrite" url="news/{R:1}.html" />
                </rule>
                
                <!-- API路由 -->
                <rule name="API Routes">
                    <match url="^api/(.*)$" />
                    <action type="Rewrite" url="api.php?action={R:1}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

宝塔伪静态规则 (Nginx)

bash 复制代码
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location /news/ {
    try_files $uri /news/$1.html;
}

location /api {
    rewrite ^/api/(.*)$ /api.php?action=$1 last;
}

使用说明

  1. 将上述文件按照目录结构放置到您的网站目录中
  2. 根据您的服务器环境配置伪静态规则
  3. 修改data/news.json文件添加您的新闻内容
  4. 确保data/目录有写入权限(如果需要后台添加新闻功能)

扩展建议

  1. 后台管理:可以添加一个简单的后台管理系统来管理新闻
  2. 图片上传:为新闻添加图片上传功能
  3. 分类功能:扩展JSON结构支持新闻分类
  4. 缓存机制:添加缓存提高性能

这个实现方案既支持现代浏览器的AJAX加载,又为SEO提供了基本的静态内容,同时通过伪静态规则实现了美观的URL结构。更多数据详情:baijiahao.baidu.com/s?id=183050...

相关推荐
Ashlee_code8 小时前
什么是Web3?金融解决方案
开发语言·金融·架构·eclipse·web3·区块链·php
Sally璐璐13 小时前
IPSAN 共享存储详解:架构、优化与落地实践指南
开发语言·php
程序猿阿伟15 小时前
《声音的变形记:Web Audio API的实时特效法则》
开发语言·前端·php
Clownseven16 小时前
Shell 脚本实战指南:内网 ARP 洪泛监控与飞书/邮件自动告警
网络·php·飞书
浪裡遊1 天前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
ejinxian1 天前
PHP 超文本预处理器 发布 8.5 版本
开发语言·php
zorro_z1 天前
PHP语法基础篇(九):正则表达式
php
高压锅_12202 天前
思科与华为网络设备命令对比指南:从基础操作到高级配置
服务器·华为·php
SuperherRo2 天前
WEB攻防-文件包含&LFI&RFI&伪协议编码算法&无文件利用&黑白盒
php·文件包含·伪协议·lfi·无文件·黑白盒·rfi