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:
- 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; }
- Get all subset sets from valid sku combinations (Cartesian set)
- 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