摘要
其实建立一个博客系统是非常简单的,有很多开源的程序,如果你不喜欢博客系统,也可以自己开发,也可以自己简单做一个。我这次就是用Vue.js和php做后端服务实现一个简单的博客。
界面
代码结构
代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>VueBlog</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0,viewport-fit=cover">
<script src="./static/js/vue.min.js"></script>
<script src="./static/js/vue-router.min.js"></script>
<script src="./static/js/axios.min.js"></script>
<link rel="stylesheet" href="./static/css/app.css">
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
<script src="./static/js/app.js"></script>
</body>
</html>
static/js/app.js
// 定义文章列表组件
const BlogList = {
template: `
<div class="container">
<div class="header">
<span class="logo">
<img src="./static/img/logo.jpg" />
</span>
<h2>TANKING,热爱创作!</h2>
<span class="tag">
<a href="https://github.com/likeyun?tab=repositories" target="_blank">
<img src="./static/img/github.png" />
</a>
</span>
</div>
<div v-if="isLoading" class="loading-message">加载中...</div>
<ul v-infinite-scroll="loadMoreBlogs" infinite-scroll-disabled="loadingMore">
<li v-for="blog in blogs" :key="blog.blog_id">
<router-link :to="'/blog/' + blog.blog_id">
<p class="blog_title">{{ blog.blog_title }}</p>
<p class="blog_info">
<span>{{ blog.blog_category }}</span>
<span>{{ blog.blog_time }}</span>
<span>{{ blog.blog_pv }} 阅读</span>
</p>
</router-link>
</li>
</ul>
<div class="error-message" v-if="getFail">{{ getFail }}</div>
</div>`,
// 数据
data() {
return {
blogs: [], // 列表数据
getFail: null, // 加载失败
isLoading: true, // 加载中
currentPage: 0, // 当前页码
loadingMore: false // 是否正在加载更多内容
};
},
async created() {
// 加载初始文章列表
await this.loadMoreBlogs();
},
mounted() {
// 监听滚动事件
window.addEventListener('scroll', this.handleScroll);
},
methods: {
// 监听滚动事件
handleScroll() {
const scrollY = window.scrollY;
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
if (scrollY + windowHeight >= documentHeight - 200 && !this.loadingMore) {
// 当用户滚动到接近底部并且没有正在加载更多数据时
this.loadMoreBlogs();
}
},
// 异步加载列表
async loadMoreBlogs() {
try {
// 正在加载更多数据
this.loadingMore = true;
const response = await axios.get('./server/getBlogList.php', {
params: {
p: this.currentPage + 1
}
});
if (response.data.code === 200) {
// 获取成功
this.blogs.push(...response.data.blogList);
this.currentPage++;
} else if (response.data.code === 202) {
// 已到最后一页
this.getFail = '已到最后一页';
// 销毁监听事件
window.removeEventListener('scroll', this.handleScroll);
} else {
// 获取失败
this.getFail = '获取博客列表失败';
}
// 隐藏加载中
this.isLoading = false;
} catch (error) {
// 获取失败
this.getFail = '获取博客列表失败';
console.error(error);
} finally {
// 加载完成
this.loadingMore = false;
}
}
}
};
// 文章正文组件
const BlogDetail = {
template: `
<div class="container">
<div v-if="isLoading" class="loading-message">加载中...</div>
<div v-else>
<p class="blog_title blog_content_title">{{ blog.blog_title }}</p>
<p class="blog_info blog_content_info">
<span>{{ blog.blog_category }}</span>
<span>{{ blog.blog_author }}</span>
<span>{{ blog.blog_time }}</span>
<span>{{ blog.blog_pv }} 阅读</span>
</p>
<div v-html="blog.blog_content" class="blog_content"></div>
<button class="like_button" @click="likeBlog" :disabled="isLiked">{{ blog.blog_like }} 赞</button>
</div>
<div class="error-message" v-if="getFail">{{ getFail }}</div>
</div>`,
// 数据
data() {
return {
blog: {},
getFail: null,
isLiked: false, // 是否已经点过赞
isLoading: true, // 加载中
};
},
// 异步加载内容
async created() {
try {
// 根据路由加载博客正文
var blogId = this.$route.params.id;
const response = await axios.get('./server/getBlogContent.php?blogId=' + blogId);
if (response.data.code == 200) {
// 获取成功
this.blog = response.data.blogContent;
// 加载完成
this.isLoading = false;
}else{
// 获取失败
this.getFail = '获取博客内容失败';
}
} catch (error) {
// 获取失败
this.getFail = '获取博客内容失败';
console.error(error);
}
// 检查本地存储是否已点赞,如果已点赞则更新 isLiked
const isLiked = localStorage.getItem('liked_' + blogId);
if (isLiked === 'true') {
// 如果有缓存就设置为你已经点过赞
this.isLiked = true;
}
},
// 方法
methods: {
// 记录点赞
likeBlog() {
if (!this.isLiked) {
axios.post('./server/likeBlog.php?blogId=' + this.blog.blog_id)
.then(response => {
if (response.data.code === 200) {
// 更新点赞数量
this.blog.blog_like++;
// 将点赞状态设置为已点赞
this.isLiked = true;
// 点赞成功后,将点赞状态保存到本地存储
localStorage.setItem('liked_' + this.blog.blog_id, 'true');
}
})
.catch(error => {
console.error(error);
});
}
}
}
};
// 定义路由
const routes = [
{ path: '/', component: BlogList },
{ path: '/blog/:id', component: BlogDetail }
];
const router = new VueRouter({
routes
});
// 创建Vue实例并挂载到app节点
new Vue({
el: '#app',
router
});
演示
http://demo.likeyunba.com/blog/#/
作者
TANKING