The address of the project: https://github.com/hackftz/sku-implement/tree/master

Foreword: recently just have skU commodity demand, saw some thought, oneself realized, if passing feel write also line, trouble point praise oh, thank!

Note: original code, copy please note source oh!

The effect is as follows:

  1. Code section
  • JSX file
import React, { useState } from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  // All lines and options
  const rows = [
    ['red'.'black'],
    ['leather'.'Textile cloth'],
    ['China'.'the United States'.'Russia']];// All merchantable items
  const products = [
    ['red'.'leather'.'China'],
    ['red'.'Textile cloth'.'the United States'],
    ['black'.'Textile cloth'.'China'],
    ['black'.'Textile cloth'.'Russia']];// User options
  let initialSelectTypes = [];
  for (let i = 0; i < rows.length; i++) {
    initialSelectTypes[i] = ' ';
  }

  // The item that the user has selected
  const [selectTypes, setSelectTypes] = useState(initialSelectTypes);

  // Flatten all options
  const flatRows = rows.flat();

  // All optional lengths
  const flagRowsLength = flatRows.length;

  // Get the matrix
  const getMatrix = () = > {
    // Create matrix cannot use reference type to create matrix when modifying a column!!
    // const matrix = new Array(flagRowsLength).fill(new Array(flagRowsLength).fill(0));

    // Create a matrix
    let matrix = [];
    for (let i = 0; i < flagRowsLength; i++) {
      matrix[i] = [];

      for (let j = 0; j < flagRowsLength; j++) {
        matrix[i][j] = 0; }}// Fill the matrix with merchantable items
    for (let i = 0; i < products.length; i++) {
      const product = products[i];

      for (let j = 0; j < product.length; j++) {
        // The first commodity name
        const prod = product[j];

        // The first coordinates of the horizontal and vertical directions
        const flatRowsIndexOfProd = flatRows.indexOf(prod);

        // The rest of the item name after the first item name
        const otherProds = product.filter((item) = >item ! == prod);for (let i = 0; i < otherProds.length; i++) {
          const otherProd = otherProds[i];

          // Fill the intersection of horizontal and vertical hits
          const flatRowsIndexOfOtherProd = flatRows.indexOf(otherProd);
          matrix[flatRowsIndexOfProd][flatRowsIndexOfOtherProd] = 1; }}}return matrix;
  };

  const matrix = getMatrix();
  console.table(matrix);

  // Get an array of optional Types
  function getCanSelectTypes(selectTypes, products) {
    let canSelectTypes = [];

    / / initial value
    if (selectTypes.every((item) = > item === ' ')) {
      // Flatten products and filter duplicates
      const flatProducts = products.flat();
      canSelectTypes = [...new Set(flatProducts)];
    } else {
      // important !!!!
      // First push selectTypes forward with values using sort
      const forwardSelectTypes = selectTypes.slice().sort((a, b) = > {
        if (a && b) {
          return 1;
        }

        if(a && ! b) {return -1;
        }

        if(! a && b) {return 1;
        }

        if(! a && ! b) {return 0; }});// forwardSelectTypes converts to a matrix
      const forwardMatrix = forwardSelectTypes.filter(Boolean).map((item) = > {
        const index = flatRows.indexOf(item);
        return matrix[index];
      });

      // The initial value is used for cumulative calculation
      let initialCanSelectTypes = [];
      for (let i = 0; i < flatRows.length; i++) {
        initialCanSelectTypes[i] = 1;
      }

      canSelectTypes = forwardMatrix
        .reduce((acc, cur) = > {
          for (let i = 0; i < acc.length; i++) {
            acc[i] = acc[i] & cur[i];
          }

          return acc;
        }, initialCanSelectTypes)
        .map((item, index) = > {
          if (item === 1) {
            return flatRows[index];
          }
        })
        .filter(Boolean);
    }

    return canSelectTypes;
  }

  // The calculated option
  const canSelectTypes = getCanSelectTypes(selectTypes, products);

  // Click options
  const clickType = (index, type) = > {
    // let newSelectTypes = selectTypes.slice();
    let newSelectTypes = JSON.parse(JSON.stringify(selectTypes));

    if (newSelectTypes[index] === ' ') {
      newSelectTypes[index] = type;
    } else {
      if (newSelectTypes[index] === type) {
        // The reference problem removes the index element directly
        // newSelectTypes[index] === '';
        newSelectTypes.splice(index, 1.' ');
      } else{ newSelectTypes[index] = type; }}console.log('% c newSelectTypes after ⧭'.'color: #d0bfff', newSelectTypes);
    setSelectTypes(newSelectTypes);
  };

  return (
    <div className="App">
      {rows.map((types, index) => {
        return (
          <div className="row" key={types}>{types.map((type) => {// Optional const isSelect = selecttypes.includes (type); // Disable const noDisabled = canselecttypes.includes (type); return (<button className={'type'${+ `isSelect ? 'select ' :"'} ` + ` ${!isSelect ? (noDisabled? ' ': 'disabled') :"'} `}key={type} onClick={()= > clickType(index, type)}>
                  {type}
                </button>
              );
            })}
          </div>
        );
      })}
    </div>
  );
}

export default App;
Copy the code
  • css
.App {
  padding: 40px;
}


.row {
  height: 50px;
  line-height: 50px;

  min-width: 400px;
}

.type {
  padding: 4px 10px;
  display: inline-block;

  margin-right: 15px;
  background-color:  white;
  border: 1px solid gray;;
  color: gray;

  cursor: pointer;
}

.type.select {

  color: red;
  border: 1px solid red;
  box-shadow:none;
}

.type.disabled {
  color: lightgray;
  border: 1px solid lightgray;
  box-shadow:none;
  pointer-events: none;
}
Copy the code
  1. Implementation logic
  • We need to have these variables

    Items selected by the user — selectTypes calculated to be optional — canSelectTypes optional — isSelect not disabled — noDisabled

  • We need constants to flatten all options — flatRows The length of all options — flagRowsLength

  • We need to have several methods getMatrix — get the matrix to compare to get an array of optional Types — getCanSelectTypes

  • The key point! First of all, we need to use the initial data to generate a matrix, which is a network structure, so that we can clearly see which options can be associated with each other to form the final product options.

    So this is the matrix that I’m going to generate based on what’s available for sale.

  • Detail section – Create matrix cannot use reference type to create matrix when modifying a column!! Each time the user clicks on an option, there will be an empty option. In this case, the part of selectTypes with values should be pushed forward, and the part with values should be pushed forward. Use sort – summing each array. Use bit operations on each array element – array reference problem, use splice to remove old items