目录
skuform静态页面
ui下拉框
reduce()方法详解及高级技巧
语法
reduce的简单用法
reduce的高级用法
项目实战应用
SKUFORM完整代码
完成查看SKU列表的loading效果
spu父组件
?sku页面
深度选择器
scoped属性的作用
<template>
<div>
<el-form label-width="80px">
<el-form-item label="spu的名称"> 海绵宝宝 </el-form-item>
<el-form-item label="sku的名称">
<el-input placeholder="sku名称"></el-input>
</el-form-item>
<el-form-item label="价格(元)">
<el-input placeholder="价格(元)"></el-input>
</el-form-item>
<el-form-item label="重量(千克)">
<el-input placeholder="重量(千克)"></el-input>
</el-form-item>
<el-form-item label="规格描述">
<el-input type="textarea" rows="4"></el-input>
</el-form-item>
<el-form-item label="平台属性">
<el-form :inline="true" label-width="">
<el-form-item label="屏幕的尺寸">
<el-select placeholder="请选择" value="">
<el-option></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="销售属性">
<el-form :inline="true" label-width="">
<el-form-item label="屏幕的尺寸">
<el-select placeholder="请选择" value="">
<el-option></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="图片列表">
<el-table border>
<el-table-column
prop="prop"
label="label"
width="80px"
type="selection"
>
</el-table-column>
<el-table-column prop="图片" label="label" width="width">
</el-table-column>
<el-table-column prop="名称" label="label" width="width">
</el-table-column>
<el-table-column prop="操作" label="label" width="width">
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="label">
<el-button type="primary">保存</el-button>
<el-button type="primary">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "skuForm",
};
</script>
<style>
</style>
ui下拉框
可以是收集多个数据 使用模板字符串 在处理
可以收集到循环数据里
<el-form :inline="true" label-width="">
<el-form-item
:label="item.attrName"
v-for="item in attrInfo"
:key="item.id"
>
<el-select placeholder="请选择" v-model="item.attrIdAndValue">
<el-option
:value="`${item.id}:${attValue.id}`"
:label="attValue.valueName"
v-for="attValue in item.attrValueList"
:key="attValue.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
reduce()方法详解及高级技巧
语法
reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
callback (执行数组中每个值的函数,包含四个参数)
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组)
initialValue (作为第一次调用 callback 的第一个参数。)
如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。
reduce的简单用法
当然最简单的就是我们常用的数组求和,求乘积了。
var arr = [1, 2, 3, 4];
var sum = arr.reduce((x,y)=>x+y)
var mul = arr.reduce((x,y)=>x*y)
console.log( sum ); //求和,10
console.log( mul ); //求乘积,24
reduce的高级用法
计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
let nameNum = names.reduce((pre,cur)=>{
if(cur in pre){
pre[cur]++
}else{
pre[cur] = 1
}
return pre
},{})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}
(2)数组去重
let arr = [1,2,3,4,4,1]
let newArr = arr.reduce((pre,cur)=>{
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
},[])
console.log(newArr);// [1, 2, 3, 4]
(3)将二维数组转化为一维
let arr = [[0, 1], [2, 3], [4, 5]]
let newArr = arr.reduce((pre,cur)=>{
return pre.concat(cur)
},[])
console.log(newArr); // [0, 1, 2, 3, 4, 5]
(3)将多维数组转化为一维
let arr = [[0, 1], [2, 3], [4,[5,6,7]]]
const newArr = function(arr){
return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[])
}
console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
对象里的属性求和
var result = [
{
subject: 'math',
score: 10
},
{
subject: 'chinese',
score: 20
},
{
subject: 'english',
score: 30
}
];
var sum = result.reduce(function(prev, cur) {
return cur.score + prev;
}, 0);
console.log(sum) //60
项目实战应用
const { attrInfo, skuInfo, spuSaleAttr } = this;
skuInfo.skuSaleAttrValueList = spuSaleAttr.reduce((prev, item) => {
if (item.SaleidAndValueId) {
let [saleAttrId, saleAttrValueId] = item.SaleidAndValueId.split(":");
prev.push({ saleAttrId, saleAttrValueId });
}
return prev;
}, []);
<template>
<div>
<el-form label-width="80px">
<el-form-item label="spu的名称"> {{ spu.spuName }} </el-form-item>
<el-form-item label="sku的名称">
<el-input placeholder="sku名称" v-model="skuInfo.skuName"></el-input>
</el-form-item>
<el-form-item label="价格(元)">
<el-input
placeholder="价格(元)"
type="number"
v-model="skuInfo.price"
></el-input>
</el-form-item>
<el-form-item label="重量(千克)">
<el-input placeholder="重量(千克)" v-model="skuInfo.weight"></el-input>
</el-form-item>
<el-form-item label="规格描述">
<el-input type="textarea" rows="4" v-model="skuInfo.skuDesc"></el-input>
</el-form-item>
<el-form-item label="平台属性">
<el-form :inline="true" label-width="">
<el-form-item
:label="item.attrName"
v-for="item in attrInfo"
:key="item.id"
>
<el-select placeholder="请选择" v-model="item.attrIdAndValue">
<el-option
:value="`${item.id}:${attValue.id}`"
:label="attValue.valueName"
v-for="attValue in item.attrValueList"
:key="attValue.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="销售属性">
<el-form :inline="true" label-width="">
<el-form-item
:label="item.saleAttrName"
v-for="item in spuSaleAttr"
:key="item.id"
>
<el-select placeholder="请选择" v-model="item.SaleidAndValueId">
<el-option
v-for="AttrValue in item.spuSaleAttrValueList"
:key="AttrValue.id"
:label="AttrValue.saleAttrValueName"
:value="`${item.id}:${AttrValue.id}`"
></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="图片列表">
<el-table :data="skuImage" border @selection-change="selectionChange">
<el-table-column
prop="prop"
label="label"
width="80px"
type="selection"
>
</el-table-column>
<el-table-column prop="" label="图片" width="width">
<template slot-scope="{ row }">
<img :src="row.imgUrl" alt="" />
</template>
</el-table-column>
<el-table-column prop="imgName" label="名称" width="width">
</el-table-column>
<el-table-column prop="" label="操作" width="width">
<template slot-scope="{ row }">
<el-button
type="primary"
v-if="row.isDefault == 0"
@click="changeDefault(row)"
>
设置默认</el-button
>
<el-button v-else>默认</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveSkuInfo">保存</el-button>
<el-button type="primary" @click="cncel">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "skuForm",
data() {
return {
//存储图片的信息
skuImage: [],
//存储销售属性
spuSaleAttr: [],
//存储平台属性
attrInfo: [],
//第一类收集的数据,父组件的数据
skuInfo: {
category3Id: 0,
spuId: 0,
tmId: 0,
//通过v-model收集
skuName: "",
price: 0,
weight: "",
skuDesc: "",
//需要书写代码
skuDefaultImg: "string", //默认图片
//收集图片的字段
skuImageList: [
// {
// id: 0,
// imgName: "string",
// imgUrl: "string",
// isDefault: "string",
// skuId: 0,
// spuImgId: 0,
// },
],
//平台属性
skuAttrValueList: [
// {
// attrId: 0,
// valueId: 0,
// },
],
//销售属性
skuSaleAttrValueList: [
// {
// saleAttrId: 0,
// saleAttrValueId: 0,
// },
],
},
spu: {},
//收集图片的数据字段(数据中缺少 isDefault字段 提交前需要整理)
imageList: [],
};
},
methods: {
initData(spu, listId) {
// 收集父组件给子组件的数据
this.skuInfo.category3Id = listId.getCategory3ID;
this.skuInfo.spuId = spu.id;
this.skuInfo.tmId = spu.tmId;
this.spu = spu;
this.attrInfoList(listId);
this.spuSaleAttrList(spu.id);
this.skImageList(spu.id);
},
// 获取图片数据
async skImageList(spuid) {
let { code, data } = await this.$api.sku.spuImageList(spuid);
if (code !== 200) return;
let list = data;
list.forEach((element) => {
element.isDefault = 0;
});
this.skuImage = list;
},
//获取销售属性数据
async spuSaleAttrList(spuid) {
let { code, data } = await this.$api.sku.spuSaleAttrList(spuid);
if (code !== 200) return;
this.spuSaleAttr = data;
},
//获取平台属性
async attrInfoList(listId) {
let { getCategory1ID, getCategory2ID, getCategory3ID } = listId;
let { code, data } = await this.$api.sku.attrInfoList(
getCategory1ID,
getCategory2ID,
getCategory3ID
);
if (code !== 200) return;
this.attrInfo = data;
},
//table表格复选框事件
selectionChange(data) {
//获取到用户选中图片的信息数据,数据中缺少 isDefault字段
this.imageList = data;
},
//排他操作
changeDefault(row) {
//图片列表数据的 isDefault 变为 0
this.skuImage.forEach((item) => {
item.isDefault = 0;
});
//点击的变为1
row.isDefault = 1;
//设置默认图片
this.skuInfo.skuDefaultImg = row.imgUrl;
},
//取消按钮
cncel() {
//自定义事件
this.$emit("switching", 0);
//清除数据
Object.assign(this._data, this.$options.data());
},
// 保存按钮
async saveSkuInfo() {
//整理数据
//平台属性 attrInfo
const { attrInfo, skuInfo, spuSaleAttr, imageList } = this;
//新增数组(第一种整合数据方法)
let arr = [];
attrInfo.forEach((item) => {
if (item.attrIdAndValue) {
//用户选择 把数据切割为数组
let [attrId, valueId] = item.attrIdAndValue.split(":");
let obj = { attrId, valueId };
arr.push(obj);
}
});
//将整理好的数据赋值给 skuInfo.skuAttrValueList
skuInfo.skuAttrValueList = arr;
//整合销售属性
skuInfo.skuSaleAttrValueList = spuSaleAttr.reduce((prev, item) => {
if (item.SaleidAndValueId) {
let [saleAttrId, saleAttrValueId] = item.SaleidAndValueId.split(":");
prev.push({ saleAttrId, saleAttrValueId });
}
return prev;
}, []);
//整理图片的数据
skuInfo.skuImageList = imageList.map((item) => {
return {
imgName: item.imgName,
imgUrl: item.imgUrl,
isDefault: item.isDefault,
spuImgId: item.id,
};
});
//发请求
let { code } = await this.$api.sku.saveSkuInfo(skuInfo);
if (code !== 200) return;
this.$message("保存成功");
this.$emit("switching", 0);
},
},
};
</script>
<style>
img {
width: 100px;
height: 100px;
}
</style>
完成查看SKU列表的loading效果
----loading效果目前只会展示一次 关闭对话框时清空数据 开启loading
-----快速切换查看sku会发现上一次的数据会显示
spu父组件
<template>
<div>
<el-card>
<!-- 三级联动已经为全局组件了 -->
<componentSelect
@getShopId="getShopId"
:isShow="scene != 0"
></componentSelect>
</el-card>
<el-card>
<!-- 底部将来三部分进行切换 展示spu-->
<div v-show="scene == 0">
<el-button
type="primary"
icon="el-icon-plus"
:disabled="!listId"
@click="addspu"
>添加SPU</el-button
>
<el-table border :data="records">
<el-table-column
type="index"
label="序号"
width="80"
align="center"
></el-table-column>
<el-table-column prop="spuName" label="SPU名称"></el-table-column>
<el-table-column prop="description" label="SPU描述"></el-table-column>
<el-table-column label="操作">
<template slot-scope="{ row }">
<HintButton
type="success"
icon="el-icon-plus"
size="mini"
title="添加sku"
@click="addsku(row)"
></HintButton>
<HintButton
type="warning"
icon="el-icon-edit"
size="mini"
title="修改spu"
@click="unDateSpu(row)"
>
</HintButton>
<HintButton
type="info"
icon="el-icon-info"
size="mini"
title="查看当前spu全部的sku列表"
@click="handlesku(row)"
></HintButton>
<el-popconfirm
title="这是一段内容确定删除吗"
@onConfirm="despu(row)"
>
<HintButton
type="danger"
icon="el-icon-delete"
size="mini"
title="删除spu"
slot="reference"
></HintButton>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-pagination
:total="total"
:current-page="page"
:page-size="limit"
:page-sizes="[3, 5, 10]"
layout="prev,pager,next,jumper,sizes,total"
@current-change="reqSpuList"
@size-change="sizeChange"
>
</el-pagination>
</div>
<spuForm
v-show="scene == 1"
@changeScene="changeScene"
ref="spu"
></spuForm>
<skuForm v-show="scene == 2" ref="sku" @switching="switching"></skuForm>
</el-card>
<el-dialog
:title="`${spu.spuName}的sku的列表`"
:visible.sync="dialogTableVisible"
@close="close"
>
<el-table :data="sku" style="width: 100%" v-loading="loading">
<el-table-column prop="skuName" label="名称" width="width">
</el-table-column>
<el-table-column prop="price" label="价格" width="width">
</el-table-column>
<el-table-column prop="weight" label="重量" width="width">
</el-table-column>
<el-table-column prop="prop" label="默认图片" width="width">
<template slot-scope="{ row }">
<img :src="row.skuDefaultImg" alt="" />
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script>
import skuForm from "./skuForm.vue";
import spuForm from "./spuForm.vue";
export default {
name: "Spu",
components: {
skuForm,
spuForm,
},
data() {
return {
// 三级联动的id
listId: null,
//控制三级分类的可操作性
isShow: true,
page: 1, //分页器第几页
limit: 3, //每一页需要展示多少条数据
records: [], //spu列表数据,
total: 0, //分页器一共需要展示数据的条数
scene: 0, //0展示spu 1添加修改spu 2展示添加sku
dialogTableVisible: false, //控制对话框的显示隐藏
spu: {}, //spu类的信息
sku: [], //sku列表的数据
loading: true,
};
},
methods: {
// 自定义事件的获取id
getShopId(listId) {
this.listId = listId;
this.reqSpuList();
},
//获取spu列表数据
async reqSpuList(page = 1) {
this.page = page;
if (this.listId) {
//携带三个参数 page第几页 limit 每一页需要展示多少条数据 三级分类id
let { getCategory3ID } = this.listId;
let { page, limit } = this;
let { data, code } = await this.$api.spu.reqSpuList(
page,
limit,
getCategory3ID
);
if (code != 200) return;
this.total = data.total;
this.records = data.records;
}
},
// 当分页器某一个展示数据条数发生变化的回调
sizeChange(limit) {
this.limit = limit;
this.reqSpuList();
},
//添加spu按钮的回调
addspu() {
this.scene = 1;
//通知子组件发请求
this.$refs.spu.addData(this.listId.getCategory3ID);
},
//修改spu
unDateSpu(row) {
this.scene = 1;
// 获取子组件使用$ref
this.$refs.spu.initData(row.id);
},
//自定义事件切换长景
changeScene({ scene, flag }) {
// flag 为了区分添加还是修改
//切换场景
this.scene = scene;
// 子组件通知父组件切换常景,需要重新拉取数据
if (flag == "修改") {
this.reqSpuList(this.page);
} else {
this.reqSpuList();
}
},
//删除spu按钮的回调
async despu(row) {
console.log(111);
let { code } = await this.$api.spu.deleteSpu(row.id);
if (code != 200) return;
this.$message("删除成功");
// spu 列表的个数大于1删除的时候停留在当前页,如果spu的个数小于1返回上一页
if (this.records.length > 1) {
this.reqSpuList(this.page);
} else {
this.reqSpuList(this.page - 1);
}
},
//添加sku按钮的回调
addsku(row) {
//切换场景为2
this.scene = 2;
//父组件调用子组件方法 让子组件发请求
this.$refs.sku.initData(row, this.listId);
},
// skuform切换场景
switching(scene) {
this.scene = scene;
},
// 查看sku列表
async handlesku(spu) {
//展示对话框
this.dialogTableVisible = true;
this.spu = spu;
//获取sku列表的数据进行展示
let { data, code } = await this.$api.sku.findBySpuId(spu.id);
if (code !== 200) return;
this.sku = data;
//关闭loading
this.loading = false;
},
//关闭对话框的回调
close() {
// loading开启
this.loading = true;
//情空sku列表
this.sku = [];
},
},
};
</script>
<style>
.el-card {
margin: 20px 0;
}
.el-pagination {
text-align: center;
}
img {
width: 100px;
height: 100px;
}
</style>
?sku页面
<template>
<div>
<!-- 表格 -->
<el-table style="width: 100%" border :data="records">
<el-table-column type="index" label="序号" width="80" align="center">
</el-table-column>
<el-table-column prop="skuName" label="名称" width="width">
</el-table-column>
<el-table-column prop="skuDesc" label="描述" width="width">
</el-table-column>
<el-table-column prop="prop" label="默认图片" width="110">
<template slot-scope="{ row }">
<img :src="row.skuDefaultImg" alt="" />
</template>
</el-table-column>
<el-table-column prop="prop" label="weight" width="80"> </el-table-column>
<el-table-column prop="prop" label="price" width="80"> </el-table-column>
<el-table-column prop="prop" label="操作" width="width">
<template slot-scope="{ row }">
<el-button
type="success"
icon="el-icon-sort-down"
size="mini"
v-if="row.isSale == 0"
@click="reqSale(row)"
></el-button>
<el-button
type="success"
icon="el-icon-sort-up"
size="mini"
@click="reqCancel(row)"
v-else
></el-button>
<el-button
type="primary"
icon="el-icon-edit"
size="mini"
@click="edit"
></el-button>
<el-button
type="info"
icon="el-icon-info"
size="mini"
@click="getSkuInfo(row)"
></el-button>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-sizes="[3, 5, 10]"
:page-size="limt"
layout="prev, pager, next,jumper,->,sizes,total"
:total="total"
@current-change="reqSklist"
@size-change="sizeChange"
>
</el-pagination>
<!-- 抽屉 -->
<el-drawer :visible.sync="drawer" :show-close="false" size="50%">
<!-- Layout 布局 分为24份 -->
<el-row>
<el-col :span="5">名称</el-col>
<el-col :span="16">{{ info.skuName }}</el-col>
</el-row>
<el-row>
<el-col :span="5">描述</el-col>
<el-col :span="16">{{ info.skuDesc }}</el-col>
</el-row>
<el-row>
<el-col :span="5">价格</el-col>
<el-col :span="16">{{ info.price }}元</el-col>
</el-row>
<el-row>
<el-col :span="5">平台属性</el-col>
<el-col :span="16">
<template>
<el-tag
type="success"
v-for="item in info.skuAttrValueList"
:key="item.id"
style="margin: 10px"
>{{ item.attrId }}--{{ item.valueId }}</el-tag
>
</template>
</el-col>
</el-row>
<el-row>
<el-col :span="5">商品图片</el-col>
<el-col :span="16">
<el-carousel height="150px">
<el-carousel-item v-for="item in info.skuImageList" :key="item.id">
<img :src="item.imgUrl" alt="" />
</el-carousel-item>
</el-carousel>
</el-col>
</el-row>
</el-drawer>
</div>
</template>
<script>
export default {
name: "Sku",
data() {
return {
page: 1, //当前第几页
limt: 10, //页面有多少条数据
records: [], //存储sku列表的数据
total: 0, //分页器一共展示多少条数据
info: {}, //sku信息
drawer: false,
};
},
created() {
this.reqSklist();
},
methods: {
async reqSklist(pages = 1) {
this.page = pages;
const { page, limt } = this;
let { code, data } = await this.$api.sku.reqSklist(page, limt);
if (code != 200) return;
this.total = data.total;
this.records = data.records;
},
sizeChange(limt) {
this.limt = limt;
this.reqSklist();
},
// 上架
async reqSale(row) {
let { code } = await this.$api.sku.reqSale(row.id);
if (code !== 200) return;
row.isSale = 1;
this.$message({ type: "success", message: "上架成功" });
},
// 下架
async reqCancel(row) {
let { code } = await this.$api.sku.reqCancel(row.id);
if (code !== 200) return;
row.isSale = 0;
this.$message({ type: "success", message: "下架成功" });
},
edit() {
this.$message("正在开发中");
},
//获取sku详情
async getSkuInfo(row) {
//展示抽屉
this.drawer = true;
let { code, data } = await this.$api.sku.getSkuById(row.id);
if (code !== 200) return;
this.info = data;
},
},
};
</script>
<style>
.el-pagination {
text-align: center;
}
img {
width: 80px;
height: 90px;
}
.el-row .el-col-5 {
font-size: 18px;
text-align: right;
}
.el-col {
margin: 10px;
}
.el-carousel__item h3 {
color: #475669;
font-size: 14px;
opacity: 0.75;
line-height: 150px;
margin: 0;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n + 1) {
background-color: #d3dce6;
}
</style>
深度选择器
scoped属性的作用
对于某一个组件,如果style添加上scoped属性,给当前子组件结构中都添加一个data-v-xxx自定义属性 (是通过属性选择器,给需要的元素添加上样式的)h3[ data-v-xxx ]
子组件的根标签(拥有父组件的自定义属性:一样的),如果子组件的根节点和父组件中书写的样式相同也会添加上相应的样式
如果父组件的样式加上了scoped还想影响到子组件的样式?我们可以使用深度选择器
深度选择器可以实现样式的穿透
原生 css <<<? ? ? ? less? ?/deep/? ? scss? ::v-deep
?
|