前面添加了属性,添加属性的子级项目。也分析了如何回显,但是在添加新的商品的时,我们也同样需要进行选择,还要能正常的显示在界面上。下面对页面的显示进行分析。
1、界面情况回顾
属性显示其实是个一嵌套的数据显示。
2、选中的界面
3、页面显示
使用了函数方法skuChildName,
还使用了点击就弹窗在两个地方都用了。clickSelect
对于默认显示:还用到了skuTitle 计算接口,
当然这个接口也可以用方法来做,但这里值都可以取得,所以就用这方法。
前一个章节讲了显示,需要添加一个view 进行显示:
4、相应显示的需要的方法 skuChildName
方法很简单,就是将读取的数据,arr数组,找出数组中的name ,然后对name进行/ 拼接
注意使用的方法 map
对数组中的值 使用 / 进行拼接。
注意这里只是计算了 子级 项的name
//属性返回子元素的名称
skuChildName(arr) {
let nsArr = arr.map(item => {
return item.name
})
return nsArr.join("/")
},
5、计算页面的显示,如果没有值,那么就显示点击添加属性
是一个计算值的接口,默认是显示点击添加属性
如果this.goodsFormData.sku_select.length 不为0 ,就显示属性值中的name,用到的用 jion / 链接
注意不是 children,这里只是计算了父级 属性
在页面上显示 也是直接用了该函数名字
computed: {
skuTitle() {
if (this.goodsFormData.sku_select.length) {
let arr = this.goodsFormData.sku_select.map(item => {
return item.skuName
})
return arr.join("/")
} else {
return "点击添加属性"
}
}
},
<uni-forms-item label="商品属性" >
<u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
<view class="skuList">
<view class="item" v-for="item in goodsFormData.sku_select" @click="clickSelect">
<view class="left">{{item.skuName}}:</view>
<view class="right">{{skuChildName(item.children)}}</view>
</view>
</view>
</uni-forms-item>
6 整体的代码(除开商品,属性这一栏 界面的 全都有了)
<template>
<view class="goodsView">
<!-- 添加商品 -->
<uni-forms ref="goodsForm" :model="goodsFormData" :rules="goodsRules" :label-width="100" label-align="right">
<uni-forms-item label="商品图片" required="true">
<uni-file-picker v-model="goodsFormData.thumb" fileMediatype="image" mode="grid" ></uni-file-picker>
</uni-forms-item>
<uni-forms-item label="商品名称" required name="name" >
<!-- trim 去空格 -->
<uni-easyinput v-model="goodsFormData.name" placeholder="请输入商品名称" trim="both"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="产品分类" required name="category_id">
<!-- 云端数据 下拉框获取 field 就是获取的内容 一定要写成 value text 这是官方定义的 value选中的值,text显示的文本,也就是value后台用,text前台用 -->
<!-- 利用这个组件就实现了后端数据库的读取 -->
<uni-data-select collection="green-mall-categories" field="_id as value, name as text"
v-model="goodsFormData.category_id"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="商品价格" required name="price">
<!-- trim 去空格 -->
<uni-easyinput type="number" v-model="goodsFormData.price" placeholder="请输入商品价格"
trim="both"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="商品原价">
<!-- trim 去空格 -->
<uni-easyinput type="number" v-model="goodsFormData.before_price" placeholder="请输入原价"
trim="both"></uni-easyinput>
</uni-forms-item>
<uni-forms-item label="商品属性" >
<u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
<view class="skuList">
<view class="item" v-for="item in goodsFormData.sku_select" @click="clickSelect">
<view class="left">{{item.skuName}}:</view>
<view class="right">{{skuChildName(item.children)}}</view>
</view>
</view>
</uni-forms-item>
<uni-forms-item label="商品描述">
<!-- type 是类型 textarea 就是大框 -->
<uni-easyinput type="textarea" placeholder="请输入详细的描述信息"
v-model="goodsFormData.description"></uni-easyinput>
</uni-forms-item>
<view class="btnView">
<button type="primary" @click="onSubmit">确认提交</button>
</view>
</uni-forms>
<uni-popup ref="attrWrapPop" type="bottom">
<!-- 底部弹出 type
ref 是一个名字属性,便于被调用 给 clickSelect
在 clickSelect 函数中调用了该接口
-->
<view class="attrWrapper">
<!-- 分三部分 就是上中下 头身体和尾部 -->
<view class="head">
<view class="title">商品属性</view>
<!-- clickAddAttr函数 添加属性的-->
<view class="addAttr" @click="clickAddAttr()">+ 添加属性</view>
</view>
<view class="body">
<!-- 读取 skuArr 循环显示 分两部分显示 top 和 btngroup-->
<view class="item" v-for="(item,index) in skuArr">
<view class="top">
<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
<!-- changeCheckbox 选中就做这个操作 -->
<!-- checked 是否被选中的属性标识 -->
<view class="font">{{item.skuName}}</view>
</view>
<view class="btnGroup" v-if="item.checked">
<!-- 需要判断checked 是不是true 是不是选中,选中了就展示-->
<view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"
@click="clickChlidBtn(index,cIdx)">{{child.name}}</view>
<!-- btn 读取skuArr ,循环显示
选中就加class 为active
点击 就执行 clickChlidBtn函数
-->
<view class="btn" @click="clickAddAttr(index)">
<!-- btn 该盒子就是一个 + 号,用来添加该属性下的选项
clickAddAttr 点就执行
uicon就一个 + 号图标
-->
<u-icon name="plus"></u-icon>
</view>
</view>
</view>
</view>
<view class="foot">
<button type="primary" @click="clickConfirmSelect">确认选择</button>
<!-- 按钮 ,蓝色提交按钮
type 就是颜色格式
点击就是确认该商品的属性
clickConfirmSelect
-->
</view>
</view>
<view class="safe-area-bottom"></view>
<!--防止被苹果虚拟home键 挡住 -->
<!--
这里就是直接调用的app.vue的全局样式。
什么是全局样式:就是样式那里没有scoped 的,所以在以前老是要写一个表示局部样式,就怕vue 中class名字一样了
如果你不些scoped ,就要把全局的view 的class 写在最前面。
不知道懂不懂,慢慢悟吧
-->
</uni-popup>
<!-- 这里是点击的添加属性的弹窗 -->
<!-- 你可能懵逼了
那个添加属性的弹窗?
两个弹窗都要用
一个是第一个弹窗中的右上角的添加属性 class名字 addAttr
一个是属性规格下的选项中的 + class的名字就是btn
-->
<uni-popup ref="addAttrPop">
<uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"
@confirm="dialogConfirm"></uni-popup-dialog>
<!-- dialogConfirm 是一个确认后处理逻辑 -->
</uni-popup>
</view>
</template>
<script>
const skuCloudObj = uniCloud.importObject("green-mall-sku", {
"customUI": true
});
const goodsCloudObj = uniCloud.importObject("green-mall-goods", {
"customUI": true
})
export default {
data() {
return {
goodsFormData: {
thumb: [],
name: "",
category_id: null,
price: null,
before_price: null,
description: "",
sku_select: []
},
addAttrType: "parent", //parent代表父,child代表子
goodsRules: {
name: {
rules: [{
required: true,
errorMessage: "请输入产品名称"
}]
},
price: {
rules: [{
required: true,
errorMessage: "请输入产品价格"
}]
},
category_id: {
rules: [{
required: true,
errorMessage: "请输入产品分类"
}]
}
},
/*
skuArr: [{
_id:1,
skuName:"颜色",
checked:false,
children:[{
name:"红",
checked:false
},{
name:"蓝",
checked:false
}]
},{
_id:2,
skuName:"规格",
checked:false,
children:[{
name:"M",
checked:false
},{
name:"S",
checked:false
}]
}],
*/
// 上面是一个数据结构例子,后台数据就应该着这样存
// 实际是下面的[]
skuArr: [],
};
},
onLoad() {
},
computed: {
skuTitle() {
if (this.goodsFormData.sku_select.length) {
let arr = this.goodsFormData.sku_select.map(item => {
return item.skuName
})
console.log(arr);
return arr.join("/")
} else {
return "点击添加属性"
}
}
},
methods: {
//属性返回子元素的名称
skuChildName(arr) {
let nsArr = arr.map(item => {
return item.name
})
return nsArr.join("/")
},
//点击确认选择 是在弹出框上选
//some 数组至少有一个满足 没有就是false every就是每一个都要满足,不满足就是false
// 这里filter 选出父级属性 checked =true 被选中的 且子级属性有一个被选中的数组对象;
// 然后再对选中的对象,逐一进行map运算
//运算就是filter 过滤出来选中的子级元素
//返回一个 数组 arr 且元素为一个对象,对象展开了item ,然后将children的值放到里面,覆盖item中的children
clickConfirmSelect() {
let arr = this.skuArr.filter(item => {
let state = item.children.some(child => child.checked)
return item.checked && state
}).map(item => {
let children = item.children.filter(child => {
return child.checked
})
// console.log(item,11111111);
// console.log(children,2222222);
return {
...item,
// children //覆盖了item中children
}
})
this.goodsFormData.sku_select = arr //赋值后,页面在使用这个数组来显示 立即回显
this.$refs.attrWrapPop.close(); //关闭掉弹窗
},
//获取sku列表
async getSkuData() {
let res = await skuCloudObj.get();
this.skuArr = res.data
// console.log(res);
},
//点击添加属性 index 存在就是嵌套下 父类属性的子类选项 ,不存在就是添加父类属性
clickAddAttr(index = null) {
if (index == null) {
this.addAttrType = "parent"
this.attrIndex = null
} else {
this.addAttrType = "child"
this.attrIndex = index
}
this.$refs.addAttrPop.open();
},
//添加属性弹窗的确认按钮
async dialogConfirm(e) {
if (!e) return;
if (this.addAttrType == "parent") {
let obj = {
skuName: e,
checked: true,
children: []
}
let res = await skuCloudObj.add(obj)
obj._id = res.id;
this.skuArr.push(obj)
//向数组中添加一个元素,就弹窗的确认按钮
} else if (this.addAttrType == "child") {
let obj = {
name: e,
checked: true
}
let id = this.skuArr[this.attrIndex]._id;
let res = await skuCloudObj.updateChild(id, obj)
this.skuArr[this.attrIndex].children.push(obj)
}
},
//点击属性的复选框 改变了值,也相应改变了显示 后面也把值存到了数据库
changeCheckbox(index) {
this.skuArr[index].checked = !this.skuArr[index].checked
},
//点击属性值的子元素 改变了值,也相应改变了显示 后面也把值存到了数据库
clickChlidBtn(index, cIdx) {
this.skuArr[index].children[cIdx].checked = !this.skuArr[index].children[cIdx].checked
},
//点击选择属性
clickSelect() {
this.$refs.attrWrapPop.open(); //使用open方法弹出来
if (this.skuArr.length) return;
this.getSkuData();
},
//点击提交表单
onSubmit() {
this.$refs.goodsForm.validate().then(res => {
this.toDataBase();
}).catch(err => {
console.log(err);
})
},
//上传到云数据库
async toDataBase() {
//这里缺少一个更新的按钮,需要在list中去实现
this.goodsFormData.thumb = this.goodsFormData.thumb.map(item => {
return {
url: item.url,
name: item.name,
extname: item.extname
}
})
let res = await goodsCloudObj.add(this.goodsFormData)
uni.showToast({
title: "新增商品成功"
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
}
</script>
<style lang="scss" scoped>
.goodsView {
padding: 30rpx;
.skuList {
.item {
padding: 30rpx;
background: $page-bg-color;
margin: 15rpx 0;
@include flex-box-set(start);
}
}
}
.attrWrapper {
padding: 30rpx;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
.head {
@include flex-box();
font-size: 34rpx;
margin-bottom: 30rpx;
.title {
font-weight: bold;
}
.addAttr {
color: $brand-theme-color-aux;
}
}
.body {
.item {
border-top: 1px solid $border-color-light;
&:last-child {
border-bottom: 1px solid $border-color-light;
}
.top {
padding: 30rpx 0;
@include flex-box-set(start);
.font {
padding-left: 10rpx;
font-weight: bold;
}
}
.btnGroup {
padding: 10rpx 0 30rpx;
@include flex-box-set(start);
flex-wrap: wrap;
.btn {
padding: 0rpx 25rpx;
height: 60rpx;
border: 1rpx solid $border-color-light;
margin-right: 20rpx;
border-radius: 10rpx;
color: $text-font-color-2;
margin-bottom: 20rpx;
@include flex-box-set();
&.active {
border-color: $brand-theme-color;
color: $brand-theme-color;
background: rgba(236, 87, 79, 0.1);
}
}
}
}
}
.foot {
padding: 50rpx 200rpx;
}
}
</style>