使用灵活的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改变了内容。
放假闲来无事,从突发奇想到草草完成只花了今天一天时间,请各位大神毫不留情的拍砖~
使用灵活的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>
总结
放假闲来无事,从突发奇想到草草完成只花了今天一天时间,请各位大神毫不留情地拍砖~
博客地址
楼主的代码写得相当的认真啊。就是看起来怪怪的。
这是什么时候出来的新概念
没有任何的样式?
楼主的博客很是复古啊 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>
解释
- 后端逻辑: 后端使用Express处理GET请求,分别渲染主页和单个文章页。
- 前端逻辑: 使用jQuery监听文章元素的点击事件,通过AJAX请求获取内容,并更新DOM。同时利用History API改变URL。
- 兼容性: 当浏览器不支持HTML5或JavaScript禁用时,服务器直接返回完整的HTML页面,确保基本功能可用。
这种方案可以有效减少不必要的数据传输,提高用户体验,同时保持对搜索引擎的友好。