文章目录
- 视频链接:
- 1. 后台项目涉及到的页面
- 2. 品牌管理页面(TradeMark)
- 1. 页面展示:
- 2. 弹框页面展示:
- 3. 页面中所实现的功能点:
- 3.1 数据获取
- 3.2 对话框的显示与隐藏
- 3.3 添加品牌功能逻辑
- 3.4 修改品牌
- 3.5 删除品牌
- 3.6 点击分页器进行分页
- 3. 平台属性管理页面
- 1. 页面展示
- 2. 对话框页面展示
- 3. 页面中涉及到的功能点
- 3.1 三级联动的显示、添加属性按钮、对话框的显示、对话框中的添加属性值按钮的显示
- 3.2 三级联动数据的获取
- 3.3 平台属性数据的获取
- 3.4添加属性 / 修改属性
- 1. 用户输入属性值
- 2.点击保存
- 总结
1. 后台项目涉及到的页面
- 登录页面
- 首页数据收集与展示页面
- 商品管理页面
- 品牌管理
- 平台属性管理
- Sku管理
- Spu管理
- 权限管理
目录展示:
2. 品牌管理页面(TradeMark)
1. 页面展示:
在首页的页面样式布局中需要注意以下几点:
- 图片如何展示:
在图片的展示这款,用到了作用域插槽。作用域插槽 这里相当于el-table-column内部调用了,而prop用于向子组件传递数据。
<el-table-column prop="logoUrl" label="品牌LOGO" width="width">
<template slot-scope="{ row, $index }">
<img :src="row.logoUrl" alt="" style="width: 100px; height: 100px" />
</template>
</el-table-column>
注意:这里为什么要用到作用域插槽,我猜测是因为图片需要展示,因此用到了el-table-column里面的数据,所以需要作用域插槽将数据传递给展示图片的组件,将图片在页面上展示出来。
- 按钮样式的设置:
按钮的设置同样也用到了作用域插槽。
<el-table-column prop="date" label="操作" width="width">
<!-- 这里也是一个作用域插槽 -->
<template slot-scope="{ row, $index }">
<el-button
type="warning"
icon="el-icon-edit"
size="mini"
@click="updateTradeMark(row)"
>修改</el-button
>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="deleteTradeMark(row)"
>删除</el-button
>
</template>
</el-table-column>
注意:这里的row,代表的这一行的数据,而不是列表中某一个属性值的数据。
按钮标签涉及到了两个方法下面的功能介绍模块,会进行讲解。
2. 弹框页面展示:
在对话框布局中需要注意以下几点:
- 图片上传:
<!-- 图片上传 -->
<el-form-item label="品牌LOGO" label-width="100px" prop="logoUrl">
<!-- 收集数据,不能使用v-model 因为不是表单元素 -->
<el-upload
class="avatar-uploader"
action="/dev-api/admin/product/fileUpload"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="tmForm.logoUrl" :src="tmForm.logoUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
<div class="el-upload__tip" slot="tip">
只能上传jpg/png文件,且不超过500kb
</div>
</el-upload>
</el-form-item>
注意:代码部分我主要放的是图片上传的代码,因为我觉得这里涉及到的东西,比其他标签要多一点。其中标签属性
1. action:是指的图片上传的地方,本地图片上传成功之后,他可以返回过来上传成功之后的url,后面数据提交的时候,就可以上传这个地址,因为毕竟如果你写的是本地地址的话,人家服务器咋能收得到嘛。
2. show-file-list是否显示已上传文件列表
3. 在图片展示区域,如果图片有就展示图片,如果图片没有就展示图标。这里有一个判断
- 在el-dialog标签的显示上面用到了.sync后缀,相当于给visible进行父子组件的双向绑定,父给子传递visible属性,然后子组件修改父组件的visible的值,这一系列的动作,.sync都可以完成。
<el-dialog
:title="tmForm.id ? '修改品牌' : '添加品牌'"
:visible.sync="dialogVisible"
width="width"
>
3. 页面中所实现的功能点:
- 数据获取
- 对话框的显示与隐藏
- 添加品牌
- 修改品牌
- 删除品牌
- 点击分页器进行分页
3.1 数据获取
3.2 对话框的显示与隐藏
3.3 添加品牌功能逻辑
注意:在点击添加品牌的时候,要记得清除data中之前的表单数据,就是将对象赋值一个空对象就可以了。
3.4 修改品牌
修改品牌中跟添加品牌功能唯一的区别就是,在修改的时候,要把当前列表中的值传递给tmForm中,使其能够在对话框中进行展示。
// 修改品牌信息
updateTradeMark(row) {
this.dialogVisible = true;
this.tmForm = { ...row };
},
注意:将已有的品牌信息赋值给表单,这里不能直接把row对象赋值给tmForm,因为对象的直接赋值,相当于复制的地址,修改的同时,原对象也会随着发生改变,就算是点击取消按钮,页面中table中的数据也会发生变化。这里要对他进行浅拷贝,浅拷贝还有另外一个方法Object.assign()也可以实现浅拷贝。这里为啥不用深拷贝呢,是因为表单结构简单,不存在嵌套的现象,只有一级的话,也可以当做深拷贝。
3.5 删除品牌
deleteTradeMark(row) {
// 弹框
this.$confirm(`你确定删除${row.tmName}吗?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(async () => {
// 用户点击确定按钮的时候触发
// 向服务器发请求
let result = await this.$API.trademark.reqDeleteTradeMark(row.id);
// 删除成功
if ((result.code = 200)) {
this.$message({
type: "success",
message: "删除成功!",
});
// 再次获得商品列表,这里要对其进行判断,如果当前页的数据大于1的话,就要停留在当前页,如果没有数据的话,就要去到上一页
this.getPageList(
this.list.length > 1 ? this.page : this.page - 1,
this.limit
);
}
})
// 用户点击取消按钮的时候触发
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
删除的话,其实也是将要删除的品牌的id带过去,发请求,然后再重新请求当前的品牌列表。这里与别的按钮不同的是删除品牌之后,需要弹出提示,再次确认是否要删除,以免用户误删。还有就是要确定你当前删除前页面有多少个数据,如果数据就只有一条的话,那就要跳到上一页。
3.6 点击分页器进行分页
<el-pagination
style="margin-top: 20px; text-align: center"
:current-page="page"
:page-size="limit"
:total="total"
:page-sizes="[3, 5, 10]"
layout="prev, pager, next,->,sizes,total"
@current-change="getPageList"
@size-change="getPageList"
>
</el-pagination>
current-change:可以获得当前点击的哪一页,然后将改变后的page,带给服务器,传递过来page页的数据。
size-change:改变一个页面可以显示多少条数据,同样也是带给服务器。
注意:这里的分页器有一个小技巧 -> 可以改变 ->后面属性的位置。
3. 平台属性管理页面
1. 页面展示
在平台属性管理页面的布局中需要注意以下几点:
- 三级联动按钮是如何实现的?下面是自定义组件中的页面布局代码。
这个是三级联动中第一级的代码,后面两级就是在后面再加俩el-form-item
<el-form :inline="true" class="demo-form-inline" :model="cForm">
<el-form-item label="一级分类">
<!-- 这个change是el-select里面自带的 -->
<el-select
placeholder="请选择"
v-model="cForm.category1Id"
@change="handle1"
:disabled="show"
>
<el-option
:label="c1.name"
:value="c1.id"
v-for="(c1, index) in list1"
:key="c1.id"
></el-option>
</el-select>
</el-form-item>
data中定义的数据
data() {
return {
// 一级列表的数据
list1: [],
// 二级列表的数据
list2: [],
// 三级列表的数据
list3: [],
// 收集相应的一级,二级,三级id
cForm: {
category1Id: "",
category2Id: "",
category3Id: "",
},
};
},
说明:这里用到了element UI里面的el-form、el-form-item、el-select、el-option标签
el-form标签中: inline:代表的是行内元素,一行可以放多个表单。
el-select标签中:v-model:用于选择下拉框中某个元素的值的时候,绑定的表单数据对象cForm中对应的属性也会跟着发生变化。handle1方法:是当用于一旦选择下拉框中某个元素触发的。
el-option标签中:label表示标签中要展示什么样的数据;value可以将哪个属性的值传递到el-select中。
- 属性值列表中的这些标签,是通过for循环来进行渲染的。
2. 对话框页面展示
在平台属性管理页面中的对话框的布局中需要注意以下几点:
- 首先这个table表格展示,以及属性数据收集,是两个div框。由isShowTable变量控制其显示与隐藏。
- 在添加属性中,三级联动选不了,下面的功能点部分会详细介绍涉及到特定场景的组件的显示隐藏是如何做到的,他们都涉及到了哪些特定场景。
- 其次就是按钮添加属性值这块了,在点击天机属性之后,下方的table会进行展示,其中第二列需要输入要添加的属性值的名称。回车就保存,点击就可以修改。下面是他涉及到的代码:
<!-- 传结构,就要用到作用域插槽 -->
<template slot-scope="{ row, $index }">
<!-- 这里需要用到span以及input进行来回切换, 鼠标离开以及键盘按回车都会切换回span。span中点击会切换回input-->
<el-input
v-model="row.valueName"
placeholder="请输入属性值名称"
size="mini"
v-if="row.flag"
@blur="toLook(row)"
@keyup.native.enter="toLook(row)"
:ref="$index"
></el-input>
<!---style设置为块元素,click:切换回输入模式-->
<span
v-else
style="display: block"
@click="toEdit(row, $index)"
>{{ row.valueName }}</span
>
</template>
注意:row.flag是在点击添加属性值的按钮的时候添加的属性,一个属性值可以切换自己的模式变换。
- 删除输入的属性值名称的时候,他还会再次确认一下,不然误删了咋办。
代码如下所示:
<el-popconfirm
:title="`确定删除${row.valueName}?`"
@onConfirm="deleteAttrValue($index)"
>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
slot="reference"
></el-button>
</el-popconfirm>
其中onConfirm在确定删除按钮点击的时候才触发。这里删除用到了数组的splice方法。
3. 页面中涉及到的功能点
- 三级联动的显示、对话框的显示、对话框中的添加属性值按钮的显示
- 三级联动数据的获取
- 平台属性数据的获取
- 添加属性 / 修改属性
- 用户输入属性值
- 用户删除属性值
3.1 三级联动的显示、添加属性按钮、对话框的显示、对话框中的添加属性值按钮的显示
组件 | 显示/可用 | 隐藏/不可用 | 属性控制 |
三级联动 | 开始进入页面的时候可用 | 当用户点击添加或者修改属性的时候不可用 | isShowTable |
添加属性按钮 | 三级联动组件传递过来值的时候可以用 | 一开始还没选择三级分类的时候不可以用 | category3Id |
显示属性的表格 | 一开始就是显示,对框框中点击保存或者取消按钮也显示 | 点击添加属性按钮就隐藏 | isShowTable |
对话框 | 点击添加属性按钮显示 | 一开始是隐藏,对框框中点击保存或者取消按钮也隐藏 | isShowTable |
对话框中的添加属性值按钮 | 如果属性名Input框中有值就可以使用 | 一开始不能使用 | attrInfo.attrName |
3.2 三级联动数据的获取
一级分类的数据是在页面加载完成之后从服务器获取的。
二级分类的数据是在一级分类选择之后获取的。
三级分类数据是在二级分类选择后获取的。
一级分类选择之后的代码展示:
// 一级分类的事件回调
async handle1() {
// 清除数据
this.list2 = [];
this.list3 = [];
this.cForm.category2Id = "";
this.cForm.category3Id = "";
// 当一级分类变化的时候 ,二级分类才有展示
const { category1Id } = this.cForm;
let result = await this.$API.attr.reqCategoryList2(category1Id);
if (result.code == 200) {
this.list2 = result.data;
}
},
这里展示的是一级分类在选择属性之后的代码,首先是清除二级分类,三级分类的列表置空。然后卸载一级分类id获取二级数据,并保存下来。
二级也是这样
三级分类在选择属性之后,就会触发自定义事件,将前面收集到的三级分类的id都传递到父组件上去。
// 三级事件的回调
handle3() {
this.$emit("getCategoryId", this.cForm);
},
3.3 平台属性数据的获取
在获得第三类的分类id之后,触发自定义事件getCategoryId,下面是他的代码
// 自定义事件的回调
getCategoryId(cForm) {
const { category1Id, category2Id, category3Id } = cForm;
this.getAttrList(category1Id, category2Id, category3Id);
},
// 获取平台属性的数据
async getAttrList(category1Id, category2Id, category3Id) {
let result = await this.$API.attr.reqattrList(
category1Id,
category2Id,
category3Id
);
if (result.code) {
this.attrList = result.data;
this.category1Id = category1Id;
this.category2Id = category2Id;
this.category3Id = category3Id;
}
},
3.4添加属性 / 修改属性
在添加属性的时候,有一点需要注意一下,清空表单元素
this.attrInfo = {
attrName: "", //属性名
attrValueList: [],
categoryId: this.category3Id, //不能在这里用this收集三级id,
categoryLevel: 3,
};
在修改属性的时候,因为添加属性时直接就给attrInfo指定了一个空对象。但是修改不同的是他必须在修改哪一行上获取对象,不能直接赋值给attrInfo,这里在平台管理时也遇到过,当时处理方法是采用了…语句,浅拷贝,但是这里有二级属性,因此需要深拷贝:
// 按需引入lodash里面的深拷贝
import cloneDeep from "lodash/cloneDeep";
.......
this.attrInfo = cloneDeep(row);
1. 用户输入属性值
在点击添加属性值的时候,需要给attrInfo.attrValueList数组中push一个新对象,该对象要有一个flag,这样的话一个属性值可以切换自己的模式变换。
addAttrValue() {
// attrid是相应的属性的id,
this.attrInfo.attrValueList.push({
attrId: this.attrInfo.id, //对于修改某一个属性的时候,可以在已有的属性值的基础上新增新的属性,(在新增属性值的时候,需要把已有的属性值带上)
valueName: "",
// 给每个属性值,添加一个标记flag。好处,一个属性值可以切换自己的模式变换
flag: true,
});
},
还有就是在修改完成之后,要判断用户输入的值是否是空值,是否有重复的。
toLook(row) {
// 如果用户输入的属性为空,不应该变为查看模式
// trim函数移除字符串两侧的空白字符或其他预定义字符。
if (row.valueName.trim() == "") {
this.$message("请你输入一个正常的属性值");
return;
}
// 新增的属性值不能跟已有的属性值,some会返回一个布尔值
let repeat = this.attrInfo.attrValueList.some((item) => {
if (item !== row) {
return item.valueName == row.valueName;
}
});
if (repeat) return;
row.flag = false;
},
2.点击保存
点击保存后,要过删除掉之前临时添加的属性flag,然后发请求,最后再次获取列表。
总结