使用灵活的PJAX(pushState + Ajax)与Nodejs完成的博客站

使用灵活的PJAX(pushState + Ajax)与Nodejs完成的博客站

不知道 pushState 是何物的同学请百度 html5 history ##需求 整站都使用Ajax加载,但同时必须保证能被搜索引擎(例如百度)正常收录,而且即使浏览器不启用javascript,网站也能正常访问 ##为什么要有这个需求 很多网站都有公共的页头和页尾,然而他们总是在每一次的响应中返回这些公共的部分,浪费了服务器带宽;比较流行的通过改变网址中的hash并结合window.onhashchange事件来加载内容的网站,却又无法被百度正常收录;而且,一旦用户不启用javascript,这样的网站就无法正常显示 ##这不可能? 去**我的博客**看看吧= =。这是一个使用 HTML5 中的新 History API 完成的站点,即使浏览器不支持 HTML5 、甚至不启用javascript,网站也能正常访问。 ##网站架构 前端:Html5 History API + ejs 后端:nodejs + express + ejs + mongoose

##哈哈,其实很简单 我说的有点神秘了,其实只不过是当客户端不支持html5或者不启用js时,后台就会切换成传统的访问方式,每次访问时会将公共的页头页尾一并返回;之所以能被搜索引擎正常收录,是因为第一次打开页面会将内容一并返回到前端,而不是通过ajax加载的内容,之后的点击才是通过ajax改变了内容。

放假闲来无事,从突发奇想到草草完成只花了今天一天时间,请各位大神毫不留情的拍砖~

博客地址:http://lmk123.duapp.com/


6 回复

使用灵活的PJAX(pushState + Ajax)与Node.js完成的博客站

引言

如果你对 pushState 还不太了解,可以查阅一下 HTML5 History API

需求

整站都使用Ajax加载,但同时必须保证能被搜索引擎(例如百度)正常收录,而且即使浏览器不启用JavaScript,网站也能正常访问。

为什么要有这个需求

很多网站都有公共的页头和页尾,然而它们总是在每一次的响应中返回这些公共的部分,浪费了服务器带宽。比较流行的通过改变网址中的hash并结合 window.onhashchange 事件来加载内容的网站,却又无法被百度正常收录。而且,一旦用户不启用JavaScript,这样的网站就无法正常显示。

这不可能?

你可以去 我的博客 看看。这是一个使用 HTML5 中的新 History API 完成的站点,即使浏览器不支持 HTML5 或者不启用JavaScript,网站也能正常访问。

网站架构

  • 前端: Html5 History API + EJS
  • 后端: Node.js + Express + EJS + Mongoose

哈哈,其实很简单

我说的有点神秘了,其实只不过是当客户端不支持HTML5或者不启用JS时,后台就会切换成传统的访问方式,每次访问时会将公共的页头页尾一并返回。之所以能被搜索引擎正常收录,是因为第一次打开页面会将内容一并返回到前端,而不是通过AJAX加载的内容,之后的点击才是通过AJAX改变了内容。

示例代码

以下是一个简单的示例代码,展示了如何实现PJAX功能:

// server.js (Node.js + Express)
const express = require('express');
const app = express();
const ejs = require('ejs');

app.set('view engine', 'ejs');

app.get('/', (req, res) => {
    res.render('index', { title: '首页', content: '欢迎来到首页' });
});

app.get('/about', (req, res) => {
    res.render('about', { title: '关于', content: '这是关于页面' });
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});
<!-- index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%= title %></title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <header>
        <h1>博客站</h1>
    </header>
    <nav>
        <a href="/" class="pjax-link">首页</a>
        <a href="/about" class="pjax-link">关于</a>
    </nav>
    <div id="content">
        <%= content %>
    </div>

    <script>
        $(document).ready(function() {
            $('.pjax-link').click(function(e) {
                e.preventDefault();
                const url = $(this).attr('href');
                $('#content').load(url + ' #content', function() {
                    history.pushState(null, null, url);
                });
            });

            window.addEventListener('popstate', function(event) {
                $('#content').load(location.href + ' #content');
            });
        });
    </script>
</body>
</html>

总结

放假闲来无事,从突发奇想到草草完成只花了今天一天时间,请各位大神毫不留情地拍砖~

博客地址

http://lmk123.duapp.com/


楼主的代码写得相当的认真啊。就是看起来怪怪的。

这是什么时候出来的新概念

没有任何的样式?

楼主的博客很是复古啊 O(∩_∩)O~

为了实现一个使用PJAX(pushState + Ajax)与Node.js完成的博客站,并满足上述需求,我们可以采取以下步骤:

网站架构

  • 前端: 使用HTML5 History API和EJS模板引擎来动态加载内容。
  • 后端: 使用Node.js和Express框架处理请求,Mongoose作为MongoDB的对象模型工具。

示例代码

后端(Node.js + Express)

const express = require('express');
const app = express();
const mongoose = require('mongoose');

// 连接数据库
mongoose.connect('mongodb://localhost/blog', { useNewUrlParser: true, useUnifiedTopology: true });

// 定义文章模型
const PostSchema = new mongoose.Schema({
    title: String,
    content: String
});
const Post = mongoose.model('Post', PostSchema);

// 渲染首页
app.get('/', async (req, res) => {
    const posts = await Post.find().lean();
    res.render('index', { posts });
});

// 渲染单个文章页
app.get('/post/:id', async (req, res) => {
    const post = await Post.findById(req.params.id).lean();
    res.render('post', { post });
});

app.listen(3000, () => console.log('Server running on port 3000'));

前端(HTML + EJS + AJAX)

<!-- index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Blog</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <header>Header Content</header>
    <main id="content">
        <% posts.forEach(post => { %>
            <div class="post" data-id="<%= post._id %>">
                <h2><%= post.title %></h2>
                <p><%= post.content %></p>
            </div>
        <% }) %>
    </main>
    <footer>Footer Content</footer>

    <script>
        document.querySelectorAll('.post').forEach(post => {
            post.addEventListener('click', function() {
                const postId = this.getAttribute('data-id');
                $.get(`/post/${postId}`, (data) => {
                    $('#content').html(data);
                    history.pushState({ postId }, '', `/post/${postId}`);
                });
            });
        });

        window.addEventListener('popstate', function(event) {
            if (event.state && event.state.postId) {
                $.get(`/post/${event.state.postId}`, (data) => {
                    $('#content').html(data);
                });
            }
        });
    </script>
</body>
</html>

post.ejs 文件

<h1><%= post.title %></h1>
<p><%= post.content %></p>
<button onclick="history.back()">Back</button>

解释

  1. 后端逻辑: 后端使用Express处理GET请求,分别渲染主页和单个文章页。
  2. 前端逻辑: 使用jQuery监听文章元素的点击事件,通过AJAX请求获取内容,并更新DOM。同时利用History API改变URL。
  3. 兼容性: 当浏览器不支持HTML5或JavaScript禁用时,服务器直接返回完整的HTML页面,确保基本功能可用。

这种方案可以有效减少不必要的数据传输,提高用户体验,同时保持对搜索引擎的友好。

回到顶部