1、概述
前面我们讲了布局和相应商品属性的页面布局。属性是一个弹窗,它是一个cell的组件的实现属性。点击该cell就会调用uni-popup 进行弹窗。基本的页面布局如下:
属性显示其实是个一嵌套的数据显示。
2 页面显示商品属性 点击添加属性
2.1 代码如下:
<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>
2.2 代码解读
cell :
该组件就是cell单元格。一般用于一组列表的情况,比如个人中心页,设置页等,默认有一个边框,且整个可以被点击 。
title是组件显示的名称;
isLink 就是显示一个右侧的箭头;
border:不用显示默认的边框; 注意使用加v-band(也就是加 :)
<uni-forms-item label="商品属性" >
// label 显示在界面上的文本 就是商品属性
<u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
// cell 实现点击的组件 title 就是 该如何显示?-----见2.3
// clickSelect 是一个函数 ----见 2.4
//下面是 显示选中后效果,后面还会继续分析
<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>
2.3 title的计算
默认就是显示的点击添加属性,如果已经添加了属性就会进行显示,把数据传递给this.goodsFormData.sku_select
如果数据有,那就是数据库有,数据库的值也是来自于 一开始选中的,后面再来分析这个选择接口。
computed: {
skuTitle() {
if (this.goodsFormData.sku_select.length) {
let arr = this.goodsFormData.sku_select.map(item => {
return item.skuName
})
return arr.join("/")
} else {
return "点击添加属性"
}
}
},
2.4 对cell 的点击clickSelect
//点击选择属性
clickSelect() {
//通过uni-popup 的pen方法,弹出来, 看---2.5 uni-popup
this.$refs.attrWrapPop.open(); //使用open方法弹出来
if (this.skuArr.length) return; //如果数据存在就不用继续执行getSkuData 函数了
this.getSkuData(); }, //如果数据不存在就继续执行getSkuData ---看2.6 getSkuData
2.5 弹窗 中的属性布局和处理 unipopup
2.5.1 解析
<uni-popup ref="attrWrapPop" type="bottom">
<!-- 底部弹出 type
ref 是一个名字属性,便于被调用 给 clickSelect
在 clickSelect 函数中调用了该接口 见2.6.1
-->
<view class="attrWrapper">
<!-- 分三部分 就是上中下 头身体和尾部 -->
<view class="head">
<view class="title">商品属性</view>
<!-- clickAddAttr函数 添加属性的 见 2.7 -->
<view class="addAttr" @click="clickAddAttr()">+ 添加属性</view>
</view>
<view class="body">
<!-- 读取 skuArr 循环显示 分两部分显示 top 和 btngroup skuArr 见2.8 -->
<view class="item" v-for="(item,index) in skuArr">
<view class="top">
<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
<!-- changeCheckbox 选中就做这个操作 见 2.9 -->
<!-- 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函数 见-2.10
-->
<view class="btn" @click="clickAddAttr(index)">
<!-- btn 该盒子就是一个 + 号,用来添加该属性下的选项
clickAddAttr 点就执行 见 2.11
uicon就一个 + 号图标
-->
<u-icon name="plus"></u-icon>
</view>
</view>
</view>
</view>
<view class="foot">
<button type="primary" @click="clickConfirmSelect">确认选择</button>
<!-- 按钮 ,蓝色提交按钮
type 就是颜色格式
点击就是确认该商品的属性
clickConfirmSelect 见2.12
-->
</view>
</view>
<view class="safe-area-bottom"></view>
<!--防止被苹果虚拟home键 挡住 -->
<!--
这里就是直接调用的app.vue的全局样式。
什么是全局样式:就是样式那里没有scoped 的,所以在以前老是要写一个表示局部样式,就怕vue 中class名字一样了
如果你不些scoped ,就要把全局的view 的class 写在最前面。
不知道懂不懂,慢慢悟吧 见2.13
-->
</uni-popup>
<!-- 这里是点击的添加属性的弹窗 -->
<!-- 你可能懵逼了
那个添加属性的弹窗?
两个弹窗都要用
一个是第一个弹窗中的右上角的添加属性 class名字 addAttr
一个是属性规格下的选项中的 + class的名字就是btn
-->
<uni-popup ref="addAttrPop">
<uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"
@confirm="dialogConfirm"></uni-popup-dialog>
<!-- dialogConfirm 是一个确认后处理逻辑 见 2.14-->
</uni-popup>
2.5.2 具体代码:
<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>
2.6 属性表单中,添加属性和获取数据
2.6.1 clickSelect 如果点击添加属性 对cell单元的点击和2.4一样
/点击选择属性
clickSelect() {
//通过uni-popup 的pen方法,弹出来, 看---2.5 uni-popup
this.$refs.attrWrapPop.open(); //使用open方法弹出来
if (this.skuArr.length) return; //如果数据存在就不用继续执行getSkuData 函数了
this.getSkuData(); }, //如果数据不存在就继续执行getSkuData ---看2.6.2 getSkuData
2.6.2 弹窗中获取数据接口 getSkuData
云对象方式处理:后面再分析
//获取sku列表
async getSkuData() {
let res = await skuCloudObj.get();
this.skuArr = res.data
console.log(res);
},
2.7 函数方法添加属性 clickAddAttr
页面弹窗:
<!-- 这里是点击的添加属性的弹窗 -->
<!-- 你可能懵逼了
那个添加属性的弹窗?
两个弹窗都要用
一个是第一个弹窗中的右上角的添加属性 class名字 addAttr
一个是属性规格下的选项中的 + class的名字就是btn
-->
<uni-popup ref="addAttrPop">
<uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"
@confirm="dialogConfirm"></uni-popup-dialog>
<!-- dialogConfirm 是一个确认后处理逻辑 -->
</uni-popup>
方法:
//点击添加属性
clickAddAttr(index = null) {
if (index == null) {
this.addAttrType = "parent"
this.attrIndex = null
} else {
this.addAttrType = "child"
this.attrIndex = index
}
this.$refs.addAttrPop.open();
},
2.8 skuArr 数据结构
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: [],
2.9 选中属性类的操作,不是属性下面的选项 changeCheckbox
//点击属性的复选框 改变了值,也相应改变了显示 后面也把值存到了数据库
changeCheckbox(index) {
this.skuArr[index].checked = !this.skuArr[index].checked
},
2.10 选中属性类下的选项 clickChlidBtn
//点击属性值的子元素 改变了值,也相应改变了显示 后面也把值存到了数据库
clickChlidBtn(index, cIdx) {
this.skuArr[index].children[cIdx].checked = !this.skuArr[index].children[cIdx].checked
},
2.11 clickAddAttr 添加属性中的选项 点击 + 图 标
//点击添加属性
clickAddAttr(index = null) {
if (index == null) {
this.addAttrType = "parent"
this.attrIndex = null
} else {
this.addAttrType = "child"
this.attrIndex = index
}
this.$refs.addAttrPop.open();
},
2.12 选中属性后,点击确认button,使用函数 clickConfirmSelect
//点击确认选择
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
})
return {
...item,
children
}
})
this.goodsFormData.sku_select = arr
this.$refs.attrWrapPop.close();
},
2.13 全局的样式以及苹果底部安全区域,这样就不用在本vue写样式safe-area-bottom,直接调用app.vue中写。
<view class="safe-area-bottom"></view>
<!--防止被苹果虚拟home键 挡住 -->
<!--
这里就是直接调用的app.vue的全局样式。
什么是全局样式:就是样式那里没有scoped 的,所以在以前老是要写一个表示局部样式,就怕vue 中class名字一样了
如果你不些scoped ,就要把全局的view 的class 写在最前面。
不知道懂不懂,慢慢悟吧
-->
2.14 dialogConfirm 弹窗 确认后的处理逻辑
通过云对象的方式解析处理:
//添加属性弹窗的确认按钮
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)
}
},