直接在html中引入Vue.js的cdn来实现一个简单的博客

摘要

其实建立一个博客系统是非常简单的,有很多开源的程序,如果你不喜欢博客系统,也可以自己开发,也可以自己简单做一个。我这次就是用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

相关推荐
masa01018 分钟前
JavaScript--JavaScript基础
开发语言·javascript
Passion不晚2 小时前
Vue vs React vs Angular 的对比和选择
vue.js·react.js·前端框架·angular.js
她似晚风般温柔7897 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr8 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
Ylucius8 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
LvManBa9 小时前
Vue学习记录之六(组件实战及BEM框架了解)
vue.js·学习·rust
200不是二百9 小时前
Vuex详解
前端·javascript·vue.js
LvManBa9 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
是梦终空9 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票