博客 / 詳情

返回

直接在html中引入Vue.js的cdn來實現一個簡單的博客

摘要

其實建立一個博客系統是非常簡單的,有很多開源的程序,如果你不喜歡博客系統,也可以自己開發,也可以自己簡單做一個。我這次就是用Vue.js和php做後端服務實現一個簡單的博客。

界面

image.png

代碼結構

image.png
image.png
image.png

代碼

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
});

完整代碼

如需獲取後端服務、前端、樣式等完整代碼請下載:
https://afdian.net/item/279611c435d811eea89a52540025c377

演示

http://demo.likeyunba.com/blog/#/

作者

TANKING

user avatar mulander 頭像 guisijun 頭像 birenxuemou 頭像
3 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.