为了符合各大网友的产品需求,此文档有两个版本规格效果
版本1.小程序商品进入商品详情自动选中第一个相应规格参数,价格原价库存
版本2.小程序商品进入详情,不选择任何规格,当库存为0,规格展示为0的相应规格参数无法选中和展示

太难了,如果该文档帮助到了你,那就麻烦你那单身二十年的手速双击二连一下,哈哈哈

  1. 2023.06.01修改 小程序展示和后台管理系统添加商品
  2. 2023.11.18修改 小程序展示和后台管理系统添加商品
  3. 2023.11.29修改 小程序展示和后台管理系统添加商品
  4. 2024.11.13修改,小程序规格展示逻辑版本2
    版本1
    在这里插入图片描述
    版本2
    在这里插入图片描述

在这里插入图片描述
vue2+Element UI 2023.11.18 修改

<template>
	<div>
		<div class="border-box">
			<div class="border">
				<div class="name">商品规格</div>
				<div class="border-guige">
					<div v-for="(item, index) in itemList" :key="index" style="margin-top: 20px">
						<div class="flex-guige">
							<div>规格名</div>
							<div class="width-input">
								<el-input v-model="item.specificationname" placeholder="请输入内容"></el-input>
							</div>
						</div>
						<div class="flex-guige" style="margin-top: 20px">
							<div>规格值</div>
							<div class="width-tag">
								<el-tag v-for="(tag, ins) in item.specificationvalue" :key="ins" closable
									:disable-transitions="false" @close="handleClose(index, ins)">
									{{ tag.value }}
								</el-tag>
								<el-input class="input-new-tag" v-if="inpurIndex == index && inputVisible"
									v-model="inputValue" ref="saveTagInput" size="small"
									@keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm"
									@focus="focusConfirm(index)">
								</el-input>
								<el-button v-else class="button-new-tag" size="small" @click="showInput(index)">+
									规格值</el-button>
							</div>
						</div>
					</div>
					<div class="flex-guige" style="margin-top: 20px">
						<el-button type="primary" plain size="small" @click="addValue">添加规格项</el-button>
						<el-button type="danger" size="small" plain @click="deleteValue">清空规格项</el-button>
					</div>
				</div>
			</div>
			<div class="border" style="margin-top:20px">
				<div class="name">规格明细</div>
				<el-table :data="mapList" border style="width: 100%">
					<el-table-column v-for="(item, index) in itemList" :key="index" :label="item.specificationname"
						width='120'>
						<!-- 分行显示 -->
						<template slot-scope="scope">
							<div v-if="scope.row.sku[index]">{{ scope.row.sku[index].value }}</div>
						</template>
					</el-table-column>
					<el-table-column prop="groupName" label="库存" width='120'>
						<template slot-scope="scope">
							<el-input v-model="scope.row.stock" placeholder="请输入内容"></el-input>
						</template>
					</el-table-column>
					<el-table-column prop="address" label="原价" width='120'>
						<template slot-scope="scope">
							<el-input v-model="scope.row.cprice" placeholder="请输入内容"></el-input>
						</template>
					</el-table-column>
					<el-table-column prop="goodsCount" label="现价" width='140'>
						<template slot-scope="scope">
							<el-input v-model="scope.row.oprice" placeholder="请输入内容"></el-input>
						</template>
					</el-table-column>
					<el-table-column prop="goodsCount" label="头图" width='190'>
						<template slot-scope="scope">
							<el-upload action="https://jsonplaceholder.typicode.com/posts/" :limit="1" list-type="picture-card"
							@on-preview="handlePictureCardPreview" @on-remove="handleRemove">
							<i class="el-icon-plus"></i>
						</el-upload>
						<el-dialog :visible.sync="dialogVisible">
							<img width="100%" :src="scope.row.img" alt="">
						</el-dialog>
						</template>
						
					</el-table-column>
					<el-table-column fixed="right" align="center" width="230" label="操作">
						<el-button type="primary" size="small">打包</el-button>
					</el-table-column>
				</el-table>
			</div>
		</div>
		<el-button type="primary" @click="onSave">保存</el-button>
		<table border cellspacing="0" cellpadding="0" id="table"></table>
	</div>
</template>

<script>
export default {
	data() {
		return {
			sourceAttribute: [
				{
					name: "颜色",
					item: ["黑", "金", "白"],
				},
				{
					name: "内存",
					item: ["16G", "32G"],
				},
			],
			inputVisible: false,
			inputValue: "",
			itemList: [
				{
					specificationname: "",
					specificationvalue: [],
				},
			],
			inpurIndex: 0,
			mapList: [],
			dialogImageUrl: '',
			dialogVisible: false
		};
	},
	methods: {
		// 保存
		onSave(){
			console.log("zzz",this.itemList,this.mapList)
		},
		// 添加
		addValue() {
			let itList = {
				specificationname: "",
				specificationvalue: [],
			};
			this.itemList.push(itList);
		},
		// 清空
		deleteValue() {
			this.itemList = [
				{
					specificationname: "",
					specificationvalue: [],
				},
			];
			this.mapList = []
		},
		// 聚焦判断是哪个数据
		focusConfirm(index) {
			this.inpurIndex = index;
		},
		// 删除
		handleClose(index, ins) {
			let skuList = []
			this.itemList[index].specificationvalue.splice(ins, 1);
			for (var { specificationvalue } of this.itemList) {
				if(specificationvalue.length){
					skuList.push(specificationvalue)
				}
			}
			var att = this.composeTableData(skuList)
			this.mapList = att
			if(skuList.length == 0){
				this.mapList = []
			}
		},

		showInput(e) {
			this.inpurIndex = e;
			this.inputVisible = true;
		},
		// 
		handleInputConfirm(e) {
			let skuList = []
			
			let inputValue = this.inputValue;
			if (inputValue) {
				this.itemList[this.inpurIndex].specificationvalue.push({
					value: inputValue,
				});
				for (var { specificationvalue } of this.itemList) {
					skuList.push(specificationvalue)
				}
				var attList = this.composeTableData(skuList)
				// console.log("dd",attList)
				this.mapList = attList
			}
			this.inputVisible = false;
			this.inputValue = "";
		},
		// 排列组合
		cartesianProductOf() {
			return Array.prototype.reduce.call(arguments, function (a, b) {
				const result = []  // 存储拼接的结果
				a.forEach(item_a => {
					b.forEach(item_b => {
						result.push(item_a.concat(item_b))
					})
				})
				return result
			}, [[]])
		},
		// 获取组合好的sku规格数据
		composeTableData(sku_list) {
			const arr = this.cartesianProductOf(...sku_list)
			console.log("arr",arr,this.mapList)
			return arr.map((item,index) => {
				return {
					sku: item,  // 组合好的规格[{...},{...}]
					oprice: '', // 销售价
					cprice: '', // 成本价
					stock: '', // 库存
					img:'', //图片
				}
			})
		},
		handleRemove(file, fileList) {
			console.log(file, fileList);
		},
		handlePictureCardPreview(file) {
			console.log(file)
			this.dialogImageUrl = file.url;
			this.dialogVisible = true;
		}
	},
};
</script>
<style scoped >
.border-box {
	width: 80%;
	/* height: 500px; */
	box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
	margin: auto;
	padding: 30px;
}

.border {
	display: flex;
}

.border-guige {
	width: 100%;
	border-radius: 2px;
	border: 1px solid rgb(227, 223, 223);
	margin-left: 10px;
	padding: 20px;
}

.flex-guige {
	display: flex;
}

.name {
	width: 80px;
}

.width-input {
	width: 30%;
	margin-left: 20px;
}

.width-tag {
	margin-left: 20px;
}

.el-tag+.el-tag {
	margin-left: 10px;
}

.button-new-tag {
	height: 32px;
	line-height: 30px;
	padding-top: 0;
	padding-bottom: 0;
	margin-left: 5px;
}

.input-new-tag {
	width: 90px;
	margin-left: 10px;
	vertical-align: bottom;
}

.avatar-uploader .el-upload {
	border: 1px dashed #846767;
	border-radius: 6px;
	cursor: pointer;
	position: relative;
	overflow: hidden;
}

.avatar-uploader .el-upload:hover {
	border-color: #409EFF;
}

.avatar-uploader-icon {
	font-size: 28px;
	color: #8c939d;
	width: 178px;
	height: 178px;
	line-height: 178px;
	text-align: center;
}

.avatar {
	width: 178px;
	height: 178px;
	display: block;
}
</style>

uniapp 小程序代码 版本1

<template>
	<view class="box">
		<view class="money">{{originalPrice}}<text>{{currentPrice}}</text></view>
		<view class="flex-item">
			<view v-for="(item,index) in skuName" :key="index">
				<view class="title">{{item.specificationname}}:</view>
				<view class="f-v">
					<view @tap="activeSku(index,ins)" :class="el.type == true?'active_sku_color':'active_sku'" 
					v-for="(el,ins) in item.specificationvalue" :key="ins">{{el.value}}</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default{
		data(){
			return{
				skuName:[],
				//后端返回数据
				skuList:[{originalPrice:299,currentPrice:199,inventory:100,img:'',sku:[{value:'黑色'},{value:'大'}]},
				{originalPrice:399,currentPrice:8899,inventory:100,img:'',sku:[{value:'绿色'},{value:'大'}]},
				{originalPrice:499,currentPrice:9999,inventory:100,img:'',sku:[{value:'黑色'},{value:'小'}]},
				{originalPrice:599,currentPrice:4499,inventory:100,img:'',sku:[{value:'绿色'},{value:'小'}]}],
				activeIndex:0, //规格
				originalPrice:'',//现价
				currentPrice:'',//原价
			}
		},
		onLoad() {
			this.onSaveSkuList()
		},
		methods:{
			onSaveSkuList(){
				//后端返回数据skuName 
				this.skuName = [
					{specificationname:'颜色',specificationvalue:[{value:'黑色'},{value:'绿色'}]},
					{specificationname:'型号',specificationvalue:[{value:'大'},{value:'小'}]}
				],
				this.skuName.forEach((el,index)=>{
					el.specificationvalue.forEach((item,ins)=>{
						this.skuName[index].specificationvalue[0].type = true
					})
				})
				this.originalPrice = this.skuList[0].originalPrice
				this.currentPrice = this.skuList[0].currentPrice
			},
			activeSku(i,is){
				this.skuName[i].specificationvalue.forEach((item,ins)=>{
					this.$set(this.skuName[i].specificationvalue[ins],'type',false)
				})
				this.$set(this.skuName[i].specificationvalue[is],'type',true)
				let list = []
				this.skuName.forEach((item,ins)=>{
					item.specificationvalue.forEach((el,index)=>{
						if(el.type == true){
							list.push({value:el.value})
						}
					})
				})
				this.skuList.forEach((el,index)=>{
					if(JSON.stringify(list) == JSON.stringify(el.sku)){
						this.originalPrice = el.originalPrice
						this.currentPrice = el.currentPrice
					}
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	.money{
		display: flex;
		align-items: center;
		color: red;
		margin-left: 30rpx;
		margin-top: 30rpx;
		text{
			color: #999;
		}
	}
	.flex-item{
		width: 690rpx;
		margin: auto;
		margin-top: 40rpx;
		.title{
			font-size: 28rpx;
			font-weight: bold;
			margin: 20rpx 0rpx 20rpx 0rpx;
		}
		.f-v{
			display: flex;
			align-items: center;
			flex-wrap: wrap;
			.active_sku{
				border: 1rpx solid #999;
				padding: 3rpx 10rpx 3rpx 10rpx;
				font-size: 24rpx;
				margin-right: 10rpx;
				border-radius: 5rpx;
			}
			.active_sku_color{
				border: 1rpx solid #990002;
				padding: 3rpx 10rpx 3rpx 10rpx;
				font-size: 24rpx;
				margin-right: 10rpx;
				border-radius: 5rpx;
				color: #990002;
			}
		}
	}
	
	
</style>

uniapp 小程序代码 版本2

<template>
	<view class="content">
		<view class="box">
				<view class="money" v-if="inventory != 0">当前价格:¥{{originalPrice}}<text> -- 原价:¥{{currentPrice}}</text></view>
				<view v-else>库存为0,价格范围:¥{{originalPrice}} ----{{currentPrice}}</view>
				<view class="flex-item">
					<view class="title" v-if="inventory != 0">库存:{{inventory}}</view>
					<view v-for="(item,index) in skuName" :key="index">
						<view class="title">{{item.specificationname}}:</view>
						<view class="f-v">
							<view @tap="activeSku(index,ins,el)" :class="el.type == true?'active_sku_color':el.type == 'DOG'?'wsku':'active_sku'" 
							v-for="(el,ins) in item.specificationvalue" :key="ins">{{el.value}}</view>
						</view>
					</view>
				</view>
			</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				skuName:[],
				// 后端返数据
				skuList:[
				{originalPrice:299,currentPrice:199,inventory:10,img:'',sku:[{value:'黑色'},{value:'大'},{value:'16G'}]},
				{originalPrice:299,currentPrice:199,inventory:10,img:'',sku:[{value:'黑色'},{value:'大'},{value:'64G'}]},
				{originalPrice:499,currentPrice:9999,inventory:9,img:'',sku:[{value:'黑色'},{value:'小'},{value:'16G'}]},
				{originalPrice:499,currentPrice:9999,inventory:9,img:'',sku:[{value:'黑色'},{value:'小'},{value:'64G'}]},
				{originalPrice:499,currentPrice:9999,inventory:9,img:'',sku:[{value:'黑色'},{value:'中'},{value:'16G'}]},
				{originalPrice:499,currentPrice:9999,inventory:9,img:'',sku:[{value:'黑色'},{value:'中'},{value:'64G'}]},
				
				{originalPrice:399,currentPrice:8899,inventory:1,img:'',sku:[{value:'绿色'},{value:'大'},{value:'16G'}]},
				{originalPrice:399,currentPrice:8899,inventory:0,img:'',sku:[{value:'绿色'},{value:'大'},{value:'64G'}]},
				{originalPrice:599,currentPrice:4499,inventory:66,img:'',sku:[{value:'绿色'},{value:'小'},{value:'16G'}]},
				{originalPrice:599,currentPrice:4499,inventory:66,img:'',sku:[{value:'绿色'},{value:'小'},{value:'64G'}]},
				{originalPrice:599,currentPrice:4499,inventory:66,img:'',sku:[{value:'绿色'},{value:'中'},{value:'16G'}]},
				{originalPrice:599,currentPrice:4499,inventory:66,img:'',sku:[{value:'绿色'},{value:'中'},{value:'64G'}]},
				
				{originalPrice:55,currentPrice:66,inventory:4,img:'',sku:[{value:'灰色'},{value:'小'},{value:'16G'}]},
				{originalPrice:55,currentPrice:66,inventory:3,img:'',sku:[{value:'灰色'},{value:'小'},{value:'64G'}]},
				{originalPrice:55,currentPrice:76,inventory:56,img:'',sku:[{value:'灰色'},{value:'大'},{value:'16G'}]},
				{originalPrice:55,currentPrice:76,inventory:56,img:'',sku:[{value:'灰色'},{value:'大'},{value:'64G'}]},
				{originalPrice:55,currentPrice:76,inventory:56,img:'',sku:[{value:'灰色'},{value:'中'},{value:'16G'}]},
				{originalPrice:55,currentPrice:76,inventory:56,img:'',sku:[{value:'灰色'},{value:'中'},{value:'64G'}]},
				
				
				{originalPrice:55,currentPrice:66,inventory:9,img:'',sku:[{value:'红色'},{value:'小'},{value:'16G'}]},
				{originalPrice:55,currentPrice:66,inventory:999,img:'',sku:[{value:'红色'},{value:'小'},{value:'64G'}]},
				{originalPrice:55,currentPrice:66,inventory:0,img:'',sku:[{value:'红色'},{value:'中'},{value:'16G'}]},
				{originalPrice:55,currentPrice:66,inventory:8,img:'',sku:[{value:'红色'},{value:'中'},{value:'64G'}]},
				{originalPrice:55,currentPrice:76,inventory:9,img:'',sku:[{value:'红色'},{value:'大'},{value:'16G'}]},
				{originalPrice:55,currentPrice:76,inventory:56,img:'',sku:[{value:'红色'},{value:'大'},{value:'64G'}]}],
				
				activeIndex:0,
				originalPrice:'',
				currentPrice:'',
				inventory:0,//库存
				// 后端返回数据
				skuName : [
					{specificationname:'颜色',specificationvalue:[{value:'黑色'},{value:'绿色'},{value:'灰色'},{value:'红色'},]},
					{specificationname:'型号',specificationvalue:[{value:'大'},{value:'小'},{value:'中'}]},
					{specificationname:'内存',specificationvalue:[{value:'16G'},{value:'64G'}]}
				],
			}
		},
		onLoad() {
			this.getPice()
		},
		methods: {
			getPice(){
				// 获取最大价格
				const maxObj = this.getMaxValue(this.skuList, 'currentPrice');
				// 最小价格
				const minObj = this.getMinValue(this.skuList, 'originalPrice');
				this.currentPrice = maxObj.currentPrice
				this.originalPrice = minObj.originalPrice
			},
			getMaxValue(arr, prop) {
			  const max = Math.max(...arr.map(item => item[prop]));
			  return arr.find(item => item[prop] === max);
			},
			getMinValue(arr, prop) {
			  const min = Math.min(...arr.map(item => item[prop]));
			  return arr.find(item => item[prop] === min);
			},
			// 比较对象是否相等
			shallowEqual(obj1, obj2) {
			  if (obj1 === obj2) return true;
			  if (!obj1 || !obj2) return false;
			  if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;
			  const keys1 = Object.keys(obj1);
			  const keys2 = Object.keys(obj2);
			  if (keys1.length !== keys2.length) return false;
			  for (let key of keys1) {
			    if (obj1[key] !== obj2[key]) return false;
			  }
			  return true;
			},
			activeSku(i,is,b){
				if(b.type == 'DOG'){
					return
				}
				if(this.skuName[i].specificationvalue[is].type == true){
					this.$set(this.skuName[i].specificationvalue[is],'type',false)
					// 取消选中,清空价格
					this.inventory = 0
					this.getPice()
				}else{
					this.$set(this.skuName[i].specificationvalue[is],'type',true)
					this.skuName[i].specificationvalue.forEach((item,ins)=>{
						if(ins != is){
							this.$set(this.skuName[i].specificationvalue[ins],'type',false)
						}
					})
				}
				let list = []
				this.skuName.forEach((item,ins)=>{
					item.specificationvalue.forEach((el,index)=>{
						if(el.type == true){
							list.push({value:el.value})
						}
					})
				})
				
				let vsku = []
				let simplesku = this.skuList.filter(item => item.inventory == 0)
				simplesku.forEach((el,l)=>{
					el.sku.forEach((m,k)=>{
						list.forEach((p,j)=>{
							if(this.shallowEqual(p,JSON.parse(JSON.stringify(el.sku[i])))){ //找出符合条件的规格
								vsku.push(...el.sku)
							}
						})
					})
				})
				// 去重筛选的数组
				let result = Array.from(new Set(vsku.map(item => JSON.stringify(item)))).map(item => JSON.parse(item));
				// 清除当前层的索引
				result.splice(i,1)
				let num = 0
				this.skuName.forEach((el,index)=>{
					el.specificationvalue.forEach((s,k)=>{
						if(s.type == 'DOG'){
							s.type = false
						}
						if(result.length){
							result.forEach((ei,z)=>{
								if(ei.value == s.value ){
									this.$set(this.skuName[index].specificationvalue[k],'type','DOG')
								}
							})
						}else{
							if(this.skuName[index].specificationvalue[k].type == 'DOG'){
								this.$set(this.skuName[index].specificationvalue[k],'type',false)
							}
						}
						if(s.type == true){
							num += 1
						}
					})
				})
				this.skuList.forEach((el,index)=>{
					if(JSON.stringify(list) == JSON.stringify(el.sku)){
						this.originalPrice = el.originalPrice
						this.currentPrice = el.currentPrice
						this.inventory = el.inventory //库存
					}
				})
				if(num != this.skuName.length){ //未选完整规格清空
					this.inventory = 0
					this.getPice()
				}
			},
			
		}
	}
</script>

<style lang="scss">
	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
	.money{
			display: flex;
			align-items: center;
			color: red;
			// margin-left: 30rpx;
			margin-top: 30rpx;
			text{
				color: #999;
			}
		}
		.flex-item{
			width: 690rpx;
			margin: auto;
			margin-top: 30rpx;
			.title{
				font-size: 28rpx;
				font-weight: bold;
				margin: 20rpx 0rpx 20rpx 0rpx;
			}
			.f-v{
				display: flex;
				align-items: center;
				flex-wrap: wrap;
				.active_sku{
					border: 1rpx solid #999;
					padding: 3rpx 10rpx 3rpx 10rpx;
					font-size: 24rpx;
					margin-right: 10rpx;
					border-radius: 5rpx;
				}
				.active_sku_color{
					border: 1rpx solid #990002;
					padding: 3rpx 10rpx 3rpx 10rpx;
					font-size: 24rpx;
					margin-right: 10rpx;
					border-radius: 5rpx;
					color: #990002;
				}
				.cucunSku{
					border: 1rpx solid #990002;
					padding: 3rpx 10rpx 3rpx 10rpx;
					font-size: 24rpx;
					margin-right: 10rpx;
					border-radius: 5rpx;
					color: #990002;
				}
				.wsku{
					border: 1rpx solid #131399;
					padding: 3rpx 10rpx 3rpx 10rpx;
					font-size: 24rpx;
					margin-right: 10rpx;
					border-radius: 5rpx;
					color: #464a99;
					background-color: #131399;
				}
			}
		}
		
</style>

更多推荐