uniapp+vue2实现商品添加多规格交互

299 阅读3分钟

image.png

代码:

//utils/index.js

export const cartesianProduct = (arrays) => {
  function recursiveProduct(arrays, index, current) {
    if (index === arrays.length) {
      result.push({
        specification: current.slice(),
      });
      return;
    }

    for (let i = 0; i < arrays[index].length; i++) {
      current.push(arrays[index][i]);
      recursiveProduct(arrays, index + 1, current);
      current.pop();
    }
  }

  let result = [];
  recursiveProduct(arrays, 0, []);
  return result;
};

//page页面

<template>
  <view class="base-page-container container">
    <u-navbar
      autoBack
      placeholder
      title="多规格"
      :titleStyle="{ color: '#000', fontSize: '36rpx', fontWeight: 600 }"
    >
      <template slot="right">
        <u-button
          :customStyle="{
            width: '128rpx',
            height: '56rpx',
            background: '#4ABE45',
            borderRadius: '30rpx',
            color: '#fff',
          }"
          >完成</u-button
        >
      </template>
    </u-navbar>
    <!-- 规格信息 -->
    <view
      class="specification-box"
      v-for="(item, index) in specificationList"
      :key="index"
    >
      <view class="specification-box-header">
        <text>{{ item.name }}</text>
        <u-icon
          name="trash"
          size="32rpx"
          @click="deleteSpecification(index)"
        ></u-icon>
      </view>
      <view class="specification-class" v-for="(obj, i) in item.class" :key="i">
        <view class="specification-class-name">{{ obj.name }}</view>
        <u-icon
          name="close-circle-fill"
          size="38rpx"
          style="margin-right: 12rpx"
          @click="onDeleteClass(index, i)"
        ></u-icon>
      </view>
      <view class="add-class" @click="addClass(index)"
        ><u-icon name="plus" size="28rpx" style="margin-right: 12rpx"></u-icon
        >添加</view
      >
    </view>
    <view class="add-specification" @click="addSpecification"
      ><u-icon name="plus" color="#FFA918" style="margin-right: 15rpx"></u-icon
      >添加多个规格</view
    >
    <!-- 设置价格 -->
    <view class="set-price">
      <view class="set-price-title">设置价格</view>
      <view class="table-box">
        <view class="table-header">
          <view v-for="(item, index) in specificationList" :key="index">{{
            item.name
          }}</view>
          <view>图片</view>
          <view>原价</view>
          <view>现价</view>
          <view>批发价</view>
        </view>
        <view
          class="table-body"
          v-for="(item, index) in tableData"
          :key="index"
        >
          <view v-for="(obj, i) in item.specification" :key="i">{{
            obj.name
          }}</view>
          <view>上传</view>
          <view>100</view>
          <view>100</view>
          <view>100</view>
        </view>
      </view>
    </view>
    <!-- 添加规格弹窗 -->
    <u-popup :show="popupShow" @close="popupShow = false" @open="addText = ''">
      <view class="add-box">
        <u--input
          placeholder="多规格商品以空格隔开"
          border="none"
          v-model="addText"
          :customStyle="{
            background: '#F9F9F9',
            borderRadius: '16rpx',
            height: '85rpx',
          }"
        ></u--input>
        <view class="add-btn"
          ><u-button
            :customStyle="{
              width: '126rpx',
              height: '62rpx',
              borderRadius: '36rpx',
              borderColor: '#e9e9e9',
              color: '#999',
            }"
            @click="onAdd"
            >添加</u-button
          ></view
        >
      </view>
    </u-popup>
  </view>
</template>
<script>
import { cartesianProduct } from "@/utils";
export default {
  data() {
    return {
      popupShow: false,
      tableData: [],
      addText: "",
      addType: "", //添加规格或者规格下的分类 ,specification->规格 class-> 规格的子项
      addSpecificationIndex: "", //准备添加的规格index
      specificationList: [
        {
          name: "颜色",
          class: [],
        },
        {
          name: "尺寸",
          class: [],
        },
      ],
    };
  },
  methods: {
    addClass(index) {
      this.addSpecificationIndex = index;
      this.addType = "class";
      this.popupShow = true;
    },
    //添加规格
    addSpecification() {
      this.addType = "specification";
      this.popupShow = true;
    },
    //点击添加按钮
    onAdd() {
      if (!this.addText) return;
      const arr = this.addText.trim().split(/\s+/);
      //判断是否是添加的规格
      if (this.addType === "specification") {
        arr.forEach((item) => {
          this.$set(this.specificationList, this.specificationList.length, {
            name: item,
            class: [],
          });
        });
        this.popupShow = false;
        this.$nextTick(() => {
          this.getTableData();
        });
        return;
      }
      //添加规格下的分类
      const index = this.addSpecificationIndex; //要给哪个规格添加子项
      const classList = arr.map((item) => {
        return {
          name: item,
        };
      });
      this.$set(this.specificationList, index, {
        ...this.specificationList[index],
        class: [...this.specificationList[index].class, ...classList],
      });
      this.popupShow = false;
      this.$nextTick(() => {
        this.getTableData();
      });
    },
    //删除规格
    deleteSpecification(index) {
      this.specificationList = this.specificationList.filter(
        (item, i) => i != index
      );
      this.$nextTick(() => {
        this.getTableData();
      });
    },
    //删除某个规格中的某个子项
    onDeleteClass(index, i) {
      let classList = this.specificationList[index].class;
      classList = classList.filter((item, i2) => i2 != i);
      this.$set(this.specificationList, index, {
        ...this.specificationList[index],
        class: classList,
      });
      this.$nextTick(() => {
        this.getTableData();
      });
    },
    //计算循环出下面的列表
    getTableData() {
      const list = this.specificationList.map((item, index) => {
        const newArr = [];
        item.class.forEach((item2, index2) => {
          newArr.push({
            name: item2.name,
            id: index + "-" + index2,
          });
        });
        return newArr;
      });
      const newList = cartesianProduct(list);
      this.tableData = newList;
    },
  },
};
</script>
<style scoped lang="scss">
.container {
  background-color: #f6f7fb;
  padding: 16rpx 14rpx;
  .specification-box {
    background-color: #fff;
    padding: 30rpx;
    margin-bottom: 14rpx;
    border-radius: 14rpx;
    &-header {
      font-size: 28rpx;
      color: #333;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .specification-class {
      display: flex;
      margin-top: 16rpx;
      align-items: center;
      justify-content: space-between;
      &-name {
        flex: 1;
        height: 70rpx;
        line-height: 70rpx;
        background: #f6f7f9;
        border-radius: 8rpx;
        padding-left: 24rpx;
        color: #333;
        font-size: 26rpx;
        margin-right: 34rpx;
      }
    }
    .add-class {
      height: 70rpx;
      border-radius: 8rpx;
      font-size: 26rpx;
      background: #f6f7f9;
      display: flex;
      align-items: center;
      padding-left: 23rpx;
      margin-top: 16rpx;
    }
  }
  .add-specification {
    background-color: #fff;
    height: 110rpx;
    border-radius: 14rpx;
    margin-top: 14rpx;
    display: flex;
    align-items: center;
    color: #ffa918;
    font-size: 28rpx;
    justify-content: center;
    &:active {
      background-color: rgba(0, 0, 0, 0.05);
    }
  }
  .set-price {
    background-color: #fff;
    padding: 31rpx;
    border-radius: 14rpx;
    margin-top: 14rpx;
    &-title {
      font-size: 28rpx;
      color: #333333;
      margin-bottom: 28rpx;
    }
    .table-box {
      font-size: 26rpx;
    }
    .table-header {
      height: 72rpx;
      background-color: #f8f8f8;
      border-radius: 6rpx;
      color: #676767;
      display: flex;
      align-items: center;
      & > view {
        // width: 90rpx;
        flex: 1;
        // max-width: 90rpx;
        text-align: center;
      }
    }
    .table-body {
      display: flex;
      align-items: center;
      margin-top: 20rpx;
      & > view {
        flex: 1;
        text-align: center;
      }
    }
  }
  .add-box {
    padding: 19rpx 25rpx;
    padding-bottom: 60rpx;
    .add-btn {
      height: 104rpx;
      display: flex;
      align-items: center;
      justify-content: flex-end;
    }
  }
}
</style>