VUE similar to Taobao chooses multiple specifications of products (inventory judgment)

1. Component effect display

You can also visit the link to view the page effect...


Blind package component series:

 

VUE simple prompt box

VUE tree diagram (recursive implementation)

VUE multi-store shopping cart

 

 

 2. How to use

Introduce components:

import goodsspec from '../../../../components/ghGoodsSpec/ghGoodsSpec.vue'

Use in the appropriate area of ​​<template>

<goodsspec :goods="goods" :isShow="modalIsShow" @closeModal="closeModal"></goodsspec>

The component stipulates that the JSON of the product specification information and a Boolean value need to be passed from the parent component to control the display status of the specification selection pop-up box.

Commodity specification information JSON must conform to the component specification standard (the following is the JSON in the example, the inventory json, and the specification json):


modalIsShow:false,
goods: {
	defaultimg:'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3457897174,1250176029&fm=26&gp=0.jpg',
	"priceInfo": [{
			"SKU": "1_1_5_11",
			"stock": 888,
			"price": 15535400.00,
			"difference": "黑色;34;帆布鞋",
			goodsimg:'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3323728883,1529837998&fm=26&gp=0.jpg'
		}, {
			"SKU": "1_3_5_12",
			"stock": 99,
			"price": 100.00,
			"difference": "黑色;34;凉鞋",
			goodsimg:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1006940732,1295991734&fm=26&gp=0.jpg'
		}, {
			"SKU": "1_4_6_13",
			"stock": 150,
			"price": 10011.00,
			"difference": "粉色;36;运动鞋",
			goodsimg:'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1916398967,1152344977&fm=26&gp=0.jpg'
		},
		{
			"SKU": "1_3_5_12",
			"stock": 9999,
			"price": 100.00,
			"difference": "红色;35;凉鞋",
			goodsimg:'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2755143450,1175568520&fm=26&gp=0.jpg'
		}, {
			"SKU": "1_4_5_13",
			"stock": 100000,
			"price": 10088.00,
			"difference": "粉色;35;运动鞋",
			goodsimg:'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3305162035,1457776276&fm=26&gp=0.jpg'
		}
	],
	"SKUInfo": [{
		"name": "颜色",
		"sort": 1,
		"items": [{
				"name": "黑色",
				"value": 1,
				"sort": 1
			},
			{
				"name": "红色",
				"value": 3,
				"sort": 2
			},
			{
				"name": "粉色",
				"value": 4,
				"sort": 3
			}
		]
	}, {
		"name": "尺码",
		"sort": 2,
		"items": [{
				"name": "35",
				"value": 5,
				"sort": 1
			},
			{
				"name": "36",
				"value": 6,
				"sort": 2
			},
			{
				"name": "34",
				"value": 7,
				"sort": 3
			}
		]
	}, {
		"name": "分类",
		"sort": 4,
		"items": [{
				"name": "帆布鞋",
				"value": 11,
				"sort": 1
			},
			{
				"name": "凉鞋",
				"value": 12,
				"sort": 2
			},
			{
				"name": "运动鞋",
				"value": 13,
				"sort": 3
			}
		]
	}]
}

3. Code implementation

Implementation principle:

When you click the specifications button, the selected specifications are loaded into an array, and finally the combined specifications are substituted into the json of the product quantity to find.

<template>
	<div class="ui-shade" v-show="isShow"  @click="changisshow">
		<div class="modal_cont" :class="isShow ? 'silderout':''" @click.stop="changisshow()">
			<div class="page_modal" @click.stop>
				<div id="geuige">
					<div class="cose_modal" @click="changisshow()"><span>×</span></div>
					<div class="goods_intro flex-star">
						<img :src="defaultimg">
						<div class="goods_info">
							<div class="goods_price">{
   
   {price}}</div>
							<div class="kucun">库存<span>{
   
   {num}}</span>件</div>
							<div class="checkre flex-star">
								<span>已选:</span>
								<div>{
   
   {showAttr}}</div>
							</div>
						</div>
					</div>

					<div v-for="(item,itemindex) in goods.SKUInfo" class="chose_item">
						<p class="chose_item_tit">{
   
   {item.name}}</p>
						<div class="chose_item_cont flex-star">
							<div v-for="(attr,attrindex) in item.items" v-on:click="specificationBtn(attr.name,itemindex,attrindex)"
							 v-bind:class="[attr.isShow?'':'noneActive',subIndex[itemindex] == attrindex?'productActive':'']">
								{
   
   {attr.name}}
							</div>
						</div>
					</div>

					<div class="num_opt flex-between">
						<span>购买数量</span>
						<div class="numopt flex-star">
							<div class="add">-</div>
							<div>2</div>
							<div class="reduce">+</div>
						</div>
					</div>
					<div class="btn_cont flex-star">
						<input type="button" name="" id="" value="加入购物车" />
						<input type="button" name="" id="" value="马上抢" />
					</div>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				selectArr: [], //存放被选中的值
				showAttr: "",
				num: 0,
				shopItemInfo: {}, //存放要和选中的值进行匹配的数据
				subIndex: [], //是否选中 因为不确定是多规格还是单规格,所以这里定义数组来判断
				price: '', //选中规格的价钱
        defaultimg:''
			}
		},
		props:{
			isShow:{
				type:Boolean,
				default:false
			},
			goods:{
				type:Object,
				required:true
			}
		},
		created: function() {
			var self = this;
			for (var i in self.goods.priceInfo) {
				self.shopItemInfo[self.goods.priceInfo[i].difference] = self.goods.priceInfo[i]; //修改数据结构格式,改成键值对的方式,以方便和选中之后的值进行匹配
			}
      this.defaultimg = this.goods.defaultimg;
      console.log(this.defaultimg,66666);
			self.checkItem();
			// self.specificationBtn("黑色",0,0)
		},
		methods: {
			changisshow(e) {
				this.$emit("closeModal",false)
			},
			specificationBtn: function(item, n, index) {
				var self = this;

				console.info(self.selectArr[n] + "66666" + item)
				if (self.selectArr[n] != item) {
					self.selectArr[n] = item;
					self.subIndex[n] = index;

				} else {
					self.selectArr[n] = undefined;
					self.subIndex[n] = -1; //去掉选中的颜色
				}

				var showarr = self.selectArr;
				var tempTop = [];
				showarr.forEach((item, i, arr) => {
					if (item) {
						tempTop.push(item)
					}
				})

				self.showAttr = tempTop.join(";");
				self.checkItem();
				tempTop = []
			},
			checkItem: function() {
				var self = this;
				var option = self.goods.SKUInfo;
				var result = []; //定义数组存储被选中的值
				for (var i in option) {
					result[i] = self.selectArr[i] ? self.selectArr[i] : '';
				}
				console.log(result);

				if (self.shopItemInfo[result.join(";")]) {
					self.num = self.shopItemInfo[result.join(";")].stock;
					self.price = "¥" + (self.shopItemInfo[result.join(";")].price).toFixed(2);
          self.defaultimg = self.shopItemInfo[result.join(";")].goodsimg;
				} else {
					self.num = 0;
					self.price = "¥0.00";
          self.defaultimg = self.goods.defaultimg;
				}


				for (var i in option) {
					var last = result[i]; //把选中的值存放到字符串last去
					for (var k in option[i].items) {
						result[i] = option[i].items[k].name; //赋值,存在直接覆盖,不存在往里面添加name值
						option[i].items[k].isShow = self.isMay(result); //在数据里面添加字段isShow来判断是否可以选择
					}

					console.info(last)
					result[i] = last; //还原,目的是记录点下去那个值,避免下一次执行循环时避免被覆盖
				}
				self.$forceUpdate(); //重绘
			},
			isMay: function(result) {
				for (var i in result) {
					if (result[i] == '') {
						return true; //如果数组里有为空的值,那直接返回true
					}
				}
				if (this.shopItemInfo[result.join(";")]) { //匹配选中的数据的库存,若不为空返回true反之返回false
					return this.shopItemInfo[result.join(";")].stock == 0 ? false : true;
				}
			}
		}
	}
</script>

<style scoped="scopedss">
	.page_modal {
		width: 100%;
		background: linear-gradient(to right, #fff, #fff) 0 .2rem no-repeat;
		background-size: 100% auto;
		color: #222;
		position: absolute;
		bottom: 0;
	}

	.goods_intro {
		padding: 0 .25rem;
	}

	.goods_intro img {
		width: 2rem;
		height: 2rem;
		border: 3px solid #fff;
		border-radius: 4px;
		box-shadow: 0 0 6px rgba(0, 0, 0, .3);
	}

	.goods_info {
		margin-left: .15rem;
	}

	.goods_price {
		color: #feab27;
		font-size: .34rem;
	}

	.kucun {
		margin: .05rem 0;
	}

	.num_opt {
		width: calc(100% - .5rem);
		margin: 0 .25rem;
		padding: .25rem 0;
		border-bottom: 1px solid #eeeeee;
	}

	.numopt div {
		width: .7rem;
		height: .6rem;
		background: #f5f5f5;
		text-align: center;
		line-height: .6rem;
		color: #666;
	}

	.numopt div:nth-child(2) {
		margin: 0 .08rem;
		background: white;
		color: #333;
	}

	.chose_item {
		width: calc(100% - .5rem);
		margin: 0 .25rem;
		border-bottom: 1px solid #eeeeee;
		padding-top: .3rem;
	}

	.chose_item_cont {
		margin-top: .2rem;
	}

	.chose_item_cont div {
		padding: .12rem .24rem;
		background: #f6f4f5;
		border-radius: 5px;
		margin-bottom: .2rem;
	}

	.chose_item_cont div:nth-child(n + 2) {
		margin-left: .2rem;
	}

	.chose_item .chose_item_tit {
		font-size: .3rem;
		font-weight: bold;
	}

	.ui-shade {
		display: flex;
	}

	.silderout {
		display: block;
		bottom: 0;
		animation: silderout .25s;
	}

	.btn_cont input {
		height: .8rem;
		width: 50%;
		border: none;
		color: white;
	}

	.btn_cont input:nth-child(1) {
		background: #ff9e01;
		border-radius: .8rem 0 0 .8rem;
	}

	.btn_cont input:nth-child(2) {
		background: #ff6f00;
		border-radius: 0 .8rem .8rem 0;
	}

	.btn_cont {
		width: calc(100% - .5rem);
		margin: 0 .25rem;
		padding: .15rem 0;
	}

	.productActive {
		background: #feab27 !important;
		color: white;
	}

	.cose_modal {
		position: absolute;
		width: .4rem;
		top: .4rem;
		height: .4rem;

		border: 1px solid #615763;
		border-radius: 50%;
		right: .2rem;
		line-height: .34rem;
		text-align: center;
	}

	@keyframes silderout {
		from {
			bottom: -100vh;
		}

		to {
			bottom: 0;
		}
	}

	@keyframes silderin {
		from {
			bottom: vh;
		}

		to {
			bottom: -100vh;
		}
	}

	.modal_cont {
		position: absolute;
		height: 100vh;
		width: 100vw;
	}

	.noneActive {
		background-color: #ccc;
		opacity: 0.4;
		color: #000;
		pointer-events: none;
	}
</style>

The writing is not good, so please show me a lot.

Guess you like

Origin blog.csdn.net/m0_43599959/article/details/112300380