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. 样式系统

    • 定义全局主题变量
    • 实现响应式布局
    • 设置统一的设计标准
相关推荐
程序员小寒2 小时前
JavaScript设计模式(八):命令模式实现与应用
前端·javascript·设计模式·ecmascript·命令模式
wgod2 小时前
new AbortController()
前端
UXbot2 小时前
UXbot 是什么?一句指令生成完整应用的 AI 工具
前端·ai·交互·个人开发·ai编程·原型模式·ux
棒棒的唐2 小时前
WSL2用npm安装的openclaw,无法正常使用openclaw gateway start启动服务的问题
前端·npm·gateway
吴声子夜歌2 小时前
Node.js——操作MySQL数据库
数据库·mysql·node.js
哔哩哔哩技术2 小时前
使用Compose Navigation3进行屏幕适配
前端
咬人喵喵3 小时前
E2.COOL 平台深度解析:从特效分类到实战操作指南
前端·编辑器·svg
RisunJan4 小时前
Linux命令-named-checkzone
linux·前端
小陈工4 小时前
Python Web开发入门(十):数据库迁移与版本管理——让数据库变更可控可回滚
前端·数据库·人工智能·python·sql·云原生·架构
吹晚风吧4 小时前
解决vite打包,base配置前缀,nginx的dist包找不到资源
服务器·前端·nginx