1、概述
在前面 ,我们将商品页面的布局给完成了,这里来对表单的标签输入进行校验,看看这里的校验还是不是也需要兼容微信小程序,还有没有前面遇到的自定义正则进行校验的情况。
另外这里还需要完成商品属性的添加,就是前面在布局中提到的弹窗。弹窗这里涉及的内容还很多,后面我们还会进一步来分析和研究。
2、表单校验
包含图片、名称、价格、类别、属性、描述等等,这里我们看到应该必须要有图片、名称、价格、类别这个几个元素。
<uni-forms ref="goodsForm" :model="goodsFormData" :rules="goodsRules" :label-width="100" label-align="right">
2.1 这里就没有删除rules ,因为我们这里没有自定义的校验规则。
2.2 必须填写的属性,页面的froms-item 中要加入 required这个属性值,js规则部分,要通过name定义其他规则,也加入required,没有就不管了,如这里的图。
2.3 要进行规则的校验,必须填写name 便于进行规则的指定
没有name,没有办法指定,见上图
2.4 data的规则数据定义。绑定到标签的 name
如这里的name 和 price 就是名称和价格的规则。写道我们表单的rules里面(goodsRules)
特别要注意书写的格式。
3、分类 使用的下拉框 云端数据获取 就这个uni-data-select 可以获取云端数据,所以用这个组件较为方便。
需要安装,并使用云端数据获取
<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>
4、商品属性 采用的cell的单元格(uview中组件,可以被点击)
4.1 cell
该组件就是cell单元格。一般用于一组列表的情况,比如个人中心页,设置页等,默认有一个边框,且整个可以被点击 。
title是组件显示的名称;
isLink 就是显示一个右侧的箭头;
border:不用显示默认的边框; 注意使用加v-band(也就是加 :)
<u-cell :title="skuTitle" isLink :border="false" @click="clickSelect"></u-cell>
然后我们给这个点击加一个事件。需要-可以读5小节代码。
//点击选择属性
clickSelect() {
this.$refs.attrWrapPop.open();
if (this.skuArr.length) return;
this.getSkuData();
},
4.2 在这个组件下面,可以将填写的属性展示出来。
具体可以阅读,5小节的代码。
<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>
4.3 弹出窗 使用的uni-popup
前面的章节,也对这个组件进行过研究。
/https://uniapp.dcloud.net.cn/component/uniui/uni-popup.html
在 47 48章节 。
4.3.1 第一点击cell 从底部弹出窗
注意:type要加
<uni-popup ref="attrWrapPop" type="bottom"><!-- 底部弹出 type ref 是一个名字属性,便于被调用 给 clickSelect 在 clickSelect 函数中调用了该接口--><view class="attrWrapper"><view class="head"><view class="title">商品属性</view><view class="addAttr" @click="clickAddAttr()">+ 添加属性</view></view><view class="body"><view class="item" v-for="(item,index) in skuArr"><view class="top"><checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox><view class="font">{{item.skuName}}</view></view><view class="btnGroup" v-if="item.checked"><view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"@click="clickChlidBtn(index,cIdx)">{{child.name}}</view><view class="btn" @click="clickAddAttr(index)"><u-icon name="plus"></u-icon></view></view></view></view><view class="foot"><button type="primary" @click="clickConfirmSelect">确认选择</button></view></view><view class="safe-area-bottom"></view></uni-popup>
4.3.2 就是展示可以选手属性元素 布局如下
这一部分就是显示可以选的属性值
1、属性 可以有多个,如颜色、规格、口味等,就是一个 循环 实现
<view class="item" v-for="(item,index) in skuArr">
2、每一个属性 可以罗列多个可选项 进行选择,并可以手动添加 可选项
2.1 分成两部分 一个top(显示属性 ) 前面有一个可选框checkbox,后面是属性名字
<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
<view class="font">{{item.skuName}}</view>
2.2 一个就是可以选的属性组排列,最后跟一个图标 +号
<view class="top">
<checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox>
<view class="font">{{item.skuName}}</view>
</view>
<view class="btnGroup" v-if="item.checked">
<view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"
@click="clickChlidBtn(index,cIdx)">{{child.name}}</view>
<view class="btn" @click="clickAddAttr(index)">
<u-icon name="plus"></u-icon>
</view>
</view>
3、点击添加,又有点击事件--->弹出窗
<view class="btn" @click="clickAddAttr(index)">
<u-icon name="plus"></u-icon>
</view>
4、具体的css样式见5的代码
5、代码
<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"><view class="attrWrapper"><view class="head"><view class="title">商品属性</view><view class="addAttr" @click="clickAddAttr()">+ 添加属性</view></view><view class="body"><view class="item" v-for="(item,index) in skuArr"><view class="top"><checkbox :checked="item.checked" @click="changeCheckbox(index)"></checkbox><view class="font">{{item.skuName}}</view></view><view class="btnGroup" v-if="item.checked"><view class="btn" :class="child.checked?'active':''" v-for="(child,cIdx) in item.children"@click="clickChlidBtn(index,cIdx)">{{child.name}}</view><view class="btn" @click="clickAddAttr(index)"><u-icon name="plus"></u-icon></view></view></view></view><view class="foot"><button type="primary" @click="clickConfirmSelect">确认选择</button></view></view><view class="safe-area-bottom"></view></uni-popup><uni-popup ref="addAttrPop"><uni-popup-dialog mode="input" title="新增" placeholder="请输入新增的内容"@confirm="dialogConfirm"></uni-popup-dialog></uni-popup></view>
</template><script>const skuCloudObj = uniCloud.importObject("kt-mall-sku", {"customUI": true});const goodsCloudObj = uniCloud.importObject("kt-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: []};},onLoad() {},computed: {skuTitle() {if (this.goodsFormData.sku_select.length) {let arr = this.goodsFormData.sku_select.map(item => {return item.skuName})return arr.join("/")} else {return "点击添加属性"}}},methods: {//属性返回子元素的名称skuChildName(arr) {let nsArr = arr.map(item => {return item.name})return nsArr.join("/")},//点击确认选择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 = arrthis.$refs.attrWrapPop.close();},//获取sku列表async getSkuData() {let res = await skuCloudObj.get();this.skuArr = res.dataconsole.log(res);},//点击添加属性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();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>