Vue入门之Web端CURD前端项目示例
Vue入門之Web端CURD前端項目示例
隨著vue.js越來越火,很多不太懂前端的小伙伴想要入坑。而入坑最好的辦法就是上手實際操作,因此本文將重點放在實際操作上,對理論不做過多解釋,不明白的地方小伙伴們可以去看官方文檔或者相關書籍。
目錄
- 一、安裝npm
- 二、安裝vue-cli
- 三、使用vue-cli創建項目
- 四、修改項目配置
- 五、啟動項目
- 六、安裝依賴
- 七、建立基本視圖框架
- 八、完善CURD功能
- 九、總結
本文的示例項目操作環境如下:
| 操作系統 | Mac OS 10.13.6 (17G65) |
| 瀏覽器 | Chrome 77.0.3865.120 |
| nvm下nodejs版本 | 10.13.0 |
| 編輯器 | Visual Studio Code 1.39.2 |
一、安裝npm
npm有多種安裝方式,這里推薦使用nvm進行安裝。
1.1 安裝nvm
- windows
地址:https://github.com/coreybutler/nvm-windows/releases
根據文檔說明安裝,記得設置淘寶的鏡像。
nvm node_mirror https://npm.taobao.org/mirrors/node/ nvm npm_mirror https://npm.taobao.org/mirrors/npm/或者修改settings.txt文件,在后面加上淘寶鏡像設置。
node_mirror: https://npm.taobao.org/mirrors/node/ npm_mirror: https://npm.taobao.org/mirrors/npm/- linux/mac
地址:https://github.com/creationix/nvm
根據文檔說明安裝,記得設置淘寶的鏡像。
# bash_profile export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node1.2 配置npm
npm config set registry https://registry.npm.taobao.org npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass1.3 安裝yarn
npm install -g yarn1.4 配置yarn
已配置過npm則無需再次配置。
yarn config set registry https://registry.npm.taobao.org -g yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g二、安裝vue-cli
細心的小伙伴會發現vue官網是不推薦入門直接上vue-cli的,這里考慮到很多小伙伴不是前端工程師,而僅僅是需要了解vue項目的基本結構,所以直接使用vue-cli創建項目吧。
使用npm或者yarn全局安裝vue-cli:
注意:這里的@vue/cli不要寫成了vue-cli,vue-cli是舊版本。
npm install -g @vue/cli # OR yarn global add @vue/cli三、使用vue-cli創建項目
現在可以開始使用vue-cli創建項目了,這里項目名稱為example-curd。
這里也可以通過vue ui來創建,使用方法是控制臺輸入vue ui,具體內容本文不做展示
vue create example-curd這時會有一個選項,第一項為默認配置,這里我們選擇第二項手動配置,回車確定。
之后會出現一個多選,這時的操作是空格鍵選擇,空格選擇完所有需要的配置之后,最后按回車確定。
本文用于演示基本的項目流程,只選擇3項,其它項小伙伴們自行查閱資料按需選擇
選好依賴項后,進入vue-router設置提示,是否使用history mode,輸入n然后回車確定。
這里的區別小伙伴們自己查閱資料。
然后會問如何處理Babel、ESLint之類的配置文件,這里為了便于修改,不與package.json混在一起,選擇第一項。
最后問你是否記錄下這套配置,由于本文只是演示,選擇的配置項并不適合正式項目,所以選擇不記錄。
選擇包管理器,這里推薦使用yarn。
項目配置完成。
四、修改項目配置
生成的項目目錄結構如圖:
為了避免默認端口被占用的情況,我們新建一個名為vue.config.js的配置文件,指定host與port。配置參考
五、啟動項目
可以在package.json中修改腳本命令,例如增加一個與serve功能相同的dev命令:
{"name": "example-curd","version": "0.1.0","private": true,"scripts": {"serve": "vue-cli-service serve","build": "vue-cli-service build","dev": "vue-cli-service serve"},"dependencies": {"core-js": "^3.1.2","vue": "^2.6.10","vue-router": "^3.0.6","vuex": "^3.0.1"},"devDependencies": {"@vue/cli-plugin-babel": "^4.0.0","@vue/cli-plugin-router": "^4.0.0","@vue/cli-plugin-vuex": "^4.0.0","@vue/cli-service": "^4.0.0","vue-template-compiler": "^2.6.10"} }啟動項目
yarn dev至此,基本的項目創建與啟動演示完畢,接下來進入實例演示。
六、安裝依賴
本文主要目的是演示創建基本CURD的前端WEB頁面,因此不做后端API的創建,這里使用mock.js攔截請求并返回模擬數據。
本文需要用到的依賴有:
- element-ui
- mockjs
- axios
使用yarn安裝以上依賴
如果已經啟動了項目,可以先ctrl + c退出,安裝完依賴后再啟動。
yarn add element-ui mockjs axios七、建立基本視圖框架
修改App.vue、main.js、router.js,同時刪除項目創建時的默認文件About.vue、Home.vue、HelloWorld.vue,在src/views目錄下創建一個layout目錄和page目錄,分別用于存放布局和頁面。
7.1 修改main.js文件
引入element組件庫及其樣式
這里的@在vue-cli默認語法中代表項目中的src目錄
src/main.js:
import Vue from 'vue'; import App from '@/App.vue'; import router from '@/router'; import store from '@/store'; import ElementUI from 'element-ui'; // ElementUI組件庫 import 'element-ui/packages/theme-chalk/lib/index.css'; // ElementUI組件庫樣式// 注冊餓了么UI Vue.use(ElementUI);new Vue({router,store,render: h => h(App) }).$mount('#app')7.2 修改App.vue
同時調整一些必要的全局html樣式。
src/App.vue:
<template><div id="app"><router-view></router-view></div> </template><style> html, body {padding: 0;margin: 0; } #app {font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,Microsoft YaHei, SimSun, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale; } a:focus, a:active {outline: none; }a, a:focus, a:hover {cursor: pointer;color: inherit;text-decoration: none; } </style>7.3 創建布局文件
在layout目錄下創建一個default.vue作為默認布局文件,初學可以使用element的Container 布局容器組件。
src/views/layout/default.vue:
<template><el-container><el-aside width="200px">Aside</el-aside><el-container><el-header>Header</el-header><el-main><router-view></router-view></el-main></el-container></el-container> </template>7.4 修改router
指定src/views/page/index.vue為本項目默認首頁,且作用于默認布局下。
() => import(‘xxx’) 為動態加載組件,這樣做的好處是用到哪個頁面加載哪個頁面,避免導致首頁加載時間過長。
src/router/index.js:
import Vue from 'vue' import VueRouter from 'vue-router' import DefaultLayout from '@/views/layout/default'Vue.use(VueRouter)const routes = [{path: '',component: DefaultLayout,redirect: 'index',children: [{path: 'index',name: 'index',component: () => import('@/views/page/index'),}],}, ]const router = new VueRouter({routes })export default router;7.5 修改index.vue
修改首頁內容,測試布局是否生效。
src/views/page/index.vue:
<template><div><el-button type="primary">首頁的按鈕</el-button></div> </template>7.6 查看基本布局是否生效
可以看到首頁的ElementUI的按鈕組件正常顯示,且首頁位于默認布局之下。
此時項目結構如下:
八、完善CURD功能
最后只剩下界面優化及基本的業務功能頁面了。
8.1 優化界面
增加左側菜單以及右側上方的導航欄。可以使用ElementUI的NavMenu 導航菜單組件來實現。
此時可以將菜單欄和標題欄拆分成獨立組件引入默認布局,創建src/views/layout/components目錄并新建header.vue及menu.vue。
此時我們希望菜單根據router配置自動生成,所以需要修改router,可以將router配置單獨提取成routes.js便于其它頁面調用。同時新建一個CURD頁面curd.vue。
[標題欄] src/views/layout/components/header.vue:
<template><div class="layout-header"><i class="icon-collapse" :class="`el-icon-s-${collapse ? 'unfold' : 'fold'}`" @click="collapseMenu"></i><div v-if="$route.name === 'index'" class="el-page-header"><div class="el-page-header__content">首頁</div></div><el-page-header v-else @back="goBack" :content="content"></el-page-header></div> </template><script> export default {props: {collapse: {type: Boolean,}},data: () => ({content: ''}),watch: {$route: {handler(to) {this.content = to.meta.title;},immediate: true}},methods: {goBack() {this.$router.back();},collapseMenu() {this.$emit('collapse-menu');}}, } </script><style> .layout-header {position: relative;height: 100%;padding: 0 20px;background: #fff;box-shadow: 0 1px 4px rgba(0,21,41,.08);display: flex;align-items: center; } .layout-header .icon-collapse {cursor: pointer;font-size: 20px;padding-right: 20px; } </style>[導航菜單] src/views/layout/components/menu.vue:
<template><el-menuref="menu"class="layout-menu"background-color="#001529"text-color="#fff"active-text-color="#1890ff":collapse="collapse":default-active="$route.name"><router-link v-for="(menu, index) in menus" :key="index" :to="menu.path"><el-menu-item :index="menu.name"><i :class="`el-icon-${menu.meta.icon || 'menu'}`"></i><span slot="title">{{ menu.meta.title }}</span></el-menu-item></router-link></el-menu> </template><script> import routes from '@/router/routes';export default {props: {collapse: Boolean},computed: {menus() {return routes[0].children || [];}}, } </script><style> .layout-menu {height: 100%;width: 100%; } </style>[路由設置] src/router/index.js:
import Vue from 'vue' import VueRouter from 'vue-router' import routes from './routes'Vue.use(VueRouter)const router = new VueRouter({routes })export default router;[路由表] src/router/routes.js:
import DefaultLayout from '@/views/layout/default';export default [{path: '',component: DefaultLayout,redirect: 'index',children: [{path: 'index',name: 'index',component: () => import('@/views/page/index'),meta: { title: '首頁', icon: 's-home' }},{path: 'curd',name: 'curd',component: () => import('@/views/page/curd'),meta: { title: '增刪改查', icon: 's-opportunity' }}],}, ]src/views/page/curd.vue:
<template><div>CURD頁面</div> </template>src/views/layout/default.vue
<template><el-container class="layout-default"><el-aside class="layout-default__menu" :style="{ width: `${collapse ? 64 : 256}px` }"><layout-menu :collapse="collapse"></layout-menu></el-aside><el-container class="layout-default__main" :style="{ 'margin-left': `${collapse ? 64 : 256}px` }"><el-header><layout-header @collapse-menu="collapse = !collapse" :collapse="collapse"></layout-header></el-header><el-main><router-view></router-view></el-main></el-container></el-container> </template><script> import LayoutMenu from './components/menu'; import LayoutHeader from './components/header';export default {components: { LayoutMenu, LayoutHeader },data: () => ({collapse: false,}), } </script><style> .layout-default .el-header {padding: 0; } .layout-default__menu {position: fixed;overflow-x: hidden;background-color: #001529;transition: width 300ms;overflow-x: hidden !important;height: 100vh; } .layout-default__main {transition: margin 300ms; } .layout-default__menu, .layout-default__menu .el-menu {border: 0 !important; } </style>此時的目錄結構是這樣的:
這時可以看到頁面已經有了較為美觀的樣式:
且菜單支持收起和展開:
8.2 修改curd頁面結構
一個基本的CURD頁面應該包括:查詢條件、操作按鈕、數據列表、列表分頁、編輯表單、詳情展示等幾個基本模塊。
因此我們可以修改原有的curd.vue為一個curd目錄,目錄下包括index.vue及其相關組件。由于表單頁面相對而言重復性較高,代碼較為冗長,所以我們將其拆分為index.vue、search.vue、form.vue三個組件,其中index.vue為列表分頁展示及數據控制,search.vue和form.vue為表單組件。
search.vue搜索表單我們可以參照element的行內表單示例進行修改:
src/views/curd/search.vue:
<template><el-card shadow="never"><el-form inline :model="model" size="small"><el-form-item label="姓名"><el-input v-model="model.name" placeholder="請輸入姓名"></el-input></el-form-item><el-form-item label="性別"><el-select v-model="model.gender" placeholder="請選擇性別"><el-option label="小姐姐" value="famale"></el-option><el-option label="小哥哥" value="male"></el-option></el-select></el-form-item><el-form-item><el-button type="primary" @click="handleSubmit">查詢</el-button><el-button plain @click="handleReset">重置</el-button></el-form-item></el-form></el-card> </template><script>export default {props: {value: {type: Object,default: () => {return {};}},},data: () => ({model: {}}),watch: {value: {handler(val) {if (val) {Object.keys(this.model).forEach(key => {this.model[key] = val[key];});} else {Object.keys(this.model).forEach(key => {this.model[key] = null;});}},immediate: true,},model: {handler(val) {this.$emit("input", val);},deep: true}},methods: {handleSubmit() {this.$emit('search', this.model);},handleReset() {Object.keys(this.model).forEach(key => {this.model[key] = null;});}}} </script>form.vue搜索表單我們可以參照element的表單驗證示例進行修改:
src/views/curd/form.vue:
<template><el-form ref="form" :model="model" :rules="rules" size="small" label-width="100px"><el-form-item label="姓名" prop="name"><el-input v-model="model.name"></el-input></el-form-item><el-form-item label="性別" prop="gender"><el-select v-model="model.gender" placeholder="請選擇性別"><el-option label="小姐姐" value="famale"></el-option><el-option label="小哥哥" value="male"></el-option></el-select></el-form-item><el-form-item label="年齡" prop="age"><el-input-number v-model="model.age"></el-input-number></el-form-item><el-form-item><el-button type="primary" size="small" @click="handleSubmit">確定</el-button><el-button plain size="small" @click="handleCancel" style="margin-left: 8px">取消</el-button></el-form-item></el-form> </template><script> export default {props: {value: {type: Object,default: () => {return {};}},},data: () => ({model: {name: '',gender: null,age: 18,},rules: {name: [{ required: true, message: '請輸入姓名', trigger: 'blur' }],gender: [{ required: true, message: '請選擇性別', trigger: 'change' }],age: [{ required: true, message: '請輸入年齡', trigger: 'change' }],}}),watch: {value: {handler(val) {if (val) {Object.keys(this.model).forEach(key => {this.model[key] = val[key];});} else {Object.keys(this.model).forEach(key => {this.model[key] = null;});}},immediate: true,},model: {handler(val) {this.$emit("input", val);},deep: true}},methods: {// 點擊確定提交表單的操作handleSubmit(name) {this.$refs.form.validate(valid => {if (valid) {const result = this.submitPure ? this.getPureModel() : JSON.parse(JSON.stringify(this.model));this.$emit("submit", result);}});},// 校驗表單validate() {this.$refs.form.validate(valid => {this.$emit("validate", valid);});},// 重置表單reset() {Object.keys(this.model).forEach(key => {this.model[key] = undefined;});this.$nextTick(() => {this.$refs.form.clearValidate();});},// 點擊取消的操作handleCancel() {this.$emit("cancel");}} }; </script>index.vue則是對以上組件的整合以及列表數據的展示操作。
src/views/curd/index.vue:
<template><div class="page-curd"><curd-search @search="handleSearch"></curd-search><div class="page-curd__action-bar"><el-button type="primary" icon="el-icon-plus" size="small" @click="handleNew">新增</el-button><el-button icon="el-icon-delete" size="small" :disabled="tableSelection && tableSelection.length <= 0" @click="handleDeleteMul">批量刪除</el-button></div><el-table size="mini" :data="tableData" class="page-curd__table" border @selection-change="handleTableSelectionChange"><el-table-column type="selection" min-width="35"></el-table-column><el-table-column label="姓名" prop="name" min-width="100"><template slot-scope="{ row }"><span><i class="el-icon-user-solid"></i>{{ row.name }}</span></template></el-table-column><el-table-column label="性別" prop="gender"><template slot-scope="{ row }"><el-tag v-if="row.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-table-column><el-table-column label="年齡" prop="age"></el-table-column><el-table-column label="操作" min-width="140" fixed="right"><template slot-scope="slotScope"><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-view" title="詳情" @click="handleView(slotScope)"></el-button><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-edit" title="編輯" @click="handleEdit(slotScope)"></el-button><el-button type="text" icon="el-icon-delete" title="刪除" @click="handleDelete(slotScope)"></el-button></template></el-table-column></el-table><el-paginationclass="page-curd__pagination"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 50, 100]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"background></el-pagination><el-dialog :visible.sync="dialogVisible" :title="title" width="450px" :close-on-click-modal="dialogMode === 'view'" append-to-body><template v-if="dialogMode === 'view'"><el-row :gutter="20"><el-col :span="12">姓名:{{ formModel.name }}</el-col><el-col :span="12">性別:<template v-if="formModel.gender"><el-tag v-if="formModel.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-col><el-col :span="12" style="margin-top: 20px;">年齡:{{ formModel.age }}</el-col></el-row></template><template v-else><curd-form ref="curdForm" v-model="formModel" @submit="handleSubmit" @cancel="handleCancel"></curd-form></template></el-dialog></div> </template><script> import CurdSearch from './search'; import CurdForm from './form';export default {components: { CurdSearch, CurdForm },data: () => ({dialogMode: 'new',dialogVisible: false,tableData: [{ name: '古力娜扎', age: 27, gender: 'famale' },{ name: '迪麗熱巴', age: 27, gender: 'famale' },{ name: '尼格買提', age: 36, gender: 'male' },],currentPage: 1,pageSize: 10,total: 3,tableSelection: [],formModel: {}}),computed: {title() {if (this.dialogMode === 'view') {return '查看';}return this.dialogMode === 'edit' ? '編輯' : '新增';}},methods: {async handleSearch(value, needReset) {if (needReset) {this.currentPage = 1;}const param = {...value,currentPage: this.currentPage,pageSize: this.pageSize,};console.log(param);},handleNew() {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'new';this.dialogVisible = true;this.formModel = {};},handleView({ row }) {this.dialogMode = 'view';this.dialogVisible = true;this.formModel = { ...row };},handleEdit({ row }) {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'edit';this.dialogVisible = true;this.formModel = { ...row };},handleDelete({ row }) {console.log('delete:', row);},handleDeleteMul() {console.log('mul delete:', this.tableSelection);},handleSubmit() {if (this.dialogMode === 'new') {console.log('new', this.formModel);} else if (this.dialogMode === 'edit') {console.log('edit', this.formModel);}},handleCancel() {this.dialogVisible = false;},handleTableSelectionChange(selection) {this.tableSelection = selection;},handleSizeChange(val) {this.currentPage = 1;this.pageSize = val;this.handleSearch();},handleCurrentChange(val) {this.currentPage = val;this.handleSearch();},} } </script><style> .page-curd__action-bar {margin: 20px 0px; } .page-curd__table {margin-bottom: 20px; } .page-curd .el-icon-user-solid {padding-right: 10px; } .page-curd__pagination {text-align: right; } </style>假如你有強迫癥的話,那就順便把首頁略微修改一下。
src/views/page/index.vue:
<template><div class="page-index">Vue入門項目CURD示例</div> </template><style> .page-index {text-align: center;padding-top: calc(50vh - 60px - 24px);font-size: 24px; } </style>此時的項目效果如下:
首頁
CURD頁面
新增
編輯
查看詳情
8.3 模擬接口數據
本示例項目為純前端項目,所以使用mockjs來模擬增刪改查的基本API。
在項目中新建一個mock目錄用于存放模擬mockjs配置文件。包括index.js、util.js、module/user.js。
src/mock/index.js:
import Mock from 'mockjs'; import { parseUrl } from './util'; import userAPI from './module/user';// 臨時緩存mockjs數據 let MockCache = {};const MockBot = {// 通用模板APIfastAPI: {// 獲取數據列表page: (base) => config => {const list = MockCache[base] || [];const param = parseUrl(config.url) || {};const { page = 1, size = 10, ...query } = param;// 計算有幾個搜索條件let queryCount = false;for (let key in query) {if (query[key]) {queryCount += 1;break;}}// 根據搜索條件過濾結果const filteredList = queryCount > 0 ? list.filter(data => {let result = false;for (let key in query) {if (data[key] === query[key]) {result = true;break;}}return result;}) : list;// 根據結果處理分頁數據const _page = Number(page);const _limit = Number(size);const pageList = filteredList.filter((item, index) => index < _limit * _page && index >= _limit * (_page - 1));const response = {page: _page,size: _limit,result: {list: pageList,total: filteredList.length,},success: true,};return response;},// 查詢數據詳情get: (base) => config => {const list = MockCache[base] || [];const param = parseUrl(config.url) || {};const id = param.id;const result = list.find((item) => item.id == id);return {result: result,success: true,};},// 新增數據add: (base) => config => {const param = JSON.parse(config.body);MockCache[base].unshift(param);return {success: true,};},// 編輯數據update: (base) => config => {const param = JSON.parse(config.body);const index = MockCache[base].findIndex(item => item.id === param.id);MockCache[base][index] = param;return {success: true,};},// 刪除數據delete: (base) => config => {const ids = JSON.parse(config.body);ids.forEach(id => {MockCache[base] = MockCache[base].filter(item => item.id !== id);});return {success: true,};}},// 根據通用模板API快速創建模擬接口fastMock: (url, list) => {MockCache[url] = list;Mock.mock(new RegExp(`\/${url}\/page`), 'get', MockBot.fastAPI.page(url));Mock.mock(new RegExp(`\/${url}\/get`), 'get', MockBot.fastAPI.get(url));Mock.mock(new RegExp(`\/${url}\/add`), 'post', MockBot.fastAPI.add(url));Mock.mock(new RegExp(`\/${url}\/update`), 'post', MockBot.fastAPI.update(url));Mock.mock(new RegExp(`\/${url}\/delete`), 'post', MockBot.fastAPI.delete(url));}, }// 產品管理 MockBot.fastMock('user', userAPI.userList);src/mock/util.js:
import Mock from 'mockjs';export const parseUrl = (url) => {let obj = {};// 創建一個Objectlet reg = /[?&][^?&]+=[^?&]+/g;// 正則匹配 ?&開始 =拼接 非?&結束 的參數let arr = url.match(reg);// match() 方法可在字符串內檢索指定的值,或找到一個或多個正則表達式的匹配。// arr數組形式 ['?id=12345','&a=b']if (arr) {arr.forEach((item) => {/*** tempArr數組 ['id','12345']和['a','b']* 第一個是key,第二個是value* */let tempArr = item.substring(1).split('=');let key = decodeURIComponent(tempArr[0]);let val = decodeURIComponent(tempArr[1]);obj[key] = val;});}return obj; }export default {// 根據配置文件和數量快速生成數據列表fastList: (config, count) => {const list = []for (let i = 0; i < count; i++) {list.push(Mock.mock(config));}return list;}, }src/mock/module/user.js:
import MockUtil from '../util';export default {// 用戶列表userList: MockUtil.fastList({id: '@guid()',name: '@cname()','gender|1': ['male', 'famale'],'age|16-40': 1,}, 43), }8.4 對接接口數據
模擬好接口,接下來就需要進行接口對接了,首先我們修改main.js,將axios創建一個實例并設置為Vue的prototype,這樣可以在每個Vue頁面或組件中直接通過this進行訪問。
創建axios實例后可以設置request和response攔截器,具體用法請查看axios官方文檔
src/main.js:
import Vue from 'vue'; import axios from 'axios'; import App from '@/App.vue'; import router from '@/router'; import store from '@/store'; import ElementUI from 'element-ui'; // ElementUI組件庫 import 'element-ui/packages/theme-chalk/lib/index.css'; // ElementUI組件庫樣式 import '@/mock';const request = axios.create({baseURL: 'http://localhost',timeout: 1000 * 60,withCredentials: true, });// respone 攔截器 request.interceptors.response.use(response => {const { data = {} } = response;const { success } = data;if (success) {return data;} else {return { success };}},error => {return { success: false };});Vue.prototype.$request = request;// 注冊餓了么UI Vue.use(ElementUI);new Vue({router,store,render: h => h(App) }).$mount('#app')配置好axios之后,我們就可以在curd頁面中進行對接了。
src/views/page/curd/index.vue:
<template><div class="page-curd"><curd-search @search="handleSearch"></curd-search><div class="page-curd__action-bar"><el-button type="primary" icon="el-icon-plus" size="small" @click="handleNew">新增</el-button><el-button icon="el-icon-delete" size="small" :disabled="tableSelection && tableSelection.length <= 0" @click="handleDeleteMul">批量刪除</el-button></div><el-table size="mini" :data="tableData" class="page-curd__table" border @selection-change="handleTableSelectionChange"><el-table-column type="selection" min-width="35"></el-table-column><el-table-column label="姓名" prop="name" min-width="100"><template slot-scope="{ row }"><span><i class="el-icon-user-solid"></i>{{ row.name }}</span></template></el-table-column><el-table-column label="性別" prop="gender"><template slot-scope="{ row }"><el-tag v-if="row.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-table-column><el-table-column label="年齡" prop="age"></el-table-column><el-table-column label="操作" min-width="140" fixed="right"><template slot-scope="slotScope"><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-view" title="詳情" @click="handleView(slotScope)"></el-button><el-button class="eagle-scheme__table-btn" type="text" icon="el-icon-edit" title="編輯" @click="handleEdit(slotScope)"></el-button><el-button type="text" icon="el-icon-delete" title="刪除" @click="handleDelete(slotScope)"></el-button></template></el-table-column></el-table><el-paginationclass="page-curd__pagination"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 50, 100]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"background></el-pagination><el-dialog :visible.sync="dialogVisible" :title="title" width="450px" :close-on-click-modal="dialogMode === 'view'" append-to-body><template v-if="dialogMode === 'view'"><el-row :gutter="20"><el-col :span="12">姓名:{{ formModel.name }}</el-col><el-col :span="12">性別:<template v-if="formModel.gender"><el-tag v-if="formModel.gender === 'male'" size="small">小哥哥 ♂</el-tag><el-tag v-else type="danger" size="small">小姐姐 ♀</el-tag></template></el-col><el-col :span="12" style="margin-top: 20px;">年齡:{{ formModel.age }}</el-col></el-row></template><template v-else><curd-form ref="curdForm" v-model="formModel" @submit="handleSubmit" @cancel="handleCancel"></curd-form></template></el-dialog></div> </template><script> import CurdSearch from './search'; import CurdForm from './form';export default {components: { CurdSearch, CurdForm },data: () => ({dialogMode: 'new',dialogVisible: false,tableData: [],currentPage: 1,pageSize: 10,total: 3,tableSelection: [],formModel: {},currentRow: {},}),computed: {title() {if (this.dialogMode === 'view') {return '查看';}return this.dialogMode === 'edit' ? '編輯' : '新增';}},created() {this.handleSearch();},methods: {async handleSearch(value, needReset) {if (needReset) {this.currentPage = 1;}const params = {...value,page: this.currentPage,size: this.pageSize,};this.$request.get('/user/page', { params }).then(response => {const { result: { list, total } = {} } = response;this.tableData = list;this.total = total;});},handleNew() {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'new';this.dialogVisible = true;this.formModel = {};},handleView({ row }) {this.dialogMode = 'view';this.dialogVisible = true;this.formModel = { ...row };},handleEdit({ row }) {if (this.$refs['curdForm']) { this.$refs['curdForm'].reset(); }this.dialogMode = 'edit';this.$request.get('/user/get', { params: { id: row.id } }).then(response => {const { result } = response;this.formModel = result;this.currentRow = result;this.dialogVisible = true;});},handleDelete({ row }) {this.$request.post('/user/delete', [row.id]).then(response => {const { success } = response;if (success) {this.$message.success('刪除成功');this.handleSearch();}});},handleDeleteMul() {const ids = this.tableSelection.map(selection => selection.id);this.$request.post('/user/delete', ids).then(response => {const { success } = response;if (success) {this.$message.success('刪除成功');this.handleSearch();}});},handleSubmit() {if (this.dialogMode === 'new') {this.$request.post('/user/add', { ...this.formModel, id: undefined }).then(response => {const { success } = response;if (success) {this.$message.success('新增成功');this.handleSearch();this.dialogVisible = false;}});} else if (this.dialogMode === 'edit') {this.$request.post('/user/update', { ...this.formModel, id: this.currentRow.id }).then(response => {const { success } = response;if (success) {this.$message.success('編輯成功');this.handleSearch();this.dialogVisible = false;}});}},handleCancel() {this.dialogVisible = false;},handleTableSelectionChange(selection) {this.tableSelection = selection;},handleSizeChange(val) {this.currentPage = 1;this.pageSize = val;this.handleSearch();},handleCurrentChange(val) {this.currentPage = val;this.handleSearch();},} } </script><style> .page-curd__action-bar {margin: 20px 0px; } .page-curd__table {margin-bottom: 20px; } .page-curd .el-icon-user-solid {padding-right: 10px; } .page-curd__pagination {text-align: right; } </style>至此,一個基本的CURD示例就完成了。
九、總結
在本實例項目中,并沒有使用多少依賴項,只有基本的UI組件庫element、基于promise的HTTP庫axios、前端模擬數據的mockjs,至于本文開始時,創建項目選擇的vuex并沒有提到,這個建議小伙伴們自己查閱相關資料去學習。
在我的學習理念中,每當學習到一個新的技術時,可以先查閱學習技術的簡單教程,然后上手實踐,從模仿到舉一反三再到創新,千萬不要只學習理論而不主動去實踐,這樣效果并不深刻。
本文中有一些ES6以上的語法并沒有過多提及,有許多技巧也并沒有過多的給大家解釋,更多的技術細節我會在以后的文章中提到,如果有BUG或者不對的地方,歡迎各位小伙伴留言指正!
謝謝。
總結
以上是生活随笔為你收集整理的Vue入门之Web端CURD前端项目示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 视频剪辑软件哪个好用?快把这些软件收好
- 下一篇: vue3.x路由404通配处理