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

news2024/12/20 22:37:29

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

一、项目初始化

1. 创建项目

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

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

# 进入项目目录
cd my-blog

# 安装项目依赖
npm install

2. 安装必要依赖

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

# 安装核心依赖
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 过渡动画
<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. 核心实现:
   - 滚动事件监听
   - 进度计算逻辑
   - 组件生命周期管理
<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 防护
   - 路由导航
<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]

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

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. 路由懒加载
// [文件位置: src/router/index.js]
const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('@/views/HomeView.vue') // 懒加载首页
  },
  {
    path: '/blog',
    name: 'blog',
    component: () => import('@/views/BlogView.vue') // 懒加载博客页
  }
]
  1. 图片懒加载
// [文件位置: 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. 组件懒加载
// [文件位置: 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]

配置全局状态管理:

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]

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

: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]

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

/* 移动端优先的响应式设计 */
.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. 样式系统

    • 定义全局主题变量
    • 实现响应式布局
    • 设置统一的设计标准

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2262937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MFC】多工具栏如何保存状态

MFC中的工具栏本来只有一个&#xff0c;如果想增加几个工具栏是比较简单&#xff0c;但现在一个重要的问题是&#xff0c;状态无法保存&#xff0c;导致每次打开&#xff0c;工具栏就会出现问题&#xff0c;要么偏移位置要么显示不出。 经过研究&#xff0c;发现是MFC框架中的…

Buck开关电源闭环控制的仿真研究15V/5V[Matlab/simulink源码+Word文档]

课题设计要求 ⑴输入直流电压(VIN)&#xff1a;15V ⑵输出电压(VO)&#xff1a;5.0V ⑶负载电阻&#xff1a;R2欧 ⑷输出电压纹波峰-峰值 Vpp≤50mV &#xff0c;电感电流脉动&#xff1a;输出电流的10% ⑸开关频率(fs)&#xff1a;100kHz ⑹BUCK主电路二极管的通态压降VD0.5V…

鸿蒙项目云捐助第十八讲云捐助我的页面下半部分的实现

鸿蒙项目云捐助第十八讲云捐助我的页面下半部分的实现 在一般的应用app中都会有一个“我的”页面&#xff0c;在“我的”页面中可以完成某些设置&#xff0c;也可以完成某些附加功能&#xff0c;如“修改密码”等相关功能。这里的鸿蒙云捐助也有一个“我的”功能页面。这里对“…

Flink2.0未来趋势中需要注意的一些问题

手机打字&#xff0c;篇幅不长&#xff0c;主要讲一下FFA中关于Flink2.0的未来趋势&#xff0c;直接看重点。 Flink Forward Asia 2024主会场有一场关于Flink2.0的演讲&#xff0c;很精彩&#xff0c;官方也发布了一些关于Flink2.0的展望和要解决的问题。 1.0时代和2.0时代避免…

《深入浅出Apache Spark》系列⑤:Spark SQL的表达式优化

导读&#xff1a;随着数据量的快速增长&#xff0c;传统的数据处理方法难以满足对计算速度、资源利用率以及查询响应时间的要求。为了应对这些挑战&#xff0c;Spark SQL 引入了多种优化技术&#xff0c;以提高查询效率&#xff0c;降低计算开销。本文从表达式层面探讨了 Spark…

在Tomcat中部署应用时,如何通过域名访问而不加端口号

--江上往来人&#xff0c;但爱鲈鱼美。 --君看一叶舟&#xff0c;出没风波里。 在Tomcat中部署应用时&#xff0c;如果你希望通过域名访问而不加端口号&#xff08;默认HTTP端口80或HTTPS端口443&#xff09;&#xff0c;你通常需要在前端使用一个反向代理服务器&#xff08;如…

如何测量分辨率

一、什么是分辨率&#xff1f; 分辨率指的是分清物体细节的能力。分辨率是一个成像系统还原空间频率的能力。一些人只是简单的用分辨率去描述极限分辨率&#xff0c;但是相机在在不同的对比度的情况下还原低&#xff0c;中和高频率的能力&#xff0c;也可以显示全面综合的信息。…

Leetcode分隔链表

java 实现 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; this.next next; }* }*/ class …

maui开发成生安卓apk,运行提示该应用与此设备的CPU不兼容

在生成.NET MAUI安卓应用时遇到“该应用与此设备的CPU不兼容”的问题&#xff0c;确保你的.NET MAUI应用支持的Android目标框架与设备CPU架构相匹配。例如&#xff0c;如果你的应用是为ARM64架构编译的&#xff0c;而你的设备是x86架构&#xff0c;就会出现不兼容的问题。 一、…

在 Unity 6 中使用APV为您的世界创建全局照明的新方法(一)

Unity 6 中推出的新照明功能让您能够更快速、更高效的完成对烘焙场景的照明工作&#xff0c;在本文中我们将与大家详细分享在 Unity 6 中应用自适应探针卷创建快速全局光照的更多细节与具体应用方法。由于内容比较丰富&#xff0c;我们将把内容分为三篇文章&#xff0c;以便大家…

深度学习之超分辨率算法——FRCNN

– 对之前SRCNN算法的改进 输出层采用转置卷积层放大尺寸&#xff0c;这样可以直接将低分辨率图片输入模型中&#xff0c;解决了输入尺度问题。改变特征维数&#xff0c;使用更小的卷积核和使用更多的映射层。卷积核更小&#xff0c;加入了更多的激活层。共享其中的映射层&…

VSCode 搭建Python编程环境 2024新版图文安装教程(Python环境搭建+VSCode安装+运行测试+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Python环境安装二、VScode下载及安装三、VSCode配置Python环境四、运行测试五、背景图设置 很高兴你打开了这篇博客&#xff0c;更多详细的安装教程&…

使用Docker启用MySQL8.0.11

目录 一、Docker减小镜像大小的方式 1、基础镜像选择 2、减少镜像层数 3、清理无用文件和缓存 4、优化文件复制&#xff08;COPY和ADD指令&#xff09; 二、Docker镜像多阶段构建 1、什么是dockers镜像多阶段构建 1.1 概念介绍 1.2 构建过程和优势 2、怎样在Dockerfil…

Windows安全中心(病毒和威胁防护)的注册

文章目录 Windows安全中心&#xff08;病毒和威胁防护&#xff09;的注册1. 简介2. WSC注册初探3. WSC注册原理分析4. 关于AMPPL5. 参考 Windows安全中心&#xff08;病毒和威胁防护&#xff09;的注册 本文我们来分析一下Windows安全中心&#xff08;Windows Security Center…

Hive其一,简介、体系结构和内嵌模式、本地模式的安装

目录 一、Hive简介 二、体系结构 三、安装 1、内嵌模式 2、测试内嵌模式 3、本地模式--最常使用的模式 一、Hive简介 Hive 是一个框架&#xff0c;可以通过编写sql的方式&#xff0c;自动的编译为MR任务的一个工具。 在这个世界上&#xff0c;会写SQL的人远远大于会写ja…

时空AI赋能低空智能科技创新

随着人工智能技术的不断进步&#xff0c;时空人工智能&#xff08;Spatio-Temporal AI&#xff0c;简称时空AI&#xff09;正在逐渐成为推动低空经济发展的新引擎。时空AI结合了地理空间智能、城市空间智能和时空大数据智能&#xff0c;为低空智能科技创新提供了强大的数据支持…

java 通过jdbc连接sql2000方法

1、java通过jdbc连接sql2000 需要到三个jar包&#xff1a;msbase.jar mssqlserver.jar msutil.jar 下载地址&#xff1a;https://download.csdn.net/download/sunfor/90145580 2、将三个jar包解压到程序中的LIB下&#xff1a; 导入方法&#xff1a; ①在当前目录下&#xff…

web实验二

web实验二 2024.12.19 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>青岛理工大学</title>&l…

纯前端实现更新检测

通过判断打包后的html文件中的js入口是否发生变化&#xff0c;进而实现前端的代码更新 为了使打包后的文件带有hash值&#xff0c;需要对vite打包进行配置 import { defineConfig } from vite; import vue from vitejs/plugin-vue; import { resolve } from path; import AutoI…

云原生周刊:Kubernetes v1.32 正式发布

开源项目推荐 Helmper Helmper 简化了将 Helm Charts导入OCI&#xff08;开放容器倡议&#xff09;注册表的过程&#xff0c;并支持可选的漏洞修复功能。它确保您的 Helm Charts不仅安全存储&#xff0c;还能及时应用最新的安全修复。该工具完全兼容 OCI 标准&#xff0c;能够…