element ui 电商后台商品属性管理页面
电商后台商品属性管理
最近在做电商后台,电商商品中有个SKU值,类似于 服装的 “尺码”“颜色”“款式"等。
界面如下:
所用到的知识点如下:
table中增加一个操作按钮
<el-table-column fixed="right" align="center" label="操作" width="200">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" @click="handleUpdate(scope.row)" />
<el-button icon="el-icon-delete" @click="handleDel(scope.row)" />
<el-button icon="el-icon-paperclip" plain @click="handleEdit(scope.row)" />
</template>
</el-table-column>
以上代码中的最后一个按钮就是属性管理页面的操作按钮。
- icon就是给按钮增加一个图标
- plain就是将按钮的样式改为透明的样式
- click是给按钮绑定一个点击事件
- table中的每一列中如果要插入其他内容,是需要通过slot插槽的形式进行处理的。而且调用数据的时候是需要用scope.row的方式来获取到本行的数据。
点击事件处理函数如下:
handleEdit(row) {
// 编辑属性功能
this.AttrdialogVisible = true;
getAttribute({ categoryId: row.id }).then(response => {
if (response.code === 200) {
this.AttrList = response.result;
this.categoryId = row.id;
} else {
this.AttrList = [];
this.categoryId = undefined;
}
});
}
以上代码知识点如下:
5. 因为属性页面是弹窗,需要展示弹窗的显示与隐藏,则可以通过AttrdialogVisible
这个变量来进行控制。为true就展示,为false就关闭。
6. getAttribute
是获取属性的方法,这个方法需要传递的参数是类目ID,而且是一个对象的形式进行传递。
7. 在进行属性渲染时,我是在data中定义了一个数组来接收。也就是AttrList.
属性页面弹窗内容
//el-dialog title是标题 visible.sync就是同步的显示与隐藏 width就是宽度为整个屏幕宽度的一半
<el-dialog title="属性规格" :visible.sync="AttrdialogVisible" width="50%" :before-close="cacelAttrEdit">
//v-for渲染的时候,可以通过template标签来处理 注意:key这个唯一性的key是不能放到template标签上的,需要放到实例化的标签上。
<template v-for="(AttrItem,AttrIndex) in AttrList">
<div
:key="AttrIndex"
style="padding:10px;box-sizing:border-box;border:1px solid #efefef;margin:0px auto 10px;"
>
//el-row 代表是一行,一行可以有多列,列是通过el-col的方式展示,列占内容的多少,可以通过:span的方式进行分割,总数为24.
<el-row>
<el-col :span="16" style="display:flex;align-items:center;">
<span style="width:80px;">属性名:</span>
<el-input v-model="AttrItem.attributeName" width="50%" />
</el-col>
<el-col :span="8">
<el-button
type="danger"
icon="el-icon-delete"
style="margin-left:10px;"
plain
@click="delAttr(AttrItem)"
>删除</el-button>
<el-button type="success" icon="el-icon-check" plain @click="saveAttr(AttrItem)">保存</el-button>
</el-col>
</el-row>
<el-row>
<el-tag
:id="AttrItem.id"
:dynamic-tags="AttrItem.attributeValues | dataFormat"
:image-need="AttrItem.imageNeed"
@changeData="changeData"
@singleSwitch="singleSwitch"
/>
</el-row>
</div>
</template>
<el-button type="primary" @click="addAttr()">创建属性</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="cacelAttrEdit">关闭</el-button>
</span>
</el-dialog>
以上代码中所使用到的函数如下:
//此函数是每个属性中的是否上传图片是唯一的,也就是所有的属性集合中,只有一个是可以上传图片的。
//知识点:this.$set(当前对象,要更新的属性名(字符串),更新后的数据);这个很重要
singleSwitch(id) {
for (var i = 0; i < this.AttrList.length; i++) {
if (this.AttrList[i].imageNeed === 1) {
this.$set(this.AttrList[i], "imageNeed", 0);
this.saveAttr(this.AttrList[i]);
} else if (this.AttrList[i].id === id) {
this.$set(this.AttrList[i], "imageNeed", 1);
}
}
},
//此函数是删除属性,需要弹窗提示是否删除,如果点击了是,则进行delAttribute接口的调用。
//此处有两种情况,一种是删除已经存在的属性,则需要调用接口,如果是删除新添加的属性,则不需要调用接口。这两种方式都是需要进行this.AttrList数组的截取的。因为数据渲染的是this.AttrList的内容。
delAttr(val) {
const that = this;
that.$confirm("此操作将永久删除, 是否继续?", "提示", {
closeOnClickModal: false,
type: "warning"
}).then(() => {
//此处的判断是:如果是已经存在的属性,则会有val.id存在,调用删除接口。如果没有,则直接截取,不需要调用接口。
if (val.id) {
delAttribute(val.id).then(res => {
if (res.code === 200) {
this.$message("删除成功");
this.AttrList.splice(this.AttrList.indexOf(val), 1);
}
});
} else {
this.AttrList.splice(this.AttrList.indexOf(val), 1);
}
});
},
//此函数是保存属性,在进行属性更改后,保存属性,保存后,需要重新去调用获取属性的接口,因为新增的属性是没有id的,重新获取后,可以绑定上id值,此时如果进行删除属性的操作,是需要用到这个id值的。
saveAttr(val) {
createAttribute(val).then(res => {
if (res.code === 200) {
this.$message("保存成功");
getAttribute({ categoryId: this.categoryId }).then(response => {
//获取属性时,如果code是200,则数据获取成功,否则不进行处理。
if (response.code === 200) {
console.log(response);
this.AttrList = response.result;
}
});
}
});
},
//此函数为新增属性,新增就是往this.AttrList数组中添加一个新的对象。
addAttr() {
this.AttrList.push({
"attributeName": "",
"attributeValues": [],
"imageNeed": 0,
"categoryId": this.categoryId
});
},
//此函数是跟tag组件绑定的,也就是当tag组件中内容发生改变时,需要将此页面中的数据也相应的进行改变,因为所有的接口都是当前页面进行处理的。
changeData(obj) {
for (var i = 0; i < this.AttrList.length; i++) {
if (this.AttrList[i].id === obj["id"]) {
Object.assign(this.AttrList[i], obj);
}
}
},
//此函数为属性弹窗关闭时,此时this.AttrLit以及this.categoryId都是需要清空的,放置出现点击其他类目,还是展示上一个类目的数据
cacelAttrEdit() {
this.AttrList = [];
this.categoryId = undefined;
this.AttrdialogVisible = false;
},
// 此函数在table部分已经展示过了
handleEdit(row) {
// 编辑属性功能
this.AttrdialogVisible = true;
getAttribute({ categoryId: row.id }).then(response => {
if (response.code === 200) {
this.AttrList = response.result;
this.categoryId = row.id;
} else {
this.AttrList = [];
this.categoryId = undefined;
}
});
},
上面还有一个重要的知识点就是过滤器,过滤器我之前没有工作中遇到过,参考链接如下:
vue中过滤器的使用
vue中过滤器分为全局跟组件内两种,此处使用的是组件内的过滤器。
filters: {
//过滤器的名称为dataFormat,处理的数据为msg,最终返回一个数据即可。
dataFormat(msg) {
const attrList = [];
for (var i = 0; i < msg.length; i++) {
attrList.push(msg[i].attributeValue);
}
return attrList;
}
}
使用方法:通过 原始数据 | 过滤器名称 的方式进行使用,也就是将原始数据通过此过滤器处理后返回的数据赋值给前面的属性。AttrItem.attributeValues
是一个数组,数组中是一个个的对象,我想要把每个对象中的attributeValue
都拿出来形成一个数组,此数组就是我需要给tag组件传递的数据。
<el-tag
:id="AttrItem.id"
:dynamic-tags="AttrItem.attributeValues | dataFormat"
:image-need="AttrItem.imageNeed"
@changeData="changeData"
@singleSwitch="singleSwitch"
/>
tag组件
知识点:
<template>
<span>
<el-row style="margin:10px auto;">
<span style="width:80px;">是否需要上传图片:</span>
//el-switch 是开关,绑定的值是true或false,是Boolean类型的。此处需要进行处理。active-color是选中时的颜色,change是开关切换时触发的函数
<el-switch v-model="imageNeedBool" active-color="#13ce66" @change="switchChange" />
</el-row>
//el-tag 绑定的数据是字符串的数组集合 closable代表支持关闭
//disable-transitions ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020071114314010.png)
<el-tag
v-for="(tag,index) in attributeValuesList"
:key="index"
closable
:disable-transitions="false"
@close="handleClose(tag)"
>{{ tag }}</el-tag>
<el-input
v-if="inputVisible"
ref="saveTagInput"
v-model="inputValue"
class="input-new-tag"
size="small"
@keyup.enter.native="handleInputConfirm"
@blur="handleInputConfirm"
/>
<el-button v-else class="button-new-tag" size="small" @click="showInput">+ 添加规格</el-button>
</span>
</template>
<script>
export default {
props: {
dynamicTags: {
//在eslint检测中,数组默认值default的写法应该是写成函数的形式。default:function(){return []};
type: Array,
default: []
},
imageNeed: {
type: Number,
default: 0
},
id: {
type: String
}
},
data() {
return {
inputVisible: false,
inputValue: "",
imageNeedBool: false,
attributeValuesList: []
};
},
//此处的watch监听,是在页面已经创建完成后,如果值改变的话,页面需要实时更新
watch: {
imageNeed(newVal) {
console.log(newVal);
this.imageNeedBool = (newVal > 0);
}
},
created() {
this.imageNeedBool = (this.imageNeed > 0);
console.log(this.imageNeedBool, "////");
this.attributeValuesList = this.dynamicTags;
},
methods: {
//switch开关变化,如果改变的话,则需要改变对应的对象的值。通过Object.assign(两个对象)的方式可以进行对象数据的改变
switchChange(val) {
this.imageNeedBool = val;
const obj = Object.assign({}, { "attributeValues": this.attributeValuesList, "imageNeed": (this.imageNeedBool ? 1 : 0), "id": this.id });
//数据改变后,需要事件传递给父组件,然后数据改变,页面渲染改变
this.$emit("changeData", obj);
console.log("val", val, typeof val);
//如果当前的switch开关是打开的状态,则其他的属性switch是需要关闭的。
if (val) {
this.$emit("singleSwitch", this.id);
}
},
handleClose(tag) {
this.attributeValuesList.splice(this.attributeValuesList.indexOf(tag), 1);
const obj = Object.assign({}, { "attributeValues": this.attributeValuesList, "imageNeed": (this.imageNeedBool ? 1 : 0), "id": this.id });
this.$emit("changeData", obj);
},
showInput() {
this.inputVisible = true;
this.$nextTick(_ => {
this.$refs.saveTagInput.$refs.input.focus();
});
},
handleInputConfirm() {
let inputValue = this.inputValue;
if (!inputValue) { return; }
this.attributeValuesList.push(inputValue);
const obj = Object.assign({}, { "attributeValues": this.attributeValuesList, "imageNeed": (this.imageNeedBool ? 1 : 0), "id": this.id });
this.$emit("changeData", obj);
this.inputVisible = false;
this.inputValue = "";
}
}
};
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
</style>
本文地址:https://blog.csdn.net/yehaocheng520/article/details/107283794
上一篇: 栈的应用实例
下一篇: 荐 redis的持久化配置与主从复制