直接在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

相关推荐
lauo11 分钟前
【智体OS】官方上新发布“空钥登陆”--方便访客使用智体操作系统OS和智体应用
前端·javascript·分布式·机器人·开源
哥谭居民000114 分钟前
普通的树形数据primevue的treetable组件的treetable[ ]
前端·javascript·算法
徐小黑ACG19 分钟前
JavaScript 基础
开发语言·javascript
郑大乾6662 小时前
vuex - 第一天
javascript·vue.js·node.js
阿卡基YUAN2 小时前
JavaScript 箭头函数
前端·javascript
湛海不过深蓝2 小时前
【js】记录预览pdf文件
开发语言·javascript·pdf
兮动人2 小时前
vue之axios基本使用
前端·javascript·vue.js
嵌入式小强工作室2 小时前
STM32 Flash DB的使用方法
前端·javascript·stm32
2401_857622663 小时前
“校园疫情防控的技术支持”:疫情管控系统的实现与评估
java·数据库·vue.js·php·ux
Ares码农人生3 小时前
Vue.js 高级组件开发:设计模式与实践
vue.js