uniapp-商城-60-后台 新增商品(属性的选中和页面显示,数组join 的使用)

        前面添加了属性,添加属性的子级项目。也分析了如何回显,但是在添加新的商品的时,我们也同样需要进行选择,还要能正常的显示在界面上。下面对页面的显示进行分析。

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中的childrenclickConfirmSelect() {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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83554.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue框架

Vue 概况&#xff1a; Vue是一款用于构建用户界面的渐进式的JavaScript框架。&#xff08;官方;https:://cn.vuejs.org/) 框架:就是一套完整的项目解决方案&#xff0c;用于快速构建项目。 优点:大大提升前端项目的开发效率。 缺点:需要理解记忆框架的使用规则。&#xff…

解读RTOS 第七篇 · 驱动框架与中间件集成

1. 引言 在面向生产环境的 RTOS 系统中,硬件驱动框架与中间件层是连接底层外设与上层应用的桥梁。一个模块化、可扩展的驱动框架能够简化外设管理,提升代码可维护性;而丰富的中间件生态则为网络通信、文件系统、图形界面、安全加密等功能提供开箱即用的支持。本章将从驱动模…

JavaScript防抖与节流全解析

文章目录 前言:为什么需要防抖和节流基本概念与区别防抖(Debounce)节流(Throttle)关键区别防抖(Debounce)详解1. 基本防抖函数实现2. 防抖函数的使用3. 防抖函数的工作流程4. 防抖函数进阶 - 立即执行选项节流(Throttle)详解1. 基本节流函数实现时间戳法(第一次会立即执行)定…

JavaScript入门【3】面向对象

1.对象: 1.概述: 在js中除了5中基本类型之外,剩下得都是对象Object类型(引用类型),他们的顶级父类是Object;2.形式: 在js中,对象类型的格式为key-value形式,key表示属性,value表示属性的值3.创建对象的方式: 方式1:通过new关键字创建(不常用) let person new Object();// 添…

oracle主备切换参考

主备正常切换操作参考&#xff1a;RAC两节点->单机 &#xff08;rac和单机的操作区别&#xff1a;就是关闭其它节点&#xff0c;剩一个节点操作即可&#xff09; 1.主库准备 检查状态 SQL> select inst_id,database_role,OPEN_MODE from gv$database; INST_ID DATA…

端到端自动驾驶系统实战指南:从Comma.ai架构到PyTorch部署

引言&#xff1a;端到端自动驾驶的技术革命 在自动驾驶技术演进历程中&#xff0c;端到端&#xff08;End-to-End&#xff09;架构正引领新一轮技术革命。不同于传统分模块处理感知、规划、控制的方案&#xff0c;端到端系统通过深度神经网络直接建立传感器原始数据到车辆控制…

使用 Kotlin 和 Jetpack Compose 开发 Wear OS 应用的完整指南

环境配置与项目搭建 1. Gradle 依赖配置 // build.gradle (Module) android {buildFeatures {compose true}composeOptions {kotlinCompilerExtensionVersion "1.5.3"} }dependencies {def wear_compose_version "1.2.0"implementation "androidx.…

应用层协议简介:以 HTTP 和 MQTT 为例

文章目录 应用层协议简介&#xff1a;什么是应用层协议&#xff1f;为什么需要应用层协议&#xff1f;什么是应用层协议&#xff1f;为什么需要应用层协议&#xff1f; HTTP 协议详解HTTP 协议特点HTTP 工作的基本原理HTTP 请求与响应示例为什么 Web 应用基于 HTTP 请求&#x…

Kafka快速安装与使用

引言 这篇文章是一篇Ubuntu(Linux)环境下的Kafka安装与使用教程&#xff0c;通过本文&#xff0c;你可以非常快速搭建一个kafka的小单元进行日常开发与调测。 安装步骤 下载与解压安装 首先我们需要下载一下Kafka&#xff0c;这里笔者采用wget指令&#xff1a; wget https:…

PD 分离推理的加速大招,百度智能云网络基础设施和通信组件的优化实践

为了适应 PD 分离式推理部署架构&#xff0c;百度智能云从物理网络层面的「4us 端到端低时延」HPN 集群建设&#xff0c;到网络流量层面的设备配置和管理&#xff0c;再到通信组件和算子层面的优化&#xff0c;显著提升了上层推理服务的整体性能。 百度智能云在大规模 PD 分离…

flutter Stream 有哪两种订阅模式。

Flutter 中的 Stream 有两种订阅模式&#xff1a; ​单订阅模式 (Single Subscription)​​ 只能有一个订阅者&#xff08;listen 只能调用一次&#xff09;&#xff0c;后续调用会抛出异常。数据仅在订阅后开始传递&#xff0c;适用于点对点通信场景&#xff08;如文件读取流…

Python爬虫实战:研究JavaScript 环境补全逆向解密

1. 引言 1.1 研究背景与意义 随着互联网的快速发展,大量有价值的数据被发布在各种网站上。然而,为了保护数据安全和商业利益,许多网站采用了 JavaScript 加密技术对敏感数据进行保护。这些加密技术使得传统的爬虫技术难以直接获取和解析数据,给数据采集工作带来了巨大挑战…

[system-design] ByteByteGo_Note Summary

目录 通信协议 REST API 与 GraphQL gRPC 如何工作&#xff1f; 什么是Webhook&#xff1f; 如何提高应用程序接口的性能&#xff1f; HTTP 1.0 -> HTTP 1.1 -> HTTP 2.0 -> HTTP 3.0 (QUIC) SOAP vs REST vs GraphQL vs RPC 代码优先与应用程序接口优先 HTT…

Linux中的进程

进程控制 fork 函数 fork 函数从已存在的进程中创建新的进程&#xff0c;已存在进程为父进程&#xff0c;新创建进程为子进程 fork 的常规用法 一个父进程希望复制自己&#xff0c;使父子进程同时执行不同的代码段。例如&#xff0c;父进程等待客户端请求&#xff0c;生成子…

EDR与XDR如何选择适合您的网络安全解决方案

1. 什么是EDR&#xff1f; 端点检测与响应&#xff08;EDR&#xff09; 专注于保护端点设备&#xff08;如电脑、服务器、移动设备&#xff09;。通过在端点安装代理软件&#xff0c;EDR实时监控设备活动&#xff0c;检测威胁并快速响应。 EDR核心功能 实时监控&#xff1a;…

AGI大模型(21):混合检索之混合搜索

为了执行混合搜索,我们结合了 BM25 和密集检索的结果。每种方法的分数均经过标准化和加权以获得最佳总体结果 1 代码 先编写 BM25搜索的代码,再编写密集检索的代码,最后进行混合。 from rank_bm25 import BM25Okapi from nltk.tokenize import word_tokenize import jieb…

2025最新的软件测试面试大全(含答案+文档)

一、软件测试基础面试题 1、阐述软件生命周期都有哪些阶段? 常见的软件生命周期模型有哪些? 软件生命周期是指一个计算机软件从功能确定设计&#xff0c;到开发成功投入使用&#xff0c;并在使用中不断地修改、增补和完善&#xff0c;直到停止该软件的使用的全过程(从酝酿到…

C++.神经网络与深度学习(二次修改)

神经网络与深度学习 1. 神经网络基础1.1 神经元模型与激活函数1.2 神经网络结构与前向传播2.1 损失函数与优化算法均方误差损失函数交叉熵损失函数梯度下降优化算法2.2 反向传播与梯度计算神经元的反向传播3.1 神经元类设计与实现神经元类代码实现代码思路3.2 神经网络类构建神…

FPGA图像处理(六)------ 图像腐蚀and图像膨胀

默认迭代次数为1&#xff0c;只进行一次腐蚀、膨胀 一、图像腐蚀 1.相关定义 2.图像腐蚀效果图 3.fpga实现 彩色图像灰度化&#xff0c;灰度图像二值化&#xff0c;图像缓存生成滤波模块&#xff08;3*3&#xff09;&#xff0c;图像腐蚀算法 timescale 1ns / 1ps // // Des…

中国版Cursor:CodeBuddy腾讯云代码助手使用体验

我正在参加CodeBuddy「首席试玩官」内容创作大赛&#xff0c;本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴” 1.CodeBuddy简介 腾讯云代码助手CodeBuddy&#xff0c;这个是一款编程插件&#xff0c;我们可以在各个编程…