uni-app 商城 的sku算法(vue)
1,之前一种用的history 路由模式 , 小程序调试工具 和pc 微信端 可以 ,但是 安卓 和ios 死活不行 ,后来将 history模式改为 hash模式手机config ok 可以支持自定义分享 , 但是分享的url 会加#号, 微信会截取#之前的内容, 导致 分享后跳到首页...
·
1,实际效果图
2,后台传的数据
3,页面代码
<view class="popup spec" :class="specClass" @touchmove.stop.prevent="stopPrevent" @tap="hideSpec">
<view class="popup spec" :class="specClass" @touchmove.stop.prevent="stopPrevent" @tap="hideSpec">
<!-- 遮罩层 -->
<view class="mask"></view>
<view class="layer attr-content" @click.stop="stopPrevent">
<view class="a-t">
<image :src="this.Pic" onerror="https://gd3.alicdn.com/imgextra/i3/0/O1CN01IiyFQI1UGShoFKt1O_!!0-item_pic.jpg_400x400.jpg">
</image>
<view class="right">
<text class="price">¥{{price}}</text>
<text class="stock">库存{{ Stock }}件
</text>
<view class="selected">
已选:
<text class="selected-text" >{{ message }}</text>
</view>
</view>
</view>
<!-- sku算法 -->
<view>
<dl v-for="(item, key) in list.result" :key="key" class="attr-list" v-bind:class="{hl: highKeys[key]}">
<dt> {{key}}</dt>
<dd class="item-list">
<text
class="tit"
v-for="value in item"
:key="value.id"
@click="handleActive(key, value)"
v-bind:class="{selected: value.active, disabled: !value.active && value.disabled}"
> {{ value.name }}
</text>
</dd>
</dl>
</view>
<view class="selectCount">
<view class="row">
<view class="left">数量</view>
<view class="right"><uni-number-box class="count" :min="1" value="1" :max="5" @eventChange="numberChange"></uni-number-box></view>
</view>
</view>
<button class="btn bottom" @tap="complete()">完成</button>
</view>
</view>
js部分
export default {
components: {
},
data() {
return {
// sku算法
data: [],
Stock:"",
SkuID: "",
Price:"",
Pic:"",
skuName: "SkuID",
skuName1: "Price",
skuName2: "Pic",
skuName3:"Stock",
// 属性名称信息
keys: [],
// 数据集合{list.result list.items}
list: {},
// 分隔符
spliter: '\u2299',
result: {},
message: "",
highKeys: {},
}
}
onLoad: function(option) {
uni.request({
url: serverUrl + '/MallDataLoad.ashx?action=PromDetail',
method: 'GET',
data: {
PromDID: ID,
StoreID: this.StoreID,
tk: this.wxToken
},
success: (res) => {
console.log("团购返回数据",res.data);
// 获取真实数据之前,务必判断状态是否为200
if (res.statusCode == 200) {
//判断是否重复参加活动
PromFlag = res.data.PromFlag;
this.PromFlag = PromFlag;
if(PromFlag == 1){
this.$api.msg(res.data.PromFlagMsg);
this.spellFlag = true;
this.joinFlag = false;
}if(PromFlag == 2){
this.$api.msg(res.data.PromFlagMsg);
this.spellFlag = true;
this.joinFlag = true;
}if(PromFlag == 0){
this.$api.msg(res.data.PromFlagMsg);
this.spellFlag = false;
this.joinFlag = false;
}
var imgList = [];
goodsInfo = res.data;
this.goodsInfo = goodsInfo;
imgList = res.data.PromotionImgItem;
this.imgList = imgList;
//图文详情
desc = res.data.Describe;
this.desc = desc;
//发起拼单信息数组
Promotion1 = res.data.PromotionJoinModels;
this.Promotion1 = Promotion1;
console.log("Promotion1拼单活动数组",Promotion1);
specList = res.data.SpecsItems;
this.data = res.data.SKU;//获取后台sku数据
console.log("this.data",this.data);
this.initData();
}
}
});
}
methods: {
//sku算法
powerset(arr) {
let ps = [[]];
for (let i = 0; i < arr.length; i++) {
for (let j = 0, len = ps.length; j < len; j++) {
ps.push(ps[j].concat(arr[i]));
}
}
return ps;
},
/**
* 初始化数据
* @return
*/
initData() {
this.result = {};
this.keys = this.getAllKeys();//arrKeys["颜色", "尺码", "型号"]
for (let i = 0; i < this.keys.length; i ++) {
this.highKeys[this.keys[i]] = false;//所有的都为false
}
this.list = this.combineAttr(this.data, this.keys);
console.log("this.list",this.list);
this.initSeleted(this.SkuID);
this.initSeleted(this.Pic);
this.initSeleted(this.Price);
this.initSeleted(this.Stock);
this.buildResult(this.list.items)
this.updateStatus(this.getSelectedItem());
this.showResult();
},
/**
* 正常属性点击
*/
handleNormalClick(key, value) {
for (let i in this.list.result[key]) {
if (i != value.name) {
this.list.result[key][i].active = false;
} else {
this.list.result[key][i].active = true;
}
}
},
/**
* 无效属性点击
*/
handleDisableClick(key, value) {
this.list.result[key][value.name]["disabled"] = false;
// 清空高亮行的已选属性状态(因为更新的时候默认会跳过已选状态)
for (let i in this.list.result) {
if (i != key) {
for (let x in this.list.result[i]) {
this.list.result[i][x].active = false;
}
}
}
this.updateStatus(this.getSelectedItem());
},
/**
* 高亮行
*/
highAttributes: function() {
for (let key in this.list.result) {
this.highKeys[key] = true;
for (let attr in this.list.result[key]) {
if (this.list.result[key][attr].active === true) {
this.highKeys[key] = false;
break;
}
}
}
},
/**
* 点击事件处理
* @param key 点击的行
* @param value 点击的按钮的数据
*/
handleActive: function(key, value) {
if (value.active == true) {
return false;
}
this.handleNormalClick(key, value);
if (value.disabled === true) {
this.handleDisableClick(key, value);
}
this.updateStatus(this.getSelectedItem());
this.highAttributes();
this.showResult();
},
/**
* 计算属性
* @param {[type]} data [description]
* @param {[type]} keys [description]
* @return {[type]} [description]
*/
combineAttr(data, keys) {
let allKeys = []
let result = {}
for (let i = 0; i < data.length; i++) {
let item = data[i]
let values = []
for (let j = 0; j < keys.length; j++) {
let key = keys[j]
if (!result[key]) {
result[key] = {};
}
if (!result[key][item[key]]) {
result[key][item[key]] = {"name": item[key], "active": false, "disabled": true};
}
values.push(item[key]);
}
allKeys.push({
path: values.join(this.spliter),
sku: item['SkuID'],
price:item['Price'],
Pic:item['Pic'],
Stock:item['Stock']
});
}
return {
result: result,
items: allKeys
}
},
/**
* 获取所有属性
* @return {[type]} [description]
*/
getAllKeys() {
let arrKeys = [];
for (let attribute in this.data[0]) {
if (!this.data[0].hasOwnProperty(attribute)) {
continue;
}
if (attribute !== this.skuName && attribute !== this.skuName1 && attribute !== this.skuName2 && attribute !== this.skuName3) {
arrKeys.push(attribute);
}
}
console.log("arrKeys 所有属性",arrKeys)
return arrKeys;
},
getAttruites(arr) {
let result = []
for (let i = 0; i < arr.length; i++) {
result.push(arr[i].path)
}
return result
},
/**
* 生成所有子集是否可选、库存状态 map
*/
buildResult(items) {
let allKeys = this.getAttruites(items)
//价格 , 库存, 图片 赋值
for (let i = 0; i < allKeys.length; i++) {
let curr = allKeys[i];
let sku = items[i].sku;
let Pic = items[i].Pic;
let price =items[i].price;
let Stock = items[i].Stock;
let values = curr.split(this.spliter);
let allSets = this.powerset(values);
// 每个组合的子集
for (let j = 0; j < allSets.length; j++) {
let set = allSets[j]
let key = set.join(this.spliter)
if (this.result[key]) {
// this.result[key].skus.push();
} else {
this.result[key] = {
skus: [sku,Pic,price,Stock],
}
}
}
}
},
/**
* 获取选中的信息
* @return Array
*/
getSelectedItem() {
let result = [];
for (let attr in this.list.result) {
let attributeName = '';
for (let attribute in this.list.result[attr]) {
if (this.list.result[attr][attribute].active === true) {
attributeName = attribute;
}
}
result.push(attributeName);
}
return result
},
/**
* 更新所有属性状态
*/
updateStatus(selected) {
for (let i = 0; i < this.keys.length; i++) {
let key = this.keys[i],
data = this.list.result[key],
hasActive = !!selected[i],
copy = selected.slice();
for (let j in data) {
let item = data[j]["name"];
if (selected[i] == item) {
continue
}
copy[i] = item;
let curr = this.trimSpliter(copy.join(this.spliter), this.spliter);
this.list.result[key][j]["disabled"] = this.result[curr] ? false : true;
}
}
},
trimSpliter(str, spliter) {
// ⊙abc⊙ => abc
// ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
let reLeft = new RegExp('^' + spliter + '+', 'g');
let reRight = new RegExp(spliter + '+$', 'g');
let reSpliter = new RegExp(spliter + '+', 'g');
return str.replace(reLeft, '')
.replace(reRight, '')
.replace(reSpliter, spliter)
},
/**
* 初始化选中
* @param mixed|Int|String SkuID 需要选中的SkuID
* @return {[type]} [description]
*/
initSeleted(a) {
for (let i in this.data) {
if (this.data[i][this.skuName] == a) {
for (let x in this.data[i]) {
if (x !== this.skuName && x !== this.skuName1 && x !== this.skuName2 && x !== this.skuName3) {
this.list.result[x][this.data[i][x]].active = true;
}
}
break;
}
}
},
/**
* 显示选中的信息
* @return
*/
showResult() {
let result = this.getSelectedItem()
let s = []
for (let i = 0; i < result.length; i++) {
let item = result[i];
if (!!item) {
s.push(item)
}
}
if (s.length == this.keys.length) {
let curr = this.result[s.join(this.spliter)];
if (curr) {
this.SkuID = curr.skus[0];
this.Pic =curr.skus[1];
this.price = curr.skus[2];
this.Stock = curr.skus[3];
}
this.message = s.join('-');
}
},
created() {
this.getTextareaData();
}
}
css样式(把整个页面的都放上了)
<style lang="scss">
page {
background: $page-color-base;
padding-bottom: 160upx;
}
.disabled {
color:#ccc;
border: 1px dashed #ccc;
}
.active {
background: #fbebee;
color: $uni-color-primary;
}
.top-but {
margin: 10px;
}
.icon-you {
font-size: $font-base + 2upx;
color: #888;
}
.carousel {
height: 600upx;
position: relative;
swiper {
height: 100%;
}
.image-wrapper {
width: 100%;
height: 100%;
}
.swiper-item {
display: flex;
justify-content: center;
align-content: center;
height: 600upx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
}
/* 标题简介 */
.introduce-section {
background: #fff;
padding: 20upx 30upx;
.title {
font-size: 32upx;
color: $font-color-dark;
height: 50upx;
line-height: 50upx;
}
.price-box {
display: flex;
align-items: baseline;
height: 64upx;
padding: 10upx 0;
font-size: 26upx;
color: $uni-color-primary;
}
.price {
font-size: $font-lg + 2upx;
}
.m-price {
margin: 0 12upx;
color: $font-color-light;
text-decoration: line-through;
}
.coupon-tip {
align-items: center;
padding: 4upx 10upx;
background: $uni-color-primary;
font-size: $font-sm;
color: #fff;
border-radius: 6upx;
line-height: 1;
transform: translateY(-4upx);
}
.bot-row {
display: flex;
align-items: center;
height: 50upx;
font-size: $font-sm;
color: $font-color-light;
text {
flex: 1;
}
}
}
/* 分享 */
.share-section {
display: flex;
align-items: center;
color: $font-color-base;
background: linear-gradient(left, #fdf5f6, #fbebf6);
padding: 12upx 30upx;
.share-icon {
display: flex;
align-items: center;
width: 70upx;
height: 30upx;
line-height: 1;
border: 1px solid $uni-color-primary;
border-radius: 4upx;
position: relative;
overflow: hidden;
font-size: 22upx;
color: $uni-color-primary;
&:after {
content: '';
width: 50upx;
height: 50upx;
border-radius: 50%;
left: -20upx;
top: -12upx;
position: absolute;
background: $uni-color-primary;
}
}
.icon-xingxing {
position: relative;
z-index: 1;
font-size: 24upx;
margin-left: 2upx;
margin-right: 10upx;
color: #fff;
line-height: 1;
}
.tit {
font-size: $font-base;
margin-left: 10upx;
}
.icon-bangzhu1 {
padding: 10upx;
font-size: 30upx;
line-height: 1;
}
.share-btn {
flex: 1;
text-align: right;
font-size: $font-sm;
color: $uni-color-primary;
}
.icon-you {
font-size: $font-sm;
margin-left: 4upx;
color: $uni-color-primary;
}
}
.c-list {
font-size: $font-sm + 2upx;
color: $font-color-base;
background: #fff;
.c-row {
display: flex;
align-items: center;
padding: 20upx 30upx;
position: relative;
.user-info-box {
height: 180upx;
align-items: center;
display: flex;
position: relative;
z-index: 1;
.portrait {
width: 100upx;
height: 100upx;
border: 5upx solid #fff;
border-radius: 50%;
margin-right: 20upx;
}
.username {
margin-left: 30upx;
font-size: $font-base;
color: $font-color-light;
}
}
}
.tit {
width: 140upx;
}
.con {
flex: 1;
color: $font-color-dark;
.selected-text {
margin-right: 10upx;
}
}
.bz-list {
height: 40upx;
font-size: $font-sm + 2upx;
color: $font-color-dark;
text {
display: inline-block;
margin-right: 30upx;
}
}
.con-list {
flex: 1;
display: flex;
flex-direction: column;
color: $font-color-dark;
line-height: 40upx;
.con-row {
flex: 1;
display: flex;
justify-content: space-between;
flex-direction: row;
}
.coupon-tip {
margin: 0 10upx;
align-items: center;
padding: 4upx 10upx;
background: $uni-color-primary;
font-size: $font-sm;
color: #fff;
border-radius: 6upx;
line-height: 1;
transform: translateY(-4upx);
}
.pro-box {
display: flex;
align-items: center;
font-size: $font-sm;
color: $font-base;
}
.progress-box {
line-height: 40upx;
flex: 1;
border-radius: 10px;
overflow: hidden;
margin-right: 8upx;
}
.btn {
text-align: center;
height: 40upx;
line-height: 40upx;
border-radius: 10upx;
background: $uni-color-primary;
font-size: $font-sm;
margin-left: 10upx;
}
}
.red {
color: $uni-color-primary;
}
}
.g-swiper {
height: 180upx;
}
/* 评价 */
.eva-section {
display: flex;
flex-direction: column;
padding: 20upx 30upx;
background: #fff;
margin-top: 16upx;
.e-header {
display: flex;
align-items: center;
height: 70upx;
font-size: $font-sm + 2upx;
color: $font-color-light;
.tit {
font-size: $font-base + 2upx;
color: $font-color-dark;
margin-right: 4upx;
}
.tip {
flex: 1;
text-align: right;
}
.icon-you {
margin-left: 10upx;
}
}
}
.eva-box {
display: flex;
padding: 20upx 0;
.portrait {
flex-shrink: 0;
width: 80upx;
height: 80upx;
border-radius: 100px;
}
.right {
flex: 1;
display: flex;
flex-direction: column;
font-size: $font-base;
color: $font-color-base;
padding-left: 26upx;
.con {
font-size: $font-base;
color: $font-color-dark;
padding: 20upx 0;
}
.bot {
display: flex;
justify-content: space-between;
font-size: $font-sm;
color: $font-color-light;
}
}
}
.oper {
width: 140upx;
display: flex;
flex-direction: row;
justify-content: center;
color: #ffac30;
}
.praise-ico {
width: 38upx;
height: 38upx;
margin-left: 20upx;
margin-right: 10upx;
}
.praise-me {
}
.animation-opacity {
font-weight: bold;
opacity: 0;
}
/* 详情 */
.detail-desc {
background: #fff;
margin-top: 16upx;
.d-header {
display: flex;
justify-content: center;
align-items: center;
height: 80upx;
font-size: $font-base + 2upx;
color: $font-color-dark;
position: relative;
text {
padding: 0 20upx;
background: #fff;
position: relative;
z-index: 1;
}
&:after {
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%);
width: 300upx;
height: 0;
content: '';
border-bottom: 1px solid #ccc;
}
}
}
/* 规格弹窗 */
.attr-content {
padding: 0 30upx;
.bottom {
/* position: absolute; */
left: 50%;
transform: translate(-50%, 0%);
bottom: 10upx;
width: 100%;
}
.a-t {
display: flex;
image {
width: 170upx;
height: 170upx;
flex-shrink: 0;
margin-top: -40upx;
border-radius: 8upx;
}
.right {
display: flex;
flex-direction: column;
padding-left: 24upx;
font-size: $font-sm + 2upx;
color: $font-color-base;
line-height: 42upx;
.price {
font-size: $font-lg;
color: $uni-color-primary;
margin-bottom: 10upx;
}
.selected-text {
margin-right: 10upx;
}
}
}
.attr-list {
display: flex;
flex-direction: column;
font-size: $font-base + 2upx;
color: $font-color-base;
padding-top: 30upx;
}
.selectCount {
.row {
padding:10upx;
margin: 20upx 0;
display: flex;
justify-content: space-between;
.left {
color: #606266;
font-size: $font-base + 2upx;
}
.right {
color: #999;
}
}
}
.item-list {
padding: 20upx 0 0;
display: flex;
flex-wrap: wrap;
text {
display: flex;
align-items: center;
justify-content: center;
background: #eee;
margin-right: 20upx;
margin-bottom: 20upx;
border-radius: 100upx;
min-width: 60upx;
height: 60upx;
padding: 0 20upx;
font-size: $font-base;
}
.selected {
background: #fbebee;
color: $uni-color-primary;
}
.disabled {
color:#ccc;
border: 1px dashed #ccc;
}
}
}
/* 弹出层选择数量 */
.choiceNum {
margin-top: 30upx;
border-top: solid 1upx #aaa;
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 20upx;
.text {
font-size: 30upx;
}
.number {
display: flex;
justify-content: center;
align-items: center;
.input {
width: 80upx;
margin: 0 10upx;
background-color: #f3f3f3;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
input {
width: 80upx;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-size: 26upx;
}
}
.sub,
.add {
width: 60upx;
background-color: #ece4e6;
border-radius: 5upx;
.icon {
font-size: 30upx;
width: 60upx;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
/* 弹出层 */
.popup {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 99;
&.show {
display: block;
.mask {
animation: showPopup 0.2s linear both;
}
.layer {
animation: showLayer 0.2s linear both;
}
}
&.hide {
.mask {
animation: hidePopup 0.2s linear both;
}
.layer {
animation: hideLayer 0.2s linear both;
}
}
&.none {
display: none;
}
.mask {
position: fixed;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
background-color: rgba(0, 0, 0, 0.4);
}
.layer {
position: fixed;
z-index: 99;
bottom: 0;
width: 100%;
min-height: 60vh;
border-radius: 10upx 10upx 0 0;
background-color: #fff;
.btn {
height: 66upx;
line-height: 66upx;
border-radius: 18upx;
background: $uni-color-primary;
font-size: $font-sm;
color: #fff;
margin: 30upx auto 20upx;
}
}
@keyframes showPopup {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes hidePopup {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes showLayer {
0% {
transform: translateY(120%);
}
100% {
transform: translateY(0%);
}
}
@keyframes hideLayer {
0% {
transform: translateY(0);
}
100% {
transform: translateY(120%);
}
}
}
/* 底部操作菜单 */
.page-bottom {
position: fixed;
left: 30upx;
bottom: 30upx;
z-index: 95;
display: flex;
justify-content: center;
align-items: center;
width: 690upx;
height: 100upx;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 0 20upx 0 rgba(0, 0, 0, 0.5);
border-radius: 16upx;
.p-b-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: $font-sm;
color: $font-color-base;
width: 96upx;
height: 80upx;
.yticon {
font-size: 40upx;
line-height: 48upx;
color: $font-color-light;
}
&.active,
&.active .yticon {
color: $uni-color-primary;
}
.icon-fenxiang2 {
font-size: 42upx;
transform: translateY(-2upx);
}
.icon-shoucang {
font-size: 46upx;
}
}
.action-btn-group {
display: flex;
height: 76upx;
border-radius: 100px;
overflow: hidden;
box-shadow: 0 20upx 40upx -16upx #fa436a;
background: linear-gradient(to right, #ec93a6, #f50505);
margin-left: 20upx;
position: relative;
&:after {
content: '';
position: absolute;
top: 50%;
right: 50%;
transform: translateY(-50%);
height: 28upx;
width: 0;
border-right: 1px solid rgba(255, 255, 255, 0.5);
}
.action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 180upx;
height: 100%;
font-size: $font-base;
padding: 0;
border-radius: 0;
background: transparent;
}
}
}
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)