Vue + ElementUI的电商管理系统实例11 商品分类
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接口获取商品分类列表数据
商品分类数据列表,请求路径:categories,请求方法:get,
请求参数
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>
data 表格各行的数据
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、获取父级分类的数据列表
商品分类数据列表接口,参数type:2 表示只获取前两级的分类数据。因为最多有三级分类,所以父级分类最多两级。
添加代码获取父级分类数据:
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事件函数:
// 监听 添加分类对话框的关闭事件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 mastergit merge goods_cate
git push
ok,完成!
以上是 Vue + ElementUI的电商管理系统实例11 商品分类 的全部内容, 来源链接: utcz.com/z/379619.html