uniapp-商城-56-后台 新增商品(弹窗属性继续分析)

发布于:2025-05-14 ⋅ 阅读:(9) ⋅ 点赞:(0)

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)
                }

            },