Vue3 E-commerce Project===> What you don't know!!!

Preface

It feels good to write a widget in your project today and share it with you. If you need to use it later, just take a look at this blog

Let's start with the concept of SKU and SPU:

  • SPU (Standard Product Unit) Standardized Product Unit. It is the smallest unit of aggregation of commodity information. It is a set of reusable, easily retrievable standardized information that describes the characteristics of a product. Generally speaking, a commodity with the same attribute value and characteristics can be called a SPU.
  • SKU (Stock Keeping Unit) unit of inventory, that is, unit of stock in and out measurement, can be in units of parts, boxes, pallets, etc. SKU is the smallest physically indivisible unit of inventory. It should be handled according to different business conditions and different management modes.

SPU: Represents a commodity with many identical attributes.
SKU: Represents any combination of specifications that can be selected for changing goods. It is the unique identification of the inventory unit.

For example, the usage scenario shown in the following image

thinking

  • Get the list data of all the combinations with SKUs from the back end, find the list of SKUs with inventory, below is the list of SKUs with inventory
[Blue, China, 10 cm]
[Green, China, 20 cm]
[Blue, Japan, 30 cm]
[Black, Japan, 30 cm]

Then calculates the Cartesian set of the SKU set to get the following value, as follows:

[Blue, China, 10 cm]--->[Blue, China, 10 cm,blue#China, Blue#10cm,China#10cm,blue#China#10cm]
[Green, China, 20 cm]--->[Green, China, 20 cm,green#China, Green#20cm,China#20cm,green#China#20cm]
[Blue, Japan, 30 cm]--->[Blue, Japan, 30 cm,blue#Japan, Blue#30cm,Japan#30cm,blue#Japan#30cm]
[Black, Japan, 30 cm]--->[Black, Japan, 30 cm,black#Japan, Black#30cm,Japan#30cm,black#Japan#30cm]

Then generate a dictionary of the dedicated paths, as follows

const dic = {
  //If it happens twice, write two skuId s
  'blue':[skuId,skuId], 
  'China': [skuId],
  blue#China#10cm:[skuId]
  blue#China: [skuId]
}

Start

Create a new goods-sku.vue file in the goods/components folder

The basic layout code is as follows

<template>
  <div class="goods-sku">
    <dl>
      <dt>colour</dt>
      <dd>
        <img class="selected" src="https://yanxuan-item.nosdn.127.net/d77c1f9347d06565a05e606bd4f949e0.png" alt="">
        <img class="disabled" src="https://yanxuan-item.nosdn.127.net/d77c1f9347d06565a05e606bd4f949e0.png" alt="">
      </dd>
    </dl>
    <dl>
      <dt>size</dt>
      <dd>
        <span class="disabled">10 inch</span>
        <span class="selected">20 inch</span>
        <span>30 inch</span>
      </dd>
    </dl>
    <dl>
      <dt>Edition</dt>
      <dd>
        <span>American version</span>
        <span>Port Edition</span>
      </dd>
    </dl>
  </div>
</template>
<script>
export default {
  name: 'GoodsSku'
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>

Then use it in the component

<!-- Picture information -->
        <div class="spec">
          <GoodsName :goods="detail" />
          <!-- Specification components -->
          <GoodsSku />
        </div>
<script>
import GoodsSku from './components/goods-sku'
components:{GoodsSku}
</script>

Start Rendering Component

Inject: specs="detail.specs" into the commodity specification component
The code is as follows

<div class="spec">
          <GoodsName :goods="detail" />
          <!-- Specification components -->
          <GoodsSku :specs="detail.specs" />
        </div>

Receive data in subcomponents

props:{
	specs:{
	type:Array,
	default:()=>[]
	}
}

Then render the page with the following code

<template>
  <div class="goods-sku">
    <dl v-for='(item, index) in specs' :key='index'>
      <dt>{{item.name}}</dt>
      <dd>
        <template v-for='(tag, n) in item.values' :key='n'>
          <img :class='{selected: tag.selected}' v-if='tag.picture' :src="tag.picture" alt="" >
          <span :class='{selected: tag.selected}' v-else >{{tag.name}}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>

Bind Button Click Event to Complete Selection and Uncheck

  • The current click is selected, cancel it
  • The current click is not checked, first the current specifications buttons are all canceled, the current buttons are checked
    The code is as follows
<template>
  <div class="goods-sku">
    <dl v-for='(item, i) in specs' :key='i'>
      <dt>{{item.name}}</dt>
      <dd>
        <template v-for='(tag, n) in item.values' :key='n'>
          <img :class='{selected: tag.selected}' v-if='tag.picture' :src="tag.picture" alt="" @click='toggle(tag, item.values)'>
          <span :class='{selected: tag.selected}' v-else @click='toggle(tag, item.values)'>{{tag.name}}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
export default {
  name: 'GoodsSku',
  props: {
    // Specification parameters for goods
    specs: {
      type: Array,
      default: () => []
    }
  },
  setup () {
      // Controls the selection and selection of labels (guarantees that only one label can be selected)
      const toggle = (tag, list) => {
        // Handles whether the currently clicked label is selected
        tag.selected = !tag.selected
        // Handles clicking on tags other than the current one
        list.forEach(item => {
          if (item.name !== tag.name) {
            // Other tags, all programmed unchecked States
            item.selected = false
          }
        })
      }
      return { toggle }
  }
}
</script>

Idea Analysis of Disabling Effect

Overview steps:

  1. Create a new js file in the dictionary based on a valid (inventory) sku combination from the skus data returned in the background
/**
 * Find power-set of a set using BITWISE approach.
 *
 * @param {*[]} originalSet
 * @return {*[][]}
 */
export default function bwPowerSet(originalSet) {
  const subSets = [];

  // We will have 2^n possible combinations (where n is a length of original set).
  // It is because for every element of original set we will decide whether to include
  // it or not (2 options for each set element).
  const numberOfCombinations = 2 ** originalSet.length;

  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  // it shows by its bits (0 or 1) whether to include related element from the set or not.
  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  // include only "2" to the current set.
  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = [];

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      // Decide whether we need to include current element into the subset or not.
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex]);
      }
    }

    // Add current subset to the list of all subsets.
    subSets.push(subSet);
  }

  return subSets;
}
  1. Get all subset sets from valid sku combinations (Cartesian set)
  2. Combines a set of subsets into a path dictionary, that is, an object.
import powerSet from '@/vendor/power-set.js'
// Generate path dictionary
const usePathMap = (skus) => {
  // Path Dictionary Results
  const result = {}
  // Specification separator
  const spliter = '※'

  skus.forEach(sku => {
    // Filter out invalid sku data
    console.log(sku.inventory)
    if (sku.inventory === 0) return
    // Get aggregated data for specifications: [Blue, China, 10cm]
    const spec = sku.specs.map(item => item.valueName)
    // Calculates the Cartesian set of the sku specification
    const specSet = powerSet(spec)
    specSet.forEach(item => {
      // Exclude empty arrays
      if (item.length === 0) return
      // key to generate dictionary
      const key = item.join(spliter)
      // Add key to dictionary
      if (result[key]) {
        // The current key already exists in the dictionary
        result[key].push(sku.id)
      } else {
        // The current key does not exist in the dictionary
        result[key] = [sku.id]
      }
    })
  })

  return result
}

Reference example

Disable Effect-Set Status

Purpose: Update the disabled state of other buttons when the specification is clicked while the component is initialized.

The code is as follows

// Get values for all selected specifications
const getSelectedValues = (specs) => {
  // All selected specification data
  const result = []
  specs.forEach((item, index) => {
    // Get the selected information for the specification
    const spec = item.values.find(tag => tag.selected)
    if (spec) {
      // The specification is selected
      result[index] = spec.name
    } else {
      // The specification is not selected
      result[index] = undefined
    }
  })
  return result
}

// Controls whether specification labels are disabled
const updateDisabledStatus = (specs, pathMap) => {
  // seletedValues = [undefined, undefined, undefined]
  specs.forEach((spec, i) => {
    // Selected values need to be reinitialized each time a specification is traversed
    const seletedValues = getSelectedValue(specs)
    spec.values.forEach(tag => {
      if (tag.selected) {
        // Labels themselves are selected and do not need to be processed
        return
      } else {
        // Not checked (when initializing, you need to determine the disabled state of a single specification)
        seletedValues[i] = tag.name
      }
      // At this point, you need to decide if the current button should be disabled
      // Combine a path based on the currently selected value
      // Filter the undefined values and combine a path based on the remaining values
      let currentPath = seletedValues.filter(item => item)
      if (currentPath.length > 0) {
        // Split Path String currentPath =Black_10cm
        currentPath = currentPath.join(spliter)
        // Determine if the current path is in the path dictionary (if the path is not found in the dictionary, prove that the current label should be disabled)
        tag.disabled = !pathMap[currentPath]
      }
      // Individually determine if a single button should be disabled
      // tag.disabled = !pathMap[tag.name]
    })
  })
}
  setup (props) {
    const pathMap = getPathMap(props.goods.skus)
    // Update disabled state when component is initialized
+    updateDisabledStatus(props.specs, pathMap)
    const clickSpecs = (item, val) => {
      // If disabled, do not act
+      if (val.disabled) return
      // 1.Checking and unchecking logic
      if (val.selected) {
        val.selected = false
      } else {
        item.values.find(bv => { bv.selected = false })
        val.selected = true
      }
      // Update Disabled Status on Click
+      updateDisabledStatus(props.specs, pathMap)
    }
    return { clickSpecs }
  }

summary

That's what front-end engineers must know, come on

  • spu represents a commodity and has many identical attributes.
  • sku represents any combination of the optional specifications of the item and is the only identification of the inventory unit.
    Here's my personal understanding. Okay, I'm here today. See you tomorrow

Keywords: Javascript Vue

Added by jokobe on Tue, 21 Sep 2021 20:27:19 +0300