VUE+Node.js+mysq实现响应式个人博客|项目初始化+路由配置+基础组件搭建

Day 1 开发文档:项目初始化与基础架构搭建

一、项目初始化

1. 创建项目

首先,我们使用 Vite 创建一个基于 Vue 3 的项目:

bash 复制代码
# 创建项目
npm create vite@latest my-blog -- --template vue
# 这条命令会创建一个名为 my-blog 的新项目,使用 Vue 3 模板

# 进入项目目录
cd my-blog

# 安装项目依赖
npm install

2. 安装必要依赖

接下来,我们需要安装项目所需的核心依赖:

bash 复制代码
# 安装核心依赖
npm install vue-router@4 vuex@4 axios marked dompurify
# vue-router@4: Vue 3 的路由管理器,用于处理页面导航
# vuex@4: Vue 3 的状态管理库,用于管理全局状态
# axios: HTTP 请求库,用于与后端 API 通信
# marked: Markdown 解析器,用于解析文章内容
# dompurify: HTML 净化库,用于防止 XSS 攻击

# 安装开发依赖
npm install -D sass @types/node
# sass: CSS 预处理器,提供更强大的样式编写功能
# @types/node: Node.js 的 TypeScript 类型定义

3. 项目结构规划

创建以下目录结构,每个目录都有其特定用途:

blog-website/
├── src/
│   ├── components/     # 公共组件目录
│   │   ├── TheHeader.vue    # 网站头部导航
│   │   ├── ScrollProgress.vue    # 滚动进度条
│   │   ├── BlogCard.vue    # 博客卡片
│   │   └── TheFooter.vue    # 网站底部
│   ├── views/         # 页面组件目录
│   │   ├── HomeView.vue    # 首页
│   │   └── BlogView.vue    # 博客列表页
│   ├── router/        # 路由配置目录
│   │   └── index.js    # 路由配置文件
│   ├── store/         # 状态管理目录
│   │   └── index.js    # Vuex 配置文件
│   ├── api/          # API 接口目录
│   │   └── blog.js    # 博客相关接口
│   └── assets/       # 静态资源目录
│       └── styles/    # 样式文件目录
│           ├── main.css    # 主样式文件
│           └── responsive.css    # 响应式样式
├── index.html    # 入口 HTML 文件
└── package.json    # 项目配置文件

二、基础组件开发

1. 响应式导航栏组件

[文件位置: src/components/TheHeader.vue]

TheHeader.vue 组件说明:
1. 功能:实现响应式导航栏
2. 主要特点:
   - 自适应布局:在不同屏幕尺寸下自动调整显��方式
   - 移动端菜单:在小屏幕设备上显示汉堡菜单按钮
   - 动态交互:菜单展开/收起动画,滚动时自动隐藏/显示
3. 核心实现:
   - 使用 Vue 3 组合式 API
   - 响应式状态管理
   - CSS 过渡动画
vue 复制代码
<template>
  <header class="header" :class="{ 'header-hidden': isHeaderHidden }">
    <div class="container">
      <nav class="nav">
        <!-- Logo 区域 -->
        <router-link to="/" class="logo">
          <h1>✨ My Blog ✨</h1>
        </router-link>
        
        <!-- 移动端菜单按钮 -->
        <div class="menu-toggle" @click="toggleMenu">
          <i class="fas fa-bars"></i>
        </div>

        <!-- 导航链接 -->
        <ul class="nav-links" :class="{ active: isMenuOpen }">
          <li v-for="item in menuItems" :key="item.path">
            <router-link 
              :to="item.path" 
              @click="closeMenu"
              active-class="active"
            >
              <i :class="item.icon"></i>
              {{ item.name }}
            </router-link>
          </li>
        </ul>
      </nav>
    </div>
  </header>
</template>

<script setup>
import { ref } from 'vue'

// 控制菜单显示状态
const isMenuOpen = ref(false)
// 控制导航栏显示/隐藏
const isHeaderHidden = ref(false)

// 导航菜单项配置
const menuItems = [
  { path: '/', name: '首页', icon: 'fas fa-home' },
  { path: '/blog', name: '博客', icon: 'fas fa-cloud' }
]

// 切换菜单显示状态
const toggleMenu = () => {
  isMenuOpen.value = !isMenuOpen.value
}

// 关闭菜单
const closeMenu = () => {
  isMenuOpen.value = false
}
</script>

2. 滚动进度条组件

[文件位置: src/components/ScrollProgress.vue]

ScrollProgress.vue 组件说明:
1. 功能:显示页面阅读进度
2. 主要特点:
   - 实时进度更新:随页面滚动实时计算和显示进度
   - 平滑动画:使用 CSS 过渡实现流畅的进度更新
   - 性能优化:使用节流函数优化滚动事件处理
3. 核心实现:
   - 滚动事件监听
   - 进度计算逻辑
   - 组件生命周期管理
vue 复制代码
<template>
  <div class="scroll-progress" :style="{ width: progress + '%' }"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

// 存储滚动进度
const progress = ref(0)

// 更新滚动进度
const updateProgress = () => {
  // 计算页面总高度(减去视口高度)
  const windowHeight = document.documentElement.scrollHeight - window.innerHeight
  // 计算滚动百分比
  const scrolled = (window.scrollY / windowHeight) * 100
  progress.value = scrolled
}

// 组件挂载时添加滚动监听
onMounted(() => {
  window.addEventListener('scroll', updateProgress)
})

// 组件卸载时移除监听,防止内存泄漏
onUnmounted(() => {
  window.removeEventListener('scroll', updateProgress)
})
</script>

3. 博客卡片组件

[文件位置: src/components/BlogCard.vue]

BlogCard.vue 组件说明:
1. 功能:展示博客文章预览卡片
2. 主要特点:
   - 响应式布局:适应不同屏幕尺寸
   - 图片处理:懒加载和错误处理
   - 内容格式化:日期和摘要的智能处理
3. 核心实现:
   - 图片懒加载
   - Markdown 解析
   - XSS 防护
   - 路由导航
vue 复制代码
<template>
  <div class="blog-card" @click="handleClick">
    <!-- 文章封面图片 -->
    <div class="card-image">
      <img 
        :src="post.image || '/images/placeholder.jpg'" 
        :alt="post.title"
        @error="handleImageError"
      >
    </div>
    <!-- 文章内容预览 -->
    <div class="card-content">
      <h3 class="card-title">{{ post.title }}</h3>
      <p class="card-excerpt">{{ formatExcerpt(post.excerpt) }}</p>
      <!-- 文章元信息 -->
      <div class="card-meta">
        <span class="date">
          <i class="far fa-calendar-alt"></i>
          {{ formatDate(post.date) }}
        </span>
        <span class="category">
          <i class="fas fa-folder"></i>
          {{ post.category }}
        </span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
import { useRouter } from 'vue-router'

// 定义组件属性
const props = defineProps({
  post: {
    type: Object,
    required: true
  }
})

const router = useRouter()

// 处理卡片点击,跳转到文章详情
const handleClick = () => {
  const id = props.post?.id
  if (!id) return
  router.push(`/blog/${id}`)
}

// 格式化文章摘要,去除 HTML 标签限制长度
const formatExcerpt = (excerpt) => {
  if (!excerpt) return ''
  const html = DOMPurify.sanitize(marked(excerpt))
  const div = document.createElement('div')
  div.innerHTML = html
  let text = div.textContent || div.innerText || ''
  return text.length > 200 ? text.slice(0, 200) + '...' : text
}

// 格式化日期显示
const formatDate = (date) => {
  return new Date(date).toLocaleDateString('zh-CN')
}

// 处理图片加载失败
const handleImageError = (e) => {
  e.target.src = '/images/placeholder.jpg'
}
</script>

三、路由配置

1. 基础路由设置

[文件位置: src/router/index.js]

配置页面路由和导航规则:

javascript 复制代码
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import BlogView from '@/views/BlogView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView,
    meta: {
      title: '首页'
    }
  },
  {
    path: '/blog',
    name: 'blog',
    component: BlogView,
    meta: {
      title: '博客'
    }
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    // 页面切换时滚动到顶部
    return { top: 0 }
  }
})

export default router
路由配置说明:
1. 功能:实现页面导航和路由控制
2. 主要特点:
   - 历史模式:使用 HTML5 History API
   - 路由懒加载:优化首屏加载时间
   - 滚动行为:自动滚动到页面顶部
3. 核心实现:
   - 路由注册
   - 导航守卫
   - 滚动控制

3. 懒加载优化

[文件位置: src/router/index.js, src/components/BlogCard.vue, src/App.vue]

为了提升性能,我们在以下几个方面实现了懒加载:

  1. 路由懒加载
javascript 复制代码
// [文件位置: src/router/index.js]
const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('@/views/HomeView.vue') // 懒加载首页
  },
  {
    path: '/blog',
    name: 'blog',
    component: () => import('@/views/BlogView.vue') // 懒加载博客页
  }
]
  1. 图片懒加载
vue 复制代码
// [文件位置: src/components/BlogCard.vue]
<template>
  <div class="blog-card">
    <div class="card-image">
      <img 
        :src="post.image || '/images/placeholder.jpg'" 
        :alt="post.title"
        loading="lazy" // 使用浏览器原生懒加载
        @error="handleImageError"
      >
    </div>
  </div>
</template>
  1. 组件懒加载
vue 复制代码
// [文件位置: src/App.vue]
<script setup>
import { defineAsyncComponent } from 'vue'

// 懒加载非关键组件
const TheFooter = defineAsyncComponent(() => 
  import('./components/TheFooter.vue')
)

// 带加载状态的懒加载组件
const BlogEditor = defineAsyncComponent({
  loader: () => import('./components/BlogEditor.vue'),
  loadingComponent: LoadingSpinner,
  delay: 200,
  timeout: 3000
})
</script>
  1. 懒加载效果
  • 首屏加载时间优化:只加载必要的组件
  • 图片加载优化:减少首屏请求数量
  • 路由切换优化:按需加载页面组件
  • 内存使用优化:减少初始化时的内存占用

四、状态管理

1. Vuex Store 配置

[文件位置: src/store/index.js]

配置全局状态管理:

javascript 复制代码
import { createStore } from 'vuex'
import { blogApi } from '@/api/blog'

export default createStore({
  // 状态定义
  state: {
    posts: [],      // 文章列表
    loading: false, // 加载状态
    error: null     // 错误信息
  },

  // 修改状态的方法
  mutations: {
    SET_POSTS(state, posts) {
      state.posts = posts
    },
    SET_LOADING(state, loading) {
      state.loading = loading
    },
    SET_ERROR(state, error) {
      state.error = error
    }
  },

  // 异步操作
  actions: {
    // 获取文章列表
    async fetchPosts({ commit }) {
      try {
        commit('SET_LOADING', true)
        const { data } = await blogApi.getPosts()
        commit('SET_POSTS', data)
        return data
      } catch (err) {
        commit('SET_ERROR', err.message)
        throw err
      } finally {
        commit('SET_LOADING', false)
      }
    }
  }
})
Vuex Store 配置说明:
1. 功能:全局状态管理
2. 主要特点:
   - 集中管理数据
   - 异步操作处理
   - 状态追踪
3. 核心实现:
   - 状态定义
   - 同步修改
   - 异步操作

五、样式系统

1. 全局主题变量

[文件位置: src/assets/styles/main.css]

定义全局样式变量,确保设计的一致性:

css 复制代码
:root {
  /* 颜色系统 - 定义网站配色方案 */
  --color-primary: #3498db;    /* 主要颜色 */
  --color-secondary: #2ecc71;  /* 次要颜色 */
  --color-text: #2c3e50;      /* 文本颜色 */
  --color-background: #ffffff; /* 背景颜色 */
  --color-border: #e0e0e0;    /* 边框颜色 */

  /* 字体系统 - 定义文字样式 */
  --font-family: 'Inter', system-ui, sans-serif;
  --font-size-base: 16px;   /* 基础字号 */
  --font-size-lg: 18px;     /* 大号字体 */
  --font-size-xl: 24px;     /* 特大号字体 */

  /* 间距系统 - 统一间距标准 */
  --spacing-xs: 4px;    /* 超小间距 */
  --spacing-sm: 8px;    /* 小间距 */
  --spacing-md: 16px;   /* 中等间距 */
  --spacing-lg: 24px;   /* 大间距 */
  --spacing-xl: 32px;   /* 特大间距 */

  /* 圆角 - 统一圆角大小 */
  --border-radius: 8px;
  --border-radius-lg: 12px;

  /* 阴影 - 统一阴影效果 */
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.12);
  --shadow-md: 0 4px 6px rgba(0,0,0,0.1);
  --shadow-lg: 0 10px 15px rgba(0,0,0,0.1);
}

2. 响应式布局

[文件位置: src/assets/styles/responsive.css]

实现移动端优先的响应式设计:

css 复制代码
/* 移动端优先的响应式设计 */
.container {
  width: 100%;
  padding: 0 var(--spacing-md);
  margin: 0 auto;
}

/* 平板设备断点 (>= 768px) */
@media (min-width: 768px) {
  .container {
    max-width: 720px;  /* 限制容器最大宽度 */
  }

  .header__nav {
    display: flex;  /* 显示导航菜单 */
  }

  .header__toggle {
    display: none;  /* 隐藏菜单按钮 */
  }
}

/* 桌面设备断点 (>= 1024px) */
@media (min-width: 1024px) {
  .container {
    max-width: 960px;
  }

  .posts-grid {
    grid-template-columns: repeat(3, 1fr);  /* 三列布局 */
  }
}

/* 大屏设备断点 (>= 1280px) */
@media (min-width: 1280px) {
  .container {
    max-width: 1200px;
  }
}
样式系统说明:
1. 功能:统一的设计系统
2. 主要特点:
   - 主题变量:统一的颜色和尺寸
   - 响应式设计:适配不同设备
   - 组件样式:模块化的样式管理
3. 核心实现:
   - CSS 变量系统
   - 媒体查询
   - 布局系统

六、第一天完成的功能

  1. 项目初始化

    • 使用 Vite 创建 Vue 3 项目
    • 安装必要的依赖包
    • 规划项目目录结构
  2. 基础组件开发

    • 响应式导航栏(TheHeader)
      • 网站标题和 Logo
      • 响应式菜单
      • 移动端适配
    • 滚动进度条(ScrollProgress)
      • 实时显示阅读进度
      • 平滑动画效果
    • 博客卡片(BlogCard)
      • 文章预览展示
      • 图片加载优化
      • 响应式布局
  3. 路由配置

    • 设置基础路由(首页、博客列表)
    • 配置路由历史模式
    • 添加滚动行为控制
  4. 状态管理

    • 配置 Vuex store
    • 实现文章数据管理
    • 添加加载状态控制
  5. 样式系统

    • 定义全局主题变量
    • 实现响应式布局
    • 设置统一的设计标准
相关推荐
ling0814081423 分钟前
Vue3全局挂载Dialog组件
前端·javascript·vue
Catherinemin25 分钟前
CSS|12 display属性
前端·css
Amo 672925 分钟前
css filter: drop-shadow() 高级阴影效果
前端·css
天天进步201529 分钟前
CSS中的深度选择器 deep 详解
前端·css
95岁IT民工31 分钟前
大屏项目使用css混合实现光源扫描高亮效果
前端·css·vue.js
像污秽一样39 分钟前
简易记事本开发-(SSM+Vue)
java·vue.js·spring boot·spring·servlet·maven·mybatis
匹马夕阳1 小时前
一篇梳理清楚JavaScript ES6中的Promise
前端·javascript·es6
2401_857026231 小时前
SSM 框架结合 Vue 实现电脑测评系统:助力用户明智选择
前端·javascript·vue.js
连胜优佳2 小时前
1.zabbix概述
前端·zabbix
夜雨翦春韭2 小时前
Firefox 基本设置备忘
前端·firefox