1、創建商品分類分支goods_cate並push到遠程
查看分支:
git branch
創建分支:
git checkout -b goods_cate
推送到遠程:(以前碼雲中沒有該分支,所以要加-u,如果碼雲中有該分支,則不需要加-u)
git push -u origin goods_cate
2、通過路由加載商品分類組件
新建goods文件夾和Cate.vue文件:
<template> <div> <h3>商品分類組件</h3> </div> </template> <script> export default { } </script> <style lang="less" scoped> </style>
添加路由:
import Cate from '../components/goods/Cate.vue' const routes = [ { path: '/', redirect: '/login' }, // 重定向 { path: '/login', component: Login }, { path: '/home', component: Home, redirect: '/welcome', // 重定向 children: [ // 子路由 { path: '/welcome', component: Welcome }, { path: '/users', component: Users }, // 用戶列表 { path: '/rights', component: Rights }, // 權限列表 { path: '/roles', component: Roles }, // 角色列表 { path: '/categories', component: Cate } // 商品分類 ] } ]
點擊左側菜單的商品分類的效果如圖:

3、繪制商品分類組件的基本布局
還是面包屑和card視圖:
<template> <div> <!--面包屑導航區域--> <el-breadcrumb separator-class="el-icon-arrow-right"> <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item> <el-breadcrumb-item>商品管理</el-breadcrumb-item> <el-breadcrumb-item>商品分類</el-breadcrumb-item> </el-breadcrumb> <!--卡片視圖區域--> <el-card> <!--添加角色按鈕區域--> <el-row> <el-col> <el-button type="primary">添加分類</el-button> </el-col> </el-row> <!--分類列表區域--> <!--分頁區域--> </el-card> </div> </template> <script> export default { } </script> <style lang="less" scoped> </style>
4、調用api接口獲取商品分類列表數據
請求參數
type [1,2,3] 值:1,2,3 分別表示顯示一層二層三層分類列表 【可選參數】如果不傳遞,則默認獲取所有級別的分類
pagenum 當前頁碼值 【可選參數】如果不傳遞,則默認獲取所有分類
pagesize 每頁顯示多少條數據 【可選參數】如果不傳遞,則默認獲取所有分類
<script> export default { data() { return { // 查詢條件 queryInfo: { type: 3, pagenum: 1, pagesize: 5 }, cateList: [], // 商品分類列表數據 total: 0 // 總數據條數 } }, created() { this.getCateList() }, methods: { // 獲取商品分類數據 async getCateList() { const { data: res } = await this.$http.get('categories', { params: this.queryInfo }) if (res.meta.status !== 200) { return this.$message.error('獲取商品分類失敗') } console.log(res.data) this.cateList = res.data.result // 帶參數請求,返回的數據多一層result,還有總數total,當前頁pagenum,當然頁條數pagesize this.total = res.data.total } } } </script>
注意:這里請求接口時記得帶參數,否則會返回一個總數據的data,而沒有total、pagenum,pagesize參數。
5、使用vue-table-with-tree-grid樹形表格組件
element沒有相應的組件,要通過第三方插件來實現
打開vue ui面板,找到依賴項,點擊安裝依賴,在彈出的對話框中,搜索:vue-table-with-tree-grid,進行安裝。
然后查看文檔,有兩種用法:
import Vue from 'vue' import ZkTable from 'vue-table-with-tree-grid' Vue.use(ZkTable) // 或者 import Vue from 'vue' import ZkTable from 'vue-table-with-tree-grid' Vue.component(ZkTable.name, ZkTable)
打開入口文件main.js,導入插件:
import TreeTable from 'vue-table-with-tree-grid'
Vue.component('tree-table', TreeTable)
參考官方文檔給的示例代碼,重新回到Cate.vue文件,使用插件:
<!--分類列表區域--> <tree-table :data="cateList" :columns="columns" :selection-type="false" :expand-type="false" show-index index-text="#" border :show-row-hover="false"></tree-table>
columns 表格各列的配置(具體見下文:Columns Configs)
selection-type 是否為多選類型表格
expand-type 是否為展開行類型表格(為 True 時,需要添加名稱為 '$expand' 的作用域插槽, 它可以獲取到 row, rowIndex)
show-index 是否顯示數據索引
index-text 數據索引名稱
border 是否顯示縱向邊框
show-row-hover 鼠標懸停時,是否高亮當前行
定義columns:
// 為table表格各列的配置定義 columns: [ { label: '分類名稱', // 列標題名稱 prop: 'cat_name' // 對應列內容的屬性名 }, { label: '是否有效' }, { label: '排序' }, { label: '操作' } ]
此時效果圖:
6、使用自定義模板渲染表格數據
先自定義是否有效模板:
// 為table表格各列的配置定義 columns: [ { label: '分類名稱', // 列標題名稱 prop: 'cat_name' // 對應列內容的屬性名 }, { label: '是否有效', type: 'template', // 表示:把當前列定義為模板列 template: 'isok' // 表示當前這列使用的模板名稱 }, { label: '排序' }, { label: '操作' } ]
添加到表格:
<!--分類列表區域--> <tree-table :data="cateList" :columns="columns" :selection-type="false" :expand-type="false" show-index index-text="#" border :show-row-hover="false"> <template slot="isok" scope="scope"> <i v-if="!scope.row.cat_deleted" class="el-icon-success"></i> <i v-else class="el-icon-error"></i> </template> </tree-table> <style lang="less" scoped> .el-icon-success{color: lightgreen;} .el-icon-error{color:red;} </style>
此時效果圖:

7、 渲染排序和操作對應的UI
columns:
// 為table表格各列的配置定義 columns: [ { label: '分類名稱', // 列標題名稱 prop: 'cat_name' // 對應列內容的屬性名 }, { label: '是否有效', type: 'template', // 表示:把當前列定義為模板列 template: 'isok' // 表示當前這列使用的模板名稱 }, { label: '排序', type: 'template', // 表示:把當前列定義為模板列 template: 'order' // 表示當前這列使用的模板名稱 }, { label: '操作', type: 'template', // 表示:把當前列定義為模板列 template: 'operate' // 表示當前這列使用的模板名稱 } ]
排序和操作列代碼:
<!--排序的作用域插槽--> <template slot="order" scope="scope"> <el-tag v-if="scope.row.cat_level == 0">一級</el-tag> <el-tag v-else-if="scope.row.cat_level == 1" type="success">二級</el-tag> <el-tag v-else type="warning">三級</el-tag> </template> <!--操作的作用域插槽--> <template slot="operate" scope="scope"> <el-button size="mini" type="primary" icon="el-icon-edit">編輯</el-button> <el-button size="mini" type="danger" icon="el-icon-delete">刪除</el-button> </template>
此時效果圖:

8、實現分頁功能
添加分頁代碼:
<!--分頁區域--> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total" ></el-pagination>
添加handleSizeChange和handleCurrentChange:
// 監聽 pagesize 改變 handleSizeChange(newSize) { this.queryInfo.pagesize = newSize this.getCateList() }, // 監聽pagenum 改變 handleCurrentChange(newPage) { this.queryInfo.pagenum = newPage this.getCateList() }
給添加分類按鈕和表格之間添加間距:
<!--分類列表區域--> <tree-table class="treeTable" :data="cateList" :columns="columns" :selection-type="false" :expand-type="false" show-index index-text="#" border :show-row-hover="false"> <style lang="less" scoped> .el-icon-success{color: lightgreen;} .el-icon-error{color:red;} .treeTable{margin-top:15px;} </style>
此時效果圖:

9、添加分類的對話框和表單
添加分類按鈕添加點擊事件:
<!--添加分類按鈕區域--> <el-row> <el-col> <el-button type="primary" @click="showAddCateDialog">添加分類</el-button> </el-col> </el-row> <script> export default { 。。。 methods: { // 點擊按鈕 彈出添加分類對話框 showAddCateDialog() { this.addCateDialogVisible = true } } } </script>
添加對話框代碼:
<!--添加分類的對話框--> <el-dialog title="添加分類" :visible.sync="addCateDialogVisible" width="50%" > <!--添加分類表單區域--> <el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRef" label-width="90px"> <el-form-item label="分類名稱" prop="cat_name"> <el-input v-model="addCateForm.cat_name"></el-input> </el-form-item> <el-form-item label="父級分類"> </el-form-item> </el-form> <!--底部按鈕區域--> <span slot="footer" class="dialog-footer"> <el-button @click="addCateDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addCateDialogVisible = false">確 定</el-button> </span> </el-dialog> <script> export default { data() { return { addCateDialogVisible: false, // 控制添加分類對話框是否顯示 // 添加分類的表單數據對象 addCateForm: { cat_name: '', // 將要添加的分類名稱 cat_pid: 0, // 父分類的ID cat_level: 0 // 要添加分類的等級,默認要添加的是一級分類 }, // 添加分類表單的驗證規則對象 addCateFormRules: { cat_name: [ { required: true, message: '請輸入分類名稱', trigger: 'blur' } ] } } } } </script>
此時效果圖:

10、獲取父級分類的數據列表
添加代碼獲取父級分類數據:
parentCateList: [] // 父級分類列表數據 // 點擊按鈕 彈出添加分類對話框 showAddCateDialog() { // 獲取父級分類的數據列表 this.getParentCateList() this.addCateDialogVisible = true }, // 獲取父級分類的數據列表 async getParentCateList() { const { data: res } = await this.$http.get('categories', { params: { type: 2 } }) console.log(res) if (res.meta.status !== 200) { return this.$message.error('獲取父級分類數據失敗') } this.parentCateList = res.data }
11、通過級聯選擇器渲染數據
Cascader 級聯選擇器
當一個數據集合有清晰的層級結構時,可通過級聯選擇器逐級查看並選擇。
先導入到element.js里,這里就不寫了。
value / v-model 選中項綁定值,數組
options 可選項數據源,鍵名可通過 Props 屬性配置
props 配置選項,具體見下表
clearable 是否支持清空選項
expandTrigger 次級菜單的展開方式
checkStrictly 是否嚴格的遵守父子節點不互相關聯
value 指定選項的值為選項對象的某個屬性值
label 指定選項標簽為選項對象的某個屬性值
children 指定選項的子選項為選項對象的某個屬性值
添加代碼:
<el-form-item label="父級分類"> <!--級聯選擇器--> <!-- options用來指定數據源 props用來指定配置對象--> <el-cascader v-model="selectedKeys" :options="parentCateList" :props="cascaderProps" @change="parentCateChanged" clearable></el-cascader> </el-form-item> <script> export default { data() { return { parentCateList: [], // 父級分類列表數據 // 指定級聯選擇器的配置對象 cascaderProps: { expandTrigger: 'hover', // 次級菜單的展開方式 click / hover checkStrictly: true, // 允許選擇任意一級的選項 value: 'cat_id', // 指定選中值的屬性 label: 'cat_name', // 指定選中標簽的名稱 children: 'children' // 指定父子嵌套的屬性 }, // 選中的父級分類的ID數組 selectedKeys: [] } }, methods: { // 選擇項發生變化時觸發這個函數 parentCateChanged() { console.log(this.selectedKeys) } } } </script> <style lang="less" scoped> .el-cascader{width: 100%;} </style>
還要記得在全局樣式global.css里添加:
.el-cascader-panel{height:200px;}
否則選項框會超長。
注意:是否允許選擇任意一級的選項(例如只選第一級),以前版本的element是添加change-on-select,新版本是在props里添加checkStrictly: 'true'。
此時效果圖:


新版bug問題
- 點擊圓圈后理想是自動收起下拉,但是他這個也沒有
- 而且只能點擊圓圈才能選中,點擊文字 label 沒有效果
去百度找了一些資料,終於解決了這兩個問題:
<el-cascader v-model="selectedKeys" :options="parentCateList" :props="cascaderProps" @change="parentCateChanged" clearable ref="cascaderRef" @expand-change="cascaderClick" @visible-change="cascaderClick"></el-cascader>
cascadderClick函數:
// 解決bug:點擊圓圈后是自動收起下拉;點擊文字label同樣實現效果 cascaderClick() { let that = this setTimeout(function() { document.querySelectorAll('.el-cascader-node__label').forEach(el => { el.onclick = function() { this.previousElementSibling.click() that.$refs.cascaderRef.dropDownVisible = false } }) document .querySelectorAll('.el-cascader-panel .el-radio') .forEach(el => { el.onclick = function() { that.$refs.cascaderRef.dropDownVisible = false } }) }, 100) }
OK,現在可以完美實現效果。
12、根據父分類的變化處理表單中的數據
// 添加分類的表單數據對象 addCateForm: { cat_name: '', // 將要添加的分類名稱 cat_pid: 0, // 父分類的ID cat_level: 0 // 要添加分類的等級,默認要添加的是一級分類 },
根據剛才建立的表單數據對象分析:如果在表單中只添加分類名稱 ,那么父分類id是0,當前要添加分類的等級是0,默認添加的是一級分類;如果選中了一級分類,那么父分類id就是選中的分類id值,當前要添加分類的等級是1,添加的是二級分類;如果選中了一級和二級分類,那么父分類id就是選中的數組中二級分類id的值,當前要添加的分類的等級是2,添加的是三級分類。說的有點繞,具體看代碼吧。。
// 選擇項發生變化時觸發這個函數 parentCateChanged() { console.log(this.selectedKeys) // 如果 selectedKeys 數據中的 length 大於0,則證明選中了父級分類 // 反之,就說明沒有選中任何父級分類 if (this.selectedKeys.length > 0) { // 選擇最后一項當作父分類ID賦值 this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1] // 為當前要添加的分類的等級賦值 this.addCateForm.cat_level = this.selectedKeys.length return } else { // 父分類ID賦值 this.addCateForm.cat_pid = 0 // 為當前要添加的分類的等級賦值 this.addCateForm.cat_level = 0 } console.log(this.addCateForm) }
此時三種情況的打印結果分別為:

13、在對話框添加close事件,重置表單數據
給對話框添加colse關閉事件:
<!--添加分類的對話框--> <el-dialog title="添加分類" :visible.sync="addCateDialogVisible" width="50%" @close="addCateDialogClosed">
// 監聽 添加分類對話框的關閉事件 addCateDialogClosed() { // 表單內容重置為空 this.$refs.addCateFormRef.resetFields() // 通過ref引用調用resetFields方法 // 選中的父級分類的ID數組 重置為空 this.selectedKeys = [] // 父分類id 和 當前分類等級 重置為空 this.addCateForm.cat_pid = 0 this.addCateForm.cat_level = 0 }
14、完成添加分類的操作
調用api的添加分類接口,請求路徑:categories,請求方法:post,
請求參數
cat_pid 分類父 ID 不能為空,如果要添加1級分類,則父分類Id應該設置為 `0`
cat_name 分類名稱 不能為空
cat_level 分類層級 不能為空,`0`表示一級分類;`1`表示二級分類;`2`表示三級分類
繼續完善addCate函數:請求參數前面已經定義過了addCateForm
// 點擊按鈕,添加新的分類 addCate() { // console.log(this.addCateForm) this.$refs.addCateFormRef.validate(async valid => { if (!valid) return // 可以發起添加分類的網絡請求 const { data: res } = await this.$http.post('categories', this.addCateForm) if (res.meta.status !== 201) { this.$message.error('添加商品分類失敗!') } this.$message.success('添加商品分類成功!') this.getCateList() this.addCateDialogVisible = false }) }
此時效果圖:

15、實現編輯分類功能操作
先給編輯按鈕添加點擊事件:
<el-button size="mini" type="primary" icon="el-icon-edit" @click="editCateDialog(scope.row.cat_id)">編輯</el-button>
添加編輯對話框代碼:
打開對話框是請求根據 id 查詢分類的接口,請求路徑:categories/:id,請求方法:get
然后把查詢到的數據賦值給編輯分類的表單數據
<!--編輯商品分類的對話框--> <el-dialog title="編輯分類信息" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed" > <!--內容主體區域--> <el-form :model="editForm" :rules="addCateFormRules" ref="editFormRef" label-width="90px"> <el-form-item label="分類名稱" prop="cat_name"> <el-input v-model="editForm.cat_name"></el-input> </el-form-item> </el-form> <!--底部按鈕區域--> <span slot="footer" class="dialog-footer"> <el-button @click="editDialogVisible = false">取 消</el-button> <el-button type="primary" @click="editCateInfo">確 定</el-button> </span> </el-dialog> <script> export default { data() { return { editDialogVisible: false, // 控制編輯分類的對話框是否顯示 // 編輯分類信息的表單數據 editForm: { cat_name: '' } } }, methods: { // 監聽 編輯分類對話框 async editCateDialog(id) { // 發起根據 id 查詢分類的網絡請求 const { data: res } = await this.$http.get('categories/' + id) if (res.meta.status !== 200) { this.$message.error('查詢分類信息失敗') } this.editForm = res.data this.editDialogVisible = true }, // 監聽 編輯分類信息對話框的關閉事件 editDialogClosed() { // 表單內容重置為空 this.$refs.editFormRef.resetFields() // 通過ref引用調用resetFields方法 } } } </script>
添加確定按鈕綁定點擊事件,完成用戶信息的修改:
先預校驗,然后調用api的編輯提交分類接口,請求路徑:categories/:id,請求方法:put,請求參數:cat_name 分類名稱 不能為空
// 點擊按鈕 修改角色信息 editRoleInfo() { this.$refs.editFormRef.validate(async valid => { if (!valid) return // 可以發起修改用戶信息的網絡請求 const { data: res } = await this.$http.put('categories/' + this.editForm.cat_id, { cat_name: this.editForm.cat_name }) if (res.meta.status !== 200) { return this.$message.error('編輯商品分類失敗!') } this.$message.success('編輯商品分類成功!') this.getCateList() this.editDialogVisible = false }) }
ok,測試已經可以編輯分類名稱:

16、實現刪除分類功能操作
給刪除按鈕添加點擊事件:根據id
<el-button size="mini" type="danger" icon="el-icon-delete" @click="delCateDialog(scope.row.cat_id)">刪除</el-button>
根據分類id,調用api的刪除分類接口,請求路徑:categories/:id,請求方法:delete
// 監聽 刪除分類對話框 async delCateDialog(id) { console.log(id) // 彈框 詢問用戶是否刪除 const confirmResult = await this.$confirm('此操作將永久刪除該分類, 是否繼續?', '提示', { confirmButtonText: '確定', cancelButtonText: '取消', type: 'warning' }).catch(err => err) // 如果用戶確認刪除,則返回值為字符串 confirm // 如果用戶取消刪除,則返回值為字符串 cancel // console.log(confirmResult) if (confirmResult !== 'confirm') { return this.$message.info('已取消刪除') } // console.log('確認刪除') const { data: res } = await this.$http.delete('categories/' + id) if (res.meta.status !== 200) { return this.$message.error('刪除分類失敗!') } this.$message.success('刪除分類成功!') this.getCateList() }
完成效果圖:

17、將goods_cate提交到遠程倉庫
先查看分支:
git branch
查看當前文件狀態:
git status
然后提交到暫存區:
git add .
把當前提交到goods_cate分支:
git commit -m "完成了商品分類功能的開發"
推送到雲端goods_cate分支:
git push
把goods_cate分支合並到master:
git checkout master
git merge goods_cate
git push
ok,完成!
