Vue項目代碼詳細講解
1. jsconfig.json - JavaScript配置文件
{"compilerOptions": { // 編譯器選項配置"target": "es5", // 編譯目標:將代碼編譯為ES5版本,確保更好的瀏覽器兼容性"module": "esnext", // 模塊系統:使用最新的ES模塊系統"baseUrl": "./", // 基礎路徑:設置為項目根目錄"moduleResolution": "node", // 模塊解析策略:使用Node.js的模塊解析方式"paths": { // 路徑映射配置"@/*": [ // 定義@符號作為src目錄的別名"src/*" // @/xxx 會被解析為 src/xxx]},"lib": [ // 包含的類型定義庫"esnext", // 包含最新的ES特性"dom", // 包含DOM相關的類型定義"dom.iterable", // 包含DOM可迭代對象的類型定義"scripthost" // 包含Windows Script Host的類型定義]}
}
作用說明:
- 這個文件為VSCode等IDE提供JavaScript項目的智能提示
- 配置路徑別名讓導入更簡潔(使用@代替src)
- 確保IDE能正確理解項目的模塊系統和語法特性
2. vue.config.js - Vue CLI配置文件
// vue.config.js
const { defineConfig } = require("@vue/cli-service"); // 導入Vue CLI的配置函數module.exports = defineConfig({ // 導出配置對象transpileDependencies: true, // 轉譯所有依賴包(包括node_modules中的)// 開發服務器配置devServer: {port: 8081, // 前端開發服務器端口host: '0.0.0.0', // 允許任何主機訪問(不僅限localhost)open: false, // 啟動時不自動打開瀏覽器allowedHosts: 'all', // 允許所有主機名訪問(解決主機名驗證問題)proxy: { // 代理配置,解決開發環境的跨域問題"/api": { // 匹配所有以/api開頭的請求target: "http://localhost:8080", // 代理目標:后端服務器地址changeOrigin: true, // 改變請求頭中的origin(必要的跨域配置)pathRewrite: { // 路徑重寫規則"^/api": "/api", // 保持/api前綴不變},},},},// 生產環境配置productionSourceMap: false, // 生產環境不生成source map(減小打包體積,提高安全性)// 開發環境生成 source map(用于調試)configureWebpack: {devtool: process.env.NODE_ENV === 'development' ? 'source-map' : false// 開發環境使用source-map便于調試,生產環境關閉},// CSS相關配置css: {loaderOptions: { // CSS加載器選項scss: { // SCSS配置// 全局引入scss變量文件(當前被注釋)// additionalData: `@import "@/styles/variables.scss";`// 如果啟用,會在每個組件的樣式中自動引入這個文件},},},
});
關鍵配置說明:
- devServer.proxy:解決前后端分離開發時的跨域問題
- host: ‘0.0.0.0’:允許局域網內其他設備訪問
- productionSourceMap:生產環境關閉源碼映射,保護源代碼
3. .eslintrc.js - ESLint配置文件
module.exports = {root: true, // 標識這是項目根目錄的ESLint配置,停止向上查找env: { // 指定代碼運行環境node: true // Node.js環境(支持require、module等)},extends: [ // 繼承的規則集'plugin:vue/vue3-essential', // Vue3基本規則'eslint:recommended' // ESLint推薦規則],parserOptions: { // 解析器選項parser: '@babel/eslint-parser' // 使用Babel解析器(支持最新JS語法)},rules: { // 自定義規則'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',// console語句:生產環境警告,開發環境允許'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',// debugger語句:生產環境警告,開發環境允許'vue/multi-word-component-names': 'off'// 關閉Vue組件名必須多個單詞的規則(允許單詞組件名如Profile)}
}
規則說明:
- 開發環境允許console和debugger便于調試
- 生產環境對這些語句發出警告,提醒清理
- 關閉組件命名限制,提高開發靈活性
4. babel.config.js - Babel配置文件
module.exports = {presets: ["@vue/cli-plugin-babel/preset"], // 使用Vue CLI提供的Babel預設// 包含了Vue項目所需的所有Babel插件和配置
};
作用:
- 將現代JavaScript轉譯為兼容性更好的版本
- 支持Vue的JSX語法和其他特性
5. Profile.vue - 個人資料頁面組件
模板部分解析
<template><div class="profile"> <!-- 頁面根容器 --><el-card> <!-- Element Plus卡片組件 --><template #header> <!-- 卡片頭部插槽 --><div class="card-header"><span>個人信息</span><el-button type="primary" size="small" @click="isEdit = !isEdit"><!-- 切換編輯狀態的按鈕,根據狀態顯示不同文字 -->{{ isEdit ? "取消編輯" : "編輯信息" }}</el-button></div></template><el-formref="profileFormRef" <!-- 表單引用,用于調用表單方法 -->:model="profileForm" <!-- 綁定表單數據對象 -->:rules="rules" <!-- 表單驗證規則 -->:disabled="!isEdit" <!-- 非編輯狀態時禁用所有輸入 -->label-width="100px" <!-- 標簽寬度 -->style="max-width: 600px" <!-- 限制表單最大寬度 -->><!-- 用戶ID(始終禁用) --><el-form-item label="用戶ID"><el-input v-model="profileForm.id" disabled /></el-form-item><!-- 用戶名(始終禁用) --><el-form-item label="用戶名"><el-input v-model="profileForm.username" disabled /></el-form-item><!-- 郵箱(可編輯,帶驗證) --><el-form-item label="郵箱" prop="email"><el-input v-model="profileForm.email" /></el-form-item><!-- 手機號(可編輯,帶驗證) --><el-form-item label="手機號" prop="phone"><el-input v-model="profileForm.phone" /></el-form-item><!-- 分數顯示(使用標簽展示,顏色根據分數變化) --><el-form-item label="分數"><el-tag :type="getScoreType(profileForm.score)" size="large">{{ profileForm.score }} 分</el-tag></el-form-item><!-- 賬號狀態顯示 --><el-form-item label="賬號狀態"><el-tag :type="profileForm.status === 1 ? 'success' : 'danger'">{{ profileForm.status === 1 ? "正常" : "已禁用" }}</el-tag></el-form-item><!-- 時間戳顯示 --><el-form-item label="注冊時間"><el-input :value="formatDate(profileForm.createTime)" disabled /></el-form-item><el-form-item label="更新時間"><el-input :value="formatDate(profileForm.updateTime)" disabled /></el-form-item><!-- 編輯模式下的操作按鈕 --><el-form-item v-if="isEdit"><el-button type="primary" @click="saveProfile">保存修改</el-button><el-button @click="cancelEdit">取消</el-button></el-form-item></el-form></el-card><!-- 修改密碼卡片 --><el-card style="margin-top: 20px"><template #header><span>修改密碼</span></template><el-formref="passwordFormRef":model="passwordForm":rules="passwordRules"label-width="100px"style="max-width: 600px"><!-- 原密碼輸入 --><el-form-item label="原密碼" prop="oldPassword"><el-inputv-model="passwordForm.oldPassword"type="password" <!-- 密碼類型輸入框 -->show-password <!-- 顯示密碼切換按鈕 -->/></el-form-item><!-- 新密碼輸入 --><el-form-item label="新密碼" prop="newPassword"><el-inputv-model="passwordForm.newPassword"type="password"show-password/></el-form-item><!-- 確認密碼輸入 --><el-form-item label="確認密碼" prop="confirmPassword"><el-inputv-model="passwordForm.confirmPassword"type="password"show-password/></el-form-item><!-- 密碼表單操作按鈕 --><el-form-item><el-button type="primary" @click="handleChangePassword">修改密碼</el-button><el-button @click="resetPasswordForm">重置</el-button></el-form-item></el-form></el-card></div>
</template>
Script部分解析
<script setup>
// 使用Vue 3的Composition API + setup語法糖
import { ref, reactive, onMounted } from "vue"; // Vue核心響應式API
import { useStore } from "vuex"; // Vuex狀態管理
import { useRouter } from "vue-router"; // 路由
import { ElMessage } from "element-plus"; // 消息提示組件
import { getUser, updateUser, changePassword } from "@/api/user"; // API接口const store = useStore(); // 獲取Vuex store實例
const router = useRouter(); // 獲取路由實例
const currentUser = store.getters.user; // 從store獲取當前用戶信息// 響應式數據定義
const isEdit = ref(false); // 編輯狀態標志
const profileFormRef = ref(); // 個人信息表單引用
const passwordFormRef = ref(); // 密碼表單引用// 個人信息表單數據(響應式對象)
const profileForm = reactive({id: "",username: "",email: "",phone: "",score: 0,status: 1,createTime: "",updateTime: "",
});// 修改密碼表單數據
const passwordForm = reactive({oldPassword: "",newPassword: "",confirmPassword: "",
});// 表單驗證規則
const rules = {email: [{ required: true, message: "請輸入郵箱", trigger: "blur" }, // 必填{ type: "email", message: "請輸入正確的郵箱地址", trigger: "blur" }, // 郵箱格式],phone: [{pattern: /^1[3-9]\d{9}$/, // 手機號正則:1開頭,第二位3-9,后面9位數字message: "請輸入正確的手機號",trigger: "blur", // 失去焦點時觸發驗證},],
};// 密碼表單驗證規則
const passwordRules = {oldPassword: [{ required: true, message: "請輸入原密碼", trigger: "blur" }],newPassword: [{ required: true, message: "請輸入新密碼", trigger: "blur" },{ min: 6, max: 20, message: "密碼長度在 6 到 20 個字符", trigger: "blur" },],confirmPassword: [{ required: true, message: "請再次輸入新密碼", trigger: "blur" },{validator: (rule, value, callback) => { // 自定義驗證器if (value !== passwordForm.newPassword) {callback(new Error("兩次輸入密碼不一致"));} else {callback(); // 驗證通過}},trigger: "blur",},],
};// 獲取分數標簽類型(根據分數返回不同顏色)
const getScoreType = (score) => {if (score >= 90) return "success"; // 綠色if (score >= 60) return "warning"; // 橙色return "danger"; // 紅色
};// 格式化日期時間
const formatDate = (dateStr) => {if (!dateStr) return "";return new Date(dateStr).toLocaleString("zh-CN"); // 轉換為中文格式
};// 加載用戶信息
const loadUserInfo = async () => {try {const res = await getUser(currentUser.id); // 調用API獲取用戶信息Object.assign(profileForm, res.data); // 將返回數據合并到表單對象} catch (error) {ElMessage.error("獲取用戶信息失敗");}
};// 保存個人信息
const saveProfile = async () => {const valid = await profileFormRef.value.validate(); // 表單驗證if (!valid) return; // 驗證失敗則返回try {await updateUser(profileForm.id, {email: profileForm.email,phone: profileForm.phone,});// 更新store中的用戶信息store.commit("SET_USER", { ...currentUser, ...profileForm });ElMessage.success("保存成功");isEdit.value = false; // 退出編輯模式} catch (error) {ElMessage.error("保存失敗");}
};// 取消編輯
const cancelEdit = () => {isEdit.value = false; // 退出編輯模式loadUserInfo(); // 重新加載原始數據
};// 修改密碼
const handleChangePassword = async () => {const valid = await passwordFormRef.value.validate();if (!valid) return;try {// 調用修改密碼APIawait changePassword(currentUser.id, {oldPassword: passwordForm.oldPassword,newPassword: passwordForm.newPassword,});ElMessage.success("密碼修改成功,請重新登錄");// 清空密碼表單resetPasswordForm();// 1.5秒后退出登錄并跳轉到登錄頁setTimeout(async () => {await store.dispatch("logout"); // 調用store的logout actionrouter.push("/login"); // 跳轉到登錄頁}, 1500);} catch (error) {ElMessage.error(error.message || "密碼修改失敗");}
};// 重置密碼表單
const resetPasswordForm = () => {passwordFormRef.value?.resetFields(); // 使用可選鏈調用表單重置方法
};// 組件掛載時加載用戶信息
onMounted(() => {loadUserInfo();
});
</script>
樣式部分
<style scoped lang="scss">
.profile { // 頁面容器樣式.card-header { // 卡片頭部樣式display: flex; // 彈性布局justify-content: space-between; // 兩端對齊align-items: center; // 垂直居中}
}
</style>
6. UserManagement.vue - 用戶管理頁面組件
模板部分詳解
<template><div class="user-management"><!-- 搜索和操作欄 --><el-card class="search-card"><el-row :gutter="20"> <!-- 柵格布局,列間距20px --><el-col :span="6"> <!-- 占6格(共24格) --><el-inputv-model="searchForm.username" <!-- 雙向綁定搜索關鍵詞 -->placeholder="請輸入用戶名"clearable <!-- 顯示清空按鈕 -->@clear="handleSearch" <!-- 清空時觸發搜索 -->@keyup.enter="handleSearch" <!-- 回車鍵觸發搜索 -->><template #prefix> <!-- 前綴圖標插槽 --><el-icon><Search /></el-icon></template></el-input></el-col><el-col :span="6"><el-button type="primary" @click="handleSearch">搜索</el-button><el-button @click="resetSearch">重置</el-button></el-col><el-col :span="12" style="text-align: right"> <!-- 右對齊 --><el-button type="primary" @click="showAddDialog"><el-icon><Plus /></el-icon>新增用戶</el-button><el-button type="success" @click="handleExport"><el-icon><Download /></el-icon>導出CSV</el-button><!-- 文件上傳組件 --><el-upload:show-file-list="false" <!-- 不顯示已上傳文件列表 -->:before-upload="handleImport" <!-- 上傳前的鉤子函數 -->accept=".csv" <!-- 只接受CSV文件 -->style="display: inline-block; margin-left: 10px"><el-button type="warning"><el-icon><Upload /></el-icon>導入CSV</el-button></el-upload></el-col></el-row></el-card><!-- 數據表格 --><el-card class="table-card"><el-table:data="tableData" <!-- 綁定表格數據 -->v-loading="loading" <!-- 加載狀態 -->stripe <!-- 斑馬紋樣式 -->style="width: 100%"><!-- 表格列定義 --><el-table-column prop="id" label="ID" width="80" /><el-table-column prop="username" label="用戶名" /><el-table-column prop="email" label="郵箱" /><el-table-column prop="phone" label="手機號" /><!-- 分數列(自定義內容) --><el-table-column prop="score" label="分數" width="80"><template #default="{ row }"> <!-- 作用域插槽,row是當前行數據 --><el-tag :type="getScoreType(row.score)">{{ row.score }}</el-tag></template></el-table-column><!-- 狀態列(開關組件) --><el-table-column prop="status" label="狀態" width="100"><template #default="{ row }"><el-switchv-model="row.status" <!-- 直接綁定行數據 -->:active-value="1" <!-- 開啟時的值 -->:inactive-value="0" <!-- 關閉時的值 -->@change="handleStatusChange(row)" <!-- 狀態改變時觸發 -->/></template></el-table-column><!-- 創建時間列 --><el-table-column prop="createTime" label="創建時間" width="180"><template #default="{ row }">{{ formatDate(row.createTime) }}</template></el-table-column><!-- 操作列 --><el-table-column label="操作" width="200" fixed="right"> <!-- fixed="right"固定在右側 --><template #default="{ row }"><el-button type="primary" size="small" @click="showEditDialog(row)">編輯</el-button><el-button type="danger" size="small" @click="handleDelete(row)">刪除</el-button></template></el-table-column></el-table><!-- 分頁組件 --><el-paginationv-model:current-page="pagination.pageNum" <!-- 當前頁 -->v-model:page-size="pagination.pageSize" <!-- 每頁條數 -->:page-sizes="[10, 20, 50, 100]" <!-- 可選的每頁條數 -->:total="pagination.total" <!-- 總條數 -->layout="total, sizes, prev, pager, next, jumper" <!-- 顯示的組件 -->@size-change="handleSizeChange" <!-- 每頁條數改變 -->@current-change="handleCurrentChange" <!-- 頁碼改變 -->style="margin-top: 20px"/></el-card><!-- 新增/編輯對話框 --><el-dialogv-model="dialogVisible" <!-- 控制顯示隱藏 -->:title="dialogTitle" <!-- 動態標題 -->width="500px"@close="resetForm" <!-- 關閉時重置表單 -->><el-formref="userFormRef":model="userForm":rules="rules"label-width="80px"><el-form-item label="用戶名" prop="username"><el-inputv-model="userForm.username"placeholder="請輸入用戶名":disabled="isEdit" <!-- 編輯時禁用用戶名 -->/></el-form-item><!-- 密碼項只在新增時顯示 --><el-form-item label="密碼" prop="password" v-if="!isEdit"><el-inputv-model="userForm.password"type="password"placeholder="請輸入密碼"show-password/></el-form-item><el-form-item label="郵箱" prop="email"><el-input v-model="userForm.email" placeholder="請輸入郵箱" /></el-form-item><el-form-item label="手機號" prop="phone"><el-input v-model="userForm.phone" placeholder="請輸入手機號" /></el-form-item><el-form-item label="分數" prop="score"><el-input-numberv-model="userForm.score":min="0" <!-- 最小值 -->:max="100" <!-- 最大值 -->placeholder="請輸入分數"/></el-form-item><el-form-item label="狀態" prop="status"><el-radio-group v-model="userForm.status"><el-radio :value="1">啟用</el-radio><el-radio :value="0">禁用</el-radio></el-radio-group></el-form-item></el-form><!-- 對話框底部按鈕 --><template #footer><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="submitForm">確定</el-button></template></el-dialog></div>
</template>
Script部分詳解
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import {getUserList,createUser,updateUser,deleteUser,exportUsersCsv,importUsersCsv,
} from "@/api/user"; // 導入所有用戶相關API// ===== 響應式數據定義 =====
const loading = ref(false); // 加載狀態
const tableData = ref([]); // 表格數據
const dialogVisible = ref(false); // 對話框顯示狀態
const isEdit = ref(false); // 是否編輯模式
const userFormRef = ref(); // 表單引用// 搜索表單
const searchForm = reactive({username: "", // 搜索關鍵詞
});// 分頁配置
const pagination = reactive({pageNum: 1, // 當前頁pageSize: 10, // 每頁條數total: 0, // 總條數
});// 用戶表單數據
const userForm = reactive({id: null,username: "",password: "",email: "",phone: "",score: 0,status: 1, // 默認啟用
});// 表單驗證規則
const rules = {username: [{ required: true, message: "請輸入用戶名", trigger: "blur" },{ min: 3, max: 20, message: "長度在 3 到 20 個字符", trigger: "blur" },],password: [{ required: true, message: "請輸入密碼", trigger: "blur" },{ min: 6, max: 20, message: "長度在 6 到 20 個字符", trigger: "blur" },],email: [{ required: true, message: "請輸入郵箱", trigger: "blur" },{ type: "email", message: "請輸入正確的郵箱地址", trigger: "blur" },],phone: [{pattern: /^1[3-9]\d{9}$/,message: "請輸入正確的手機號",trigger: "blur",},],
};// 動態計算的對話框標題
const dialogTitle = ref("新增用戶");// ===== 工具函數 =====// 獲取分數對應的標簽類型
const getScoreType = (score) => {if (score >= 90) return "success";if (score >= 60) return "warning";return "danger";
};// 格式化日期
const formatDate = (dateStr) => {if (!dateStr) return "";const date = new Date(dateStr);return date.toLocaleString("zh-CN");
};// ===== 業務邏輯函數 =====// 獲取用戶列表
const getList = async () => {loading.value = true; // 開啟加載狀態try {const params = {pageNum: pagination.pageNum,pageSize: pagination.pageSize,};// 如果有搜索條件,添加到參數中if (searchForm.username) {params.username = searchForm.username;}const res = await getUserList(params); // 調用APItableData.value = res.data.list; // 設置表格數據pagination.total = res.data.total; // 設置總條數} catch (error) {ElMessage.error("獲取用戶列表失敗");} finally {loading.value = false; // 關閉加載狀態}
};// 搜索處理
const handleSearch = () => {pagination.pageNum = 1; // 搜索時重置到第一頁getList();
};// 重置搜索
const resetSearch = () => {searchForm.username = ""; // 清空搜索條件handleSearch(); // 重新搜索
};// 分頁大小改變
const handleSizeChange = () => {pagination.pageNum = 1; // 改變每頁條數時重置到第一頁getList();
};// 頁碼改變
const handleCurrentChange = () => {getList(); // 重新獲取數據
};// 顯示新增對話框
const showAddDialog = () => {isEdit.value = false; // 設置為新增模式dialogTitle.value = "新增用戶";dialogVisible.value = true;
};// 顯示編輯對話框
const showEditDialog = (row) => {isEdit.value = true; // 設置為編輯模式dialogTitle.value = "編輯用戶";Object.assign(userForm, row); // 將行數據復制到表單dialogVisible.value = true;
};// 提交表單
const submitForm = async () => {const valid = await userFormRef.value.validate(); // 表單驗證if (!valid) return;try {if (isEdit.value) {// 編輯模式:調用更新APIawait updateUser(userForm.id, userForm);ElMessage.success("更新成功");} else {// 新增模式:調用創建APIawait createUser(userForm);ElMessage.success("創建成功");}dialogVisible.value = false; // 關閉對話框getList(); // 刷新列表} catch (error) {ElMessage.error(error.message || "操作失敗");}
};// 重置表單
const resetForm = () => {userFormRef.value?.resetFields(); // 重置表單驗證狀態// 重置表單數據Object.assign(userForm, {id: null,username: "",password: "",email: "",phone: "",score: 0,status: 1,});
};// 狀態切換
const handleStatusChange = async (row) => {try {await updateUser(row.id, { status: row.status }); // 只更新狀態ElMessage.success("狀態更新成功");} catch (error) {// 失敗時恢復原狀態row.status = row.status === 1 ? 0 : 1;ElMessage.error("狀態更新失敗");}
};// 刪除用戶
const handleDelete = async (row) => {try {// 顯示確認對話框await ElMessageBox.confirm(`確定要刪除用戶 ${row.username} 嗎?`,"刪除確認",{confirmButtonText: "確定",cancelButtonText: "取消",type: "warning",});await deleteUser(row.id); // 調用刪除APIElMessage.success("刪除成功");getList(); // 刷新列表} catch (error) {// 用戶取消操作不顯示錯誤if (error !== "cancel") {ElMessage.error("刪除失敗");}}
};// 導出CSV
const handleExport = async () => {try {const res = await exportUsersCsv(); // 調用導出API// 創建Blob對象(二進制大對象)const url = window.URL.createObjectURL(new Blob([res], { type: "text/csv;charset=utf-8;" }));// 創建臨時下載鏈接const link = document.createElement("a");link.href = url;link.download = `用戶數據_${new Date().getTime()}.csv`; // 文件名帶時間戳document.body.appendChild(link);link.click(); // 觸發下載// 清理:移除鏈接并釋放URL對象setTimeout(() => {document.body.removeChild(link);window.URL.revokeObjectURL(url);}, 100);ElMessage.success("導出成功");} catch (error) {console.error("導出錯誤:", error);ElMessage.error("導出失敗: " + (error.message || "未知錯誤"));}
};// 導入CSV
const handleImport = async (file) => {// 創建FormData對象用于文件上傳const formData = new FormData();formData.append("file", file);try {const res = await importUsersCsv(formData); // 調用導入APIconst { successCount, errorCount, errors } = res.data;// 根據導入結果顯示不同提示if (errorCount > 0) {ElMessage.warning(`導入完成:成功 ${successCount} 條,失敗 ${errorCount} 條`);console.error("導入錯誤:", errors); // 控制臺輸出錯誤詳情} else {ElMessage.success(`導入成功:共 ${successCount} 條數據`);}getList(); // 刷新列表} catch (error) {ElMessage.error("導入失敗");}return false; // 阻止el-upload的默認上傳行為
};// ===== 生命周期 =====
onMounted(() => {getList(); // 組件掛載時加載數據
});
</script>
樣式部分
<style scoped lang="scss">
.user-management {.search-card {margin-bottom: 20px; // 搜索卡片底部間距}.table-card {.el-table {margin-bottom: 20px; // 表格底部間距}}
}
</style>
總結
這個Vue 3項目展示了一個完整的用戶管理系統,主要特點:
-
技術棧:
- Vue 3 + Composition API
- Element Plus UI框架
- Vuex狀態管理
- Vue Router路由
- Axios HTTP請求
-
功能特性:
- 用戶的增刪改查
- 分頁和搜索
- CSV導入導出
- 表單驗證
- 權限狀態管理
- 個人信息編輯
- 密碼修改
-
最佳實踐:
- 組件化開發
- 響應式數據管理
- 統一的錯誤處理
- 代碼注釋規范
- 模塊化的API管理