个人博客第一种实现方法
实现思路
个人博客实现思路:
首页index.html上有很多目录,点击目录会跳转到某一篇文章页面page.html下,这些文章页面有相同的框架,只是标题内容不同。
下面介绍第一种最简单的实现方法:
创建很多个html文件,每一篇不同的文件对应不同的文章,在index.html(首页文件)当中以列表的形式引入每一篇文章文件,通过a标签把首页和文章链接起来。点击目录,会跳转到某一篇文章页面。
具体实现
1、首先下载可能需要的插件
body-parser、express、mongodb
2、创建服务器文件index.js
引入express
const express=require('express')
创建服务器app
const app=express()
利用express的static引入静态目录
注意静态目录默认文件是index.html,如果更改文件名比如demo.html,需要设置static方法的第二个参数为index:false
app.use(express.static('./static',{index:false}))
//表示不把默认的index.html作为主页文件
//帮助管理静态文件
监听3000端口
app.listen(3000)
3、服务器创建完毕,接下来创建我们需要的static文件夹,保存需要的静态文件
3.1、首先设置静态目录下的文章文件和首页文件,对他们简单设置一些样式即可
page1.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./../css/page.css">
</head>
<body>
<nav>佩奇的专栏-----佩奇跟你唠唠嗑</nav>
<h3>母猪的产前护理</h3>
<p>母猪在产前就需要精心照顾</p>
</body>
</html>
page2.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./../css/page.css">
</head>
<body>
<nav>佩奇的专栏-----佩奇跟你唠唠嗑</nav>
<h3>母猪的产后护理</h3>
<p>母猪在产后需要补充营养</p>
</body>
</html>
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css/page.css">
</head>
<body>
<nav>佩奇的专栏-----佩奇跟你唠唠嗑</nav>
<div class="wrap">
<ul>
<li>
<a href="./pages/page1.html">母猪的产前护理</a>
</li>
<li>
<a href="./pages/page2.html">母猪的产后护理</a>
</li>
</ul>
</div>
</body>
</html>
对他们设置css样式:
*{
margin: 0;
padding: 0;
}
nav{
width: 100%;
height: 70px;
background-color: deeppink;
color: white;
font-weight: bold;
line-height: 70px;
font-size: 30px;
padding-left: 50px;
}
h3{
padding-left: 50px;
padding-top: 20px;
}
p{
padding-left: 50px;
}
.wrap{
padding-left: 50px;
padding-top: 20px;
}
优缺点
优点:
实现简单:给每个文章复制粘贴相同的html文件,手动修改标题和内容,把静态html链接到首页a标签,实现静态文件跳转。
缺点:
1、如果想要更改页面的版式,那么所有的文件都要更改,维护极其困难;
2、文章并不能动态更新,因为每篇文章都是在html文件里写死的;
3、文章的查找功能、搜索功能根本没办法实现。
个人博客第二种实现方法
实现思路
下面介绍个人博客的第二种实现方法:
Ajax无法实现跨页,所以只在一个页面内就能完成请求。
在首页内设计上下两个版块,上面显示所有文章列表,下面点击时能出现对应文章的标题和内容。
把所有的信息(title和content)都存储在Mongodb中,首页向服务器发起Ajax请求,请求所有文章列表,服务器查找数据库中所有的数据返回给前端,前端把它渲染到页面。
点击某一个标题,携带该标题的id向服务器发起请求,服务器查找对应id的数据返回给前端,前端把内容渲染到页面。
具体实现
1、设计首页页面,分成上下两部分
<div>
<ul class="list">
<li>母猪的产后护理</li>
</ul>
</div>
<hr>
<div class="content"></div>
2、在前端设计getList方法,发起Ajax请求,向服务器请求所有的文章列表
请求方式为GET请求,向后台list接口请求数据,因为要获取所有的数据所以不需要传递data,当成功获取到信息,执行填充页面函数。
var getList=function(){
$.ajax({
type:'GET',
url:'/list',
data:{},
success:function(jieguo){
// console.log(jieguo)
fillList(jieguo)
}
})
}
3、设计填充页面的函数
传递过来的结果中包含所有信息,这些信息是以数组形式传递的,数组中的每一个条对象都是一条数据。
定义一个空字符串,遍历数组每一项,以模板形式把每一项的title属性放到li标签里,再把所有的li标签加到html字符串中,这样html字符串就有了所有包裹着文章标题的li标签,再把li标签渲染到列表中即可。
注意:每个li要有一个id属性,以便设计后点击事件时使用。
var fillList=function(arr){
// 填充页面的方法
var html=''
arr.forEach(function(item,index){
html+=`<li class="item" data=${item._id}>${item.title}</li>`
})
$('.list').html(html)
// 拼接好的字符串渲染到页面上
}
4、设计服务器文件index.js
引入需要的express、mongoControl文件
初始化服务器文件
const express=require('express')
//引入mongoControl 数据库操纵文件
const mongoControl = require('./mongoControl')
// 初始化一个用于博客的库和表
const blogControl = new mongoControl('text', 'page')
const app=express()
app.listen(3000)
引入静态目录
app.use(express.static('./static'))
设计请求数据列表的接口
在blogControl数据库里查找所有的数据发送给前端
// 请求数据列表的接口
app.get('/list',function(req,res){
blogControl.find({},function(jieguo){
res.send(jieguo)
})
})
至此,localhost:3000能显示所有的文章标题
接下来设计点击事件,点击某一篇文章,下面的内容区显示相应的内容。
5、设计获取文章内容的函数
向后台getContent接口发起请求,携带一个id值,后台寻找id值对应的内容,获取成功,把结果中的文章内容取出来,显示到内容区。
var getContent=function(_id){
$.ajax({
type:'GET',
url:'/getContent',
data:{
_id:_id
},
success:function(jieguo){
$('.content').html(jieguo[0].content)
}
})
}
6、设计点击事件
在填充页面时,把每个被渲染上去的标题都挂上监听器,点击执行getContent函数,传入当前id。
$('.item').on('click',function(){
getContent($(this).attr('data'))
// $(this).attr(data)获取当前点击触发了回调函数的data属性值
})
7、在后台设计请求文章内容的接口
先取出得到的id,根据id在数据库中查找数据,查找成功,把查找到的数据返回给前端。
// 根据点击时的id获取内容
app.get('/getContent',function(req,res){
// console.log(req.query._id)
var _id=req.query._id
blogControl.findOneById(_id,function(jieguo){
res.send(jieguo)
})
})
实现效果
优缺点
优点:
1、使用了模板形式的开发,要想修改版式,只要修改模板就好了,维护简单;
2、所有数据都是存储在mongodb中的,可以进行搜索,排序,查找等,内容可管理;
3、Ajax的浏览体验不错;
4、大部分的html替换、渲染都是在用户的浏览器进行的,所以服务器的压力就会变小。
缺点:
1、整个项目都是在一个页面内进行,浏览列表和文章内容没有分离,无法实现大型网站系统,只适合做小的单个应用;
2、SEO优化无法完成,搜索引擎的爬虫不会去执行我们的js代码,对它来说,我们的项目只是一个空壳,没有爬取的必要。
前两种方法存储的都是html格式的数据,存储非常困难,接下来我们将解决这个问题。
个人博客第三种实现方法
后端渲染实现思路
前端渲染:前端像后端发起请求,后端设计相应的接口接受请求,查询数据库,给前端发送json格式的结果,前端把json结果通过replace拼接到页面上;
后端渲染:前端只是作为一个模板存在,后端通过fs模块读取index.html文件,获得完整的html文件的字符串,后端自己向数据库请求需要的数据,后端再把查询到的数据通过replace替换html模板里的内容,得到最终完整的html字符串,再把整个字符串一起发送给前端。
前两种方法其实都是前端的渲染,在这里,我们采用后端渲染的方式来实现博客。
后端渲染具体实现
1、设计主页模板
主页中有一个列表来接受文章题目就行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="wrap">
<ul>
<!--allList-->
</ul>
</div>
</body>
</html>
2、设计文章页面模板
文章页面设计两个待替换的符号,用来放文章标题和内容。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>佩奇的专栏-----佩奇跟你唠唠嗑</h1>
<div class="wrap">
<h3><!--title--></h3>
<p><!--content--></p>
</div>
</body>
</html>
3、设计服务器文件
3.1初始化服务器文件,引入需要的模块
在这里,我们不使用static来处理静态目录下的文件,我们需要的是可以动态发生变化的文件,不是某一个写死的文件,我们自己处理/接口请求。
const express=require('express')
const fs=require('fs')
//引入mongoControl
const mongoControl = require('./mongoControl')
// 初始化一个用于博客的库和表
const blogControl = new mongoControl('text', 'page')
const app=express()
app.listen(3000)
3.2处理首页目录(也就是/接口)接口请求
通过fs模块的readFile方法读取index.html文件,获得一个html的字符串,得到的字符串作为我们的tpl模板。
因为我们要拼接的是文章题目列表,有很多条数据,我们先定义一个中间字符串html来接收一下所有的li标签。
在blogControl数据库中查询所有信息,得到一个数组,遍历这个数组,使用es6语法拼接li标签,赋值给html,遍历完成之后,html就是待拼接的li组。
(注意:拼接li标签的时候,记得给每个标签设计一个独特的id,方便之后点击跳转页面使用)
再把tpl中待替换的部分replace成html。
最后,把替换好的tpl发送给前端。
app.get('/',function(req,res){
fs.readFile('./static/index.html',{encoding:'utf-8'},function(err,result){
if(err){
res.status(500)
return
}
// console.log(result)
// 此时的result就是获取到的index.html模板
var tpl=result
// 去数据库中查找信息
var html=''
blogControl.find({},function(jieguo){
// console.log(jieguo)
// jieguo就是包含所有信息的数组
jieguo.forEach(function(item,index){
html+=`<li><a href="/p?_id=${item._id}">${item.title}</a></li>`
})
tpl=tpl.replace('<!--allList-->',html)
res.send(tpl)
})
})
})
3.3处理文章页面/p接口请求
首先获取地址栏传递的参数_id,读取page.html文件,得到文章页面的模板。
去blogControl数据库根据id查询数据,把结果中的title和content通过replace方法替换到模板相应位置,替换结果赋值给html就行。
(注意:这里不需要中间字符串,一篇文章只替换一次标题和一次内容就行,不需要替换很多次)
后端把html字符串发送给前端
app.get('/p',function(req,res){
var _id=req.query._id
fs.readFile('./static/page.html',{encoding:'utf-8'},function(err,result){
blogControl.findOneById(_id,function(jieguo){
// jieguo中包含查询到的信息
var html=''
var json=jieguo[0]
html=result.replace('<!--title-->',json.title)
.replace('<!--content-->',json.content)
// console.log(html)
res.send(html)
// !!!!!!注意,不要写错代码位置
// 发送文件要在替换完之后,注意不要写在代码块外,否则还没有查询数据就发送数据,页面当然为空啊
})
})
})
后端渲染优缺点
优点:
1、因为我们请求获得的是完整的html内容,所以搜索引擎优化很好;
2、适合制作多个页面的整体逻辑。
缺点:
因为服务器文件的逻辑相比前两个过于复杂,填充过程也比较复杂,所以对后端的压力很大。
ejs优化
上面使用模板的方式过于复杂,可以通过ejs模板引擎来进行优化。
1、在后端index.js文件引入ejs
const ejs=require('ejs')
2、使用ejs处理主页接口请求接口
上面手写模板是先读取文件,再查找数据去渲染;
使用ejs先查找对应的数据,把数据通过ejs的renderFile方法发送给index.ejs,在index.ejs文件里进行数据的渲染。
注意ejs的语法使用:把每一行的js语句用<% %>包裹起来,把变量的调用用<%= %>包裹起来。
blogControl.find({},function(jieguo){
ejs.renderFile('./static/index.ejs',{data:jieguo},function(err,result){
res.send(result)
})
})
<!-- data传到这里来,data是一个数组,遍历数组 -->
<% data.forEach(function(item,index){ %>
<li><a href="/p?_id=<%= item._id %>"> <%= item.title %> </a></li>
<% }) %>
3、处理文章接口请求
原理同上
blogControl.findOneById(_id,function(jieguo){
var data=jieguo[0]
// console.log(data)
ejs.renderFile('./static/page.ejs',{data:data},function(err,result){
// console.log(result)
res.send(result)
})
})
<h3><!--title-->
<%= data.title %>
</h3>
<p><!--content-->
<%= data.content %>
</p>
大大简化代码。