重生之我在学Vue--第18天 Vue 3 项目功能扩展
重生之我在学Vue–第18天 Vue 3 项目功能扩展
文章目录
- 重生之我在学Vue--第18天 Vue 3 项目功能扩展
- 前言
- 一、权限管理系统
- 1.1 用户角色体系设计
- 1.2 路由权限控制
- 1.3 组件级权限控制
- 二、分页与搜索系统
- 2.1 分页类型对比
- 2.2 分页组件实现
- 2.3 搜索功能实现
- 三、文件上传系统
- 3.1 文件上传组件
- 3.2 阿里云OSS集成
- 四、今日任务:扩展项目功能
- 4.1 必做任务清单
- 4.2 扩展挑战
前言
当项目具备基础功能后,我们需要像搭乐高一样添加更复杂的模块!今天我们将解锁三大高阶能力:权限控制、数据分页和文件处理,让你的任务管理系统具备企业级应用雏形!
Vue3 官方中文文档传送点: 组合式函数 | Vue.js
功能扩展的核心是逻辑复用与架构分层,避免代码变成"意大利面条"!
Vue前端成仙之路:Vue 前端成仙之路_野生的程序嫣的博客-CSDN博客
GO后端成神之路:Go 后端成神之路_野生的程序嫣的博客-CSDN博客
一、权限管理系统
1.1 用户角色体系设计
// types/user.d.ts
interface User {
id: string
username: string
role: 'admin' | 'user'
avatar?: string
}
// stores/auth.ts
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null as User | null,
token: localStorage.getItem('token') || ''
}),
actions: {
login(userData: { username: string; password: string }) {
// 模拟登录接口
this.user = { id: '1', username: userData.username, role: 'admin' }
this.token = 'mock_token'
localStorage.setItem('token', this.token)
}
}
})
1.2 路由权限控制
// router/index.js
router.beforeEach((to) => {
const authStore = useAuthStore()
// 需要登录且未登录
if (to.meta.requiresAuth && !authStore.token) {
return '/login'
}
// 检查角色权限
if (to.meta.roles && !to.meta.roles.includes(authStore.user?.role)) {
return '/403' // 无权限页面
}
})
1.3 组件级权限控制
<template>
<button
v-if="hasPermission('delete')"
@click="handleDelete"
>
删除任务
</button>
</template>
<script setup>
import { useAuthStore } from '@/stores/auth'
const authStore = useAuthStore()
const hasPermission = (action) => {
return authStore.user?.role === 'admin' ||
(action === 'view' && authStore.user)
}
</script>
二、分页与搜索系统
2.1 分页类型对比
分页方式 | 适用场景 | 实现要点 |
---|---|---|
前端分页 | 数据量小(<1000条) | 一次性加载后JS处理 |
后端分页 | 大数据量 | 需要API支持page/size参数 |
滚动加载 | 移动端场景 | 监听滚动事件+节流处理 |
2.2 分页组件实现
<template>
<div class="pagination">
<button
v-for="page in pages"
:key="page"
:class="{ active: currentPage === page }"
@click="changePage(page)"
>
{{ page }}
</button>
</div>
</template>
<script setup>
const props = defineProps({
total: Number,
pageSize: Number,
currentPage: Number
})
const emit = defineEmits(['update:currentPage'])
const pages = computed(() => {
return Math.ceil(props.total / props.pageSize)
})
const changePage = (page) => {
emit('update:currentPage', page)
}
</script>
2.3 搜索功能实现
// 前端搜索(适用于小数据)
const filteredList = computed(() => {
return tasks.value.filter(task =>
task.title.includes(searchKeyword.value) ||
task.description.includes(searchKeyword.value)
)
})
// 后端搜索(推荐)
const loadData = async () => {
const res = await axios.get('/api/tasks', {
params: {
page: currentPage.value,
size: pageSize.value,
keyword: searchKeyword.value
}
})
tasks.value = res.data
}
三、文件上传系统
3.1 文件上传组件
<template>
<div class="uploader">
<input type="file" @change="handleFileChange" />
<progress :value="progress" max="100"></progress>
<button @click="upload">开始上传</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const file = ref(null)
const progress = ref(0)
const handleFileChange = (e) => {
file.value = e.target.files[0]
}
const upload = async () => {
const formData = new FormData()
formData.append('file', file.value)
await axios.post('/api/upload', formData, {
onUploadProgress: (e) => {
progress.value = Math.round((e.loaded / e.total) * 100)
}
})
}
</script>
3.2 阿里云OSS集成
// utils/oss.js
import OSS from 'ali-oss'
export const ossClient = new OSS({
region: 'oss-cn-shanghai',
accessKeyId: import.meta.env.VITE_OSS_KEY,
accessKeySecret: import.meta.env.VITE_OSS_SECRET,
bucket: 'your-bucket'
})
// 前端直传示例
const uploadToOSS = async (file) => {
const result = await ossClient.put(`uploads/${Date.now()}_${file.name}`, file)
return result.url
}
四、今日任务:扩展项目功能
4.1 必做任务清单
-
角色权限系统
• 添加登录页面(区分admin/user角色)
• 实现路由守卫权限控制
• 动态渲染导航菜单(根据角色显示不同功能) -
分页功能
• 为任务列表添加分页组件
• 实现前后端分页切换功能(配置开关)
• 添加页码跳转输入框 -
文件上传
• 允许为任务添加附件
• 实现上传进度显示
• 限制文件类型为图片/PDF(最大10MB)
4.2 扩展挑战
// 大文件分片上传(断点续传)
const uploadChunk = async (file, chunkSize = 1024 * 1024) => {
let chunkIndex = 0
const chunks = Math.ceil(file.size / chunkSize)
while (chunkIndex < chunks) {
const start = chunkIndex * chunkSize
const end = Math.min(file.size, start + chunkSize)
const chunk = file.slice(start, end)
await axios.post('/api/upload', {
chunk,
index: chunkIndex,
total: chunks,
fileHash: fileHash
})
chunkIndex++
}
}