VUE+Node.js+mysq实现响应式个人博客|项目初始化+路由配置+基础组件搭建
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) * 100progress.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?.idif (!id) returnrouter.push(`/blog/${id}`)
}// 格式化文章摘要,去除 HTML 标签限制长度
const formatExcerpt = (excerpt) => {if (!excerpt) return ''const html = DOMPurify.sanitize(marked(excerpt))const div = document.createElement('div')div.innerHTML = htmllet 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]
为了提升性能,我们在以下几个方面实现了懒加载:
- 路由懒加载
// [文件位置: src/router/index.js]
const routes = [{path: '/',name: 'home',component: () => import('@/views/HomeView.vue') // 懒加载首页},{path: '/blog',name: 'blog',component: () => import('@/views/BlogView.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>
- 组件懒加载
// [文件位置: 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. 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 变量系统- 媒体查询- 布局系统
六、第一天完成的功能
-
项目初始化
- 使用 Vite 创建 Vue 3 项目
- 安装必要的依赖包
- 规划项目目录结构
-
基础组件开发
- 响应式导航栏(TheHeader)
- 网站标题和 Logo
- 响应式菜单
- 移动端适配
- 滚动进度条(ScrollProgress)
- 实时显示阅读进度
- 平滑动画效果
- 博客卡片(BlogCard)
- 文章预览展示
- 图片加载优化
- 响应式布局
- 响应式导航栏(TheHeader)
-
路由配置
- 设置基础路由(首页、博客列表)
- 配置路由历史模式
- 添加滚动行为控制
-
状态管理
- 配置 Vuex store
- 实现文章数据管理
- 添加加载状态控制
-
样式系统
- 定义全局主题变量
- 实现响应式布局
- 设置统一的设计标准
相关文章:

VUE+Node.js+mysq实现响应式个人博客|项目初始化+路由配置+基础组件搭建
Day 1 开发文档:项目初始化与基础架构搭建 一、项目初始化 1. 创建项目 首先,我们使用 Vite 创建一个基于 Vue 3 的项目: # 创建项目 npm create vitelatest my-blog -- --template vue # 这条命令会创建一个名为 my-blog 的新项目&#…...

Python如何正确解决reCaptcha验证码(9)
前言 本文是该专栏的第73篇,后面会持续分享python爬虫干货知识,记得关注。 我们在处理某些国内外平台项目的时候,相信很多同学或多或少都见过,如下图所示的reCaptcha验证码。 而本文,笔者将重点来介绍在实战项目中,遇到上述中的“reCaptcha验证码”,如何正确去处理并解…...

web3跨链预言机协议-BandProtocol
项目简介 Band Protocol 项目最初于 2017年成立并建立在 ETH 之上。后于2020年转移到了 Cosmos 网络上,基于 Cosmos SDK 搭建了一条 Band Chain 。这是一条 oracle-specific chain,主要功能是提供跨链预言机服务。Cosmos生态上第一个,也是目…...

JAVA将集合切分成指定份数(简易)
JAVA将集合切分成指定份数 主要方法 /** * 主要方法* param list 切分的集合* param count 切成的份数* return*/ public static List<List> splitList(List list,int count){if(count <0 ){return Lists.newArrayList();}List<List> result Lists.newArrayL…...

深度神经网络(DNN)在时序预测中的应用与缺陷
目录 编辑 一、DNN在时序预测中的应用 二、DNN的缺陷 三、技术挑战与未来趋势 四、结论 随着大数据时代的到来,深度学习技术在时序预测领域扮演着越来越重要的角色。深度神经网络(DNN)因其强大的非线性拟合能力和自动特征提取能力&…...

springboot445新冠物资管理(论文+源码)_kaic
摘 要 使用旧方法对新冠物资管理的信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在新冠物资管理的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。这次开发的新冠物资管…...

C++算法第十一天
本篇文章我们继续学习动态规划 目录 第一题 题目链接 题目解析 代码原理 代码编写 第二题 题目链接 题目解析 代码原理 代码编写 第三题 题目链接 题目解析 代码原理 代码编写 第四题 题目链接 题目解析 代码原理 代码编写 第五题 题目链接 题目解析 代…...

常 用 类
一、 Object 类 1. Object 类的介绍 (1) Object 类位于 java.lang 包中,是继承关系的根类、超类,是所有类的父类 ( 直接的父类或是间接父类 ) (2) Object 类型的引用可以用于存储任意类型的对象。 (3) Object 类中定义方法,所有类都可以…...

ACL(访问控制列表)
ACL技术概述 • 随着网络的飞速发展,网络安全和网络服务质量 QoS ( Quality of Service )问题日益突出。 ▫ 园区重要服务器资源被随意访问,园区机密信息容易泄露,造成安全隐患。 ▫ Internet 病毒肆意侵略园区内网&am…...

json字符串转json
问题 Json格式化后,存在各种\n ,\r,以及空格,怎么办? 直接replaceAlll(“\s”,“”) 吗? 解决办法: //使用hutool的jsonutil工具,直接将其转换为json,再转string, //这样就不需要使用 各种re…...

GPT-Omni 与 Mini-Omni2:创新与性能的结合
近年来,随着人工智能技术的飞速发展,各种模型和平台应运而生,以满足从个人用户到企业级应用的多样化需求。在这一领域,GPT-Omni 和 Mini-Omni2 是两款备受瞩目的技术产品,它们凭借独特的设计和强大的功能,在…...

探秘 JSON:数据交互的轻盈使者
文章目录 一、JSON是什么二、JSON的语法规则三、应用场景四、性能优化五、总结 一、JSON是什么 JSON(JavaScript Object Notation)即 JavaScript 对象表示法,是一种轻量级的数据交换格式。JSON 以键值对的形式组织数据,键是字符串…...

源码分析之Openlayers中的Attribution属性控件
概述 本文主要介绍 Openlayers 中Attribution属性控件的源码实现,该控件也是 Openlayers 中三个默认控件之一。默认情况下,控件会显示在地图的右下角,可以通过控件的类名设置CSS属性控制。实际应用中该控件主要显示与图层源source相关的所有…...

Shell自定义(二)
1.Shell自定义 1.初始化 定义全局变量environ,把g_env的内容用memset初始化为0,这里用malloc开辟的空间为对应环境变量的长度1,多1位置是最后结束符0,strcpy把此时的对应的环境变量拷贝到g_env里面,下面是新增一个环…...

自然语言处理:我的学习心得与笔记
Pytorch 1.Pytorch基本语法 1.1 认识Pytorch 1.2 Pytorch中的autograd 2.Pytorch初步应用 2.1 使用Pytorch构建一个神经网络 2.2 使用Pytorch构建一个分类器 小节总结 学习了什么是Pytorch. 。Pytorch是一个基于Numpy的科学计算包,作为Numpy的替代者,向用户提供使用GPU强大…...

Oracle 中什么情况下 可以使用 EXISTS 替代 IN 提高查询效率
为什么 EXISTS 更高效? EXISTS 提前终止: EXISTS 一旦在子查询中找到第一个匹配项,就会立即返回 TRUE,不再继续扫描子查询中的其他记录。IN 必须扫描整个子查询的结果集,将所有结果与主查询的每一行进行对比。大数据集…...

Spring基础分析08-集成JPA/Hibernate进行ORM操作
大家好,今天和大家一起分享一下Spring集成JPAHibernate进行ORM操作的流程~ JPA(Java Persistence API)作为Java EE标准的一部分,提供了统一的API来管理实体类和持久化上下文;Hibernate则是最流行的JPA实现之一&#x…...

MySQL知识汇总(一)
一些命令行操作注意加 分号 “ ; ” show databases 查看所有数据库 use 数据库名 切换数据库 show tables 查看数据库中所有表 describe 表名 显示表中所有信息 create database [if not exists] 新库名 创…...

PDFMathTranslate 一个基于AI优秀的PDF论文翻译工具
PDFMathTranslate 是一个设想中的工具,旨在翻译PDF文档中的数学内容。以下是这个工具的主要特点和使用方法: 链接:https://www.modelscope.cn/studios/AI-ModelScope/PDFMathTranslate 功能特点 数学公式识别:利用先进的OCR&…...

React+Vite从零搭建项目及配置详解
相信很多React初学者第一次搭建自己的项目,搭建时会无从下手,本篇适合快速实现功能,熟悉React项目搭建流程。 目录 一、创建项目react-item 二、调整项目目录结构 三、使用scss预处理器 四、组件库Ant Design 五、配置基础路由 六、配置…...

@pytest.fixture() 跟 @pytest.fixture有区别吗?
在iOS UI 自动化工程里面最早我用的是pytest.fixture(),因为在pycharm中联想出来的fixture是带()的,后来偶然一次我没有带()发现也没有问题,于是详细查了一下pytest.fixture() 和 pytest.fixtur…...

Google Cloud Architect 认证考试错题集5
Google Cloud Architect 认证考试错题集5 D. Store static content such as HTML and images in a Cloud Storage bucket. Use Cloud Functions to host the APIs and save the user data in Firestore. - Storing static content in a Cloud Storage bucket is a cost-effecti…...

【Maven】基础(一)
【Maven】基础一 1. 虽然工作有段时间了,但是深感maven了解的不深入,所以这次开始深入的学习。 课程地址: https://www.bilibili.com/video/BV1JN411G7gX?spm_id_from333.788.player.switch&vd_source240d9002f7c7e3da63cd9a975639409a&p2 1.…...

多模态抽取图片信息的 Prompt
多模态抽取图片信息的 Prompt 1. 中文版2. 日文版3. 英文原版 下面使用多模态从图片中抽取文章,表格,Flowcharts的Prompt。 1. 中文版 你是一位擅长提取图片、图表、文本并对其进行解释的专家,能够保持原始语言不变。## 指南- 针对输入内容…...

WPF 使用LibVLCSharp.WPF实现视频播放、停止、暂停功能
使用LibVLCSharp.WPF实现视频播放、停止、暂停功能 1, NuGet 添加 VideoLAN.LibVLC.Windows 2. NuGet 添加 LibVLCSharp.WPF 3. wpf 代码如下: <Grid ><Grid.RowDefinitions><RowDefinition Height"*" /><RowDefinition Height&q…...

Java全栈项目 - 校园招聘信息平台
项目介绍 校园招聘信息平台是一个面向高校学生和企业的双向服务平台。该系统帮助企业发布招聘信息,方便学生查询职位并投递简历,同时为学校就业部门提供就业数据分析功能。 技术栈 后端 Spring Boot 2.xSpring SecurityMyBatis PlusMySQL 8.0RedisRabbitMQ 前端 Vue.js 2…...

java导出
请求头获取responseimport com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet;PostMapping("excel/export") ApiOperation(value "党员档案导出", httpMethod "POST")…...

【嵌入式系统】期末试题库,ARM处理器,CortexM3内核,USART,EXTI,GPIO
关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...

arcgisPro相接多个面要素转出为完整独立线要素
1、使用【面转线】工具,并取消勾选“识别和存储面邻域信息”,如下: 2、得到的线要素,如下:...

QTday1
#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口标题this->setWindowTitle("向日葵远程控制");//设置窗口图标this->setWindowIcon(QIcon("C:\\Users\\Hasee\\Desktop\\pictrue\\mypicture\\logo.png&…...