实现的功能
功能 | 详述 |
---|---|
商品分类管理 | 渲染组件和子路由;布局;渲染树形表格;渲染级联选择器;重置表单 |
分类参数_分类 | 渲染组件和子路由;布局,警告;获取和渲染商品分类到级联选择器;渲染Tab分区面板;计算属性控制按钮禁用 |
分类参数_参数 | 获取渲染分类参数数据列表;添加参数(动态渲染对话框文本,控制级联选择器只能选一级和二级);重置表单;表单预校验发起请求;修改参数;删除参数 |
参数下可选项 | 渲染可选项(按钮和文本框动态切换);添加可选项;删除可选项 |
使用到的Element-ui组件
组件名称_EN | 注册 | 备注 |
---|---|---|
Cascader | Vue.use(Cascader) | 级联选择器 |
Alert | Vue.use(Alert) | 警告 |
Tabs | Vue.use(Tabs) | 标签页 |
TabPane | Vue.use(TabPane) |
使用到的依赖
运行依赖:vue-table-with-tree-grid
// [main.js]
// 导入树形布局
import TreeTable from 'vue-table-with-tree-grid'
// 注册为全局可用组件
Vue.component('tree-table', TreeTable)
商品分类管理
1.渲染组件和子路由
2.布局
①面包屑导航
②卡片视图
③分页
3.获取渲染商品分类列表
①获取权限商品分类列表
②渲染权限商品分类列表
1️⃣树形表格
:data:数据源
:columns:表格各列配置
label:列标题名称
prop:列内容的属性名
type:自定义模板列template
:selection-type="false":去除复选框
:expand-type="false":去除展开行
show-index:数据索引列
index-text="#":数据索引列标题
:show-row-hover="false":高亮效果
<!-- [Cate.vue] -->
<!-- 表格区域 -->
<tree-table :data="catelist" :columns="columns":selection-type="false" :expand-type="false" show-index index-text="#" border :show-row-hover="false>
<!-- ...... -->
<!-- 模板列 -->
<template slot="opt">
<el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button>
<el-button type="danger" icon="el-icon-delete" size="mini">删除</el-button>
</template>
</tree-table>
// [Cate.vue -> data]
// 为table指定列的定义
columns: [
{
label: '分类名称',
prop: 'cat_name',
},
// ......
{
label: '操作',
// 将当前列定义为模板列
type: 'template',
// 表示当前这一列使用模板名称
template: 'opt',
},
],
4、添加分类
①展示添加分类对话框
②获取父级分类列表
③渲染添加分类表单
1️⃣父级分类级联选择器
options:数据源
props:配置对象
<!-- [Cate.vue] -->
<!-- options指定数据源 props指定配置对象 -->
<el-cascader
:options="parentCateList"
:props="cascaderProps"
v-model="selectedKeys"
@change="parentCateChanged"
clearable
></el-cascader>
// [Cate.vue -> data]
// 父级分类列表
parentCateList: [],
// 指定级联选择器的配置对象
cascaderProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children',
checkStrictly: true,
expandTrigger: 'hover',
},
// 选中的父级分类的id数组
selectedKeys: []
/* [assets/css/global.css] */
.el-cascader-panel{
height: 300px;
}
④添加分类
1️⃣根据父级分类的变化处理数据
// [Cate.vue -> data]
// 添加分类的表单数据对象
addCateForm: {
// 分类名称
cat_name: '',
// 父级分类的id
cat_pid: 0,
// 分类等级,默认1级分类
cat_level: 0,
}
// [Cate.vue -> methods]
// 选择项发生变化触发这个函数
parentCateChanged() {
// 如果selectedKeys 数组中>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 {
this.addCateForm.cat_pid = 0
this.addCateForm.cat_level = 0
}
}
2️⃣点击按钮添加新的分类 预校验
⑤重置表单
// [Cate.vue -> methods]
// 监听对话框关闭 重置表单
addCateDialogClosed() {
this.$refs.addCateFormRef.resetFields()
// 级联选择器
this.selectedKeys = []
this.addCateForm.cat_pid = 0
this.addCateForm.cat_level = 0
}
分类参数管理
动态参数,静态属性
1.渲染组件和子路由
2.布局
①面包屑导航
②卡片视图
③警告
<!-- [Params.vue] -->
<!-- 警告 -->
<el-alert title="注意:只允许为第三级分类设置相关参数!" type="warning" :closable="false" show-icon></el-alert>
3.获取渲染商品【分类】数据列表
①获取商品分类数据列表
②渲染商品分类数据列表
1️⃣级联选择器
2️⃣Tab分区面板
name:激活的面板name
@tab-click="handleTabClick":点击时触发
<!-- [Params.vue] -->
<!-- tab页 -->
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<!-- 添加动态参数 -->
<el-tab-pane label="动态参数" name="many"></el-tab-pane>
<!-- 添加静态属性 -->
<el-tab-pane label="静态属性" name="only"></el-tab-pane>
</el-tabs>
3️⃣计算属性控制按钮禁用
级联选择器未选中三级分类
<!-- [Params.vue] -->
<el-button
type="primary"
size="mini"
:disabled="isBtnDisable"
@click="addDialogVisible=true"
>添加参数</el-button>
// [Params.vue -> computed]
computed: {
// 按钮是否禁用,是true 否false
isBtnDisable() {
if (this.selectedCateKeys.length !== 3) {
return true
}
return false
}
}
4、获取渲染分类【参数】数据列表
①获取分类参数数据列表
1️⃣计算属性,三级分类Id
// [Params.vue -> computed]
// 当前选中的三级分类的id
cateId() {
if (this.selectedCateKeys.length === 3) {
return this.selectedCateKeys[2]
}
return null
}
2️⃣在级联选择器发生变化时发起请求
3️⃣在Tab分区面板发生变化时发起请求
4️⃣处理获取的数据,分为两个数组保存
// [Params.vue -> methods]
if (this.activeName === 'many') {
this.manyTableData = res.data
} else {
this.onlyTableData = res.data
}
②渲染商品分类数据列表
1️⃣表格
2️⃣展开行
5、添加参数
①展示添加对话框
②渲染添加对话框和表单
1️⃣对话框标题文本
// [Params.vue -> computed]
// 动态计算标题文本
titleText() {
if (this.activeName === 'many') {
return '动态参数'
} else {
return '静态属性'
}
}
<!-- [Params.vue] -->
<el-dialog :title="'添加'+titleText"></el-dialog>
2️⃣级联选择器只能选一级和二级
// [Params.vue -> methods]
// 级联选中项,变化会触发
handleChange() {
this.getParamsData()
},
// 获取参数列表数据
async getParamsData() {
// 选中的不是三级分类
if (this.selectedCateKeys.length !== 3) {
this.selectedCateKeys = []
// 清空表格数据 避免级联选择器和tab分区数据冲突
this.manyTableData = []
this.onlyTableData = []
return
}
// ......
}
③重置表单
④表单预校验,校验通过发起请求
请求结束,再刷新列表,this.getParamsData()
6、修改参数
①展示修改对话框
②渲染修改表单
根据id查询参数,并渲染到修改表单中
③表单验证规则editFormRules
④表单重置
⑤表单预校验,校验通过发起请求
7、删除参数
①弹框询问 删除用户
8、渲染参数下可选项
①处理可选项
// [Params.vue -> methods]
res.data.forEach((item) => {
item.attr_vals = item.attr_vals ? item.attr_vals.split(',') : []
// ......
})
②渲染可选项
1️⃣展开行+作用域插槽
2️⃣动态编辑标签,解决共用参数
每一行使用自己的参数inputVisible
// [Params.vue -> data]
// 文本框 按钮切换
inputVisible: false,
// 文本框输入内容
inputValue: []
// [Params.vue -> methods]
async getParamsData() {
// ......
res.data.forEach((item) => {
// ......
// 控制文本框显示和隐藏
item.inputVisible = false
// 文本框输入值
item.inputValue = ''
})
// ......
}
<!-- [Params.vue] -->
<!-- 输入文本框 -->
<el-input
class="input-new-tag"
v-if="scope.row.inputVisible"
v-model="scope.row.inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm(scope.row)"
@blur="handleInputConfirm(scope.row)"
></el-input>
<!-- 按钮 -->
<el-button
v-else
class="button-new-tag"
size="small"
@click="showInput(scope.row)"
>+ New Tag</el-button>
// [Params.vue -> methods]
// 文本框失去焦点或按下enter
async handleInputConfirm(row) {
// ......
row.inputVisible = false
},
// 点击按钮展示
showInput(row) {
row.inputiVisible = true
// ......
}
3️⃣文本框自动获取焦点
$nextTick:当页面上元素被重新渲染之后,才会执行回调函数中的代码
inputiVisible置为true时,input可能还没被渲染出来
// [Params.vue -> methods]
// 点击按钮展示
showInput(row) {
// ......
// 文本框自动获得焦点
this.$nextTick((_) => {
this.$refs.saveTagInput.$refs.input.focus()
})
},
③添加可选项
文本框失去焦点时,判断合法,处理输入
// [Params.vue -> methods]
// 文本框失去焦点或按下enter
async handleInputConfirm(row) {
// 输入非法的空格
if (row.inputValue.trim().length === 0) {
row.inputValue = ''
row.inputVisible = false
return
}
// 输入合法 后续处理
row.attr_vals.push(row.inputValue.trim())
row.inputValue = ''
row.inputVisible = false
this.saveAttrVals(row)
}
// [Params.vue -> methods]
// 发起请求 保存操作
async saveAttrVals(row) {
const { data: res } = await this.$http.put(
`categories/${this.cateId}/attributes/${row.attr_id}`,
{
attr_name: row.attr_name,
attr_sel: row.attr_sel,
attr_vals: row.attr_vals.join(','),
}
)
if (res.meta.status !== 200) {
return this.$message.error('修改参数项失败')
}
this.$message.success('修改参数项成功')
},
④删除可选项
<!-- [Params.vue] -->
<el-tag
v-for="(item,i) in scope.row.attr_vals"
:key="i"
closable
@close="handleClose(i,scope.row)"
>{{item}}</el-tag>
// [Params.vue -> methods]
// 删除对应参数可选项
handleClose(i, row) {
row.attr_vals.splice(i, 1)
this.saveAttrVals(row)
},