前端实现商品联级选择禁用(附带一个表情包插件)

<template>
  <div id="app">
    <h3>前端实现淘宝商品联级选择禁用</h3>
    <div v-for="(item, index) in specList" :key="index">
      <div class="title">{{ item.title }}</div>
      <div class="spec">
        <div class="spec-item" v-for="(its, ins) in item.list" :key="its.name + ins">
          <span
            @click="changeSpec(item.title, its.name, its.able)"
            :class="[
              selectSpec[item.title] === its.name ? 'active' : '',
              its.able ? '' : 'disabled'
            ]"
            >{{ its.name }}</span
          >
        </div>
      </div>
    </div>
    <input type="text" :value="selectEmojiVal">
    <VEmojiPicker v-show="showDialog" @select="selectEmoji" />
    <!-- <router-view/> -->
  </div>
</template>
<script>
import { VEmojiPicker } from 'v-emoji-picker';

const specList = [
  { title: '颜色', list: ['红色', '紫色', '白色', '黑色'] },
  { title: '套餐', list: ['套餐一', '套餐二', '套餐三', '套餐四'] },
  { title: '内存', list: ['64G', '128G', '256G'] },
];
const skuList = [
  // { id: 1608188117177, specs: ["红色", "套餐一", "64G"] },
  // { id: 1608188117178, specs: ["红色", "套餐一", "128G"] },
  // { id: 1608188117179, specs: ["红色", "套餐一", "256G"] },
  // { id: 1608188117180, specs: ["红色", "套餐二", "64G"] },
  // { id: 1608188117181, specs: ["红色", "套餐二", "128G"] },
  // { id: 1608188117182, specs: ["红色", "套餐二", "256G"] },
  // { id: 1608188117183, specs: ["红色", "套餐三", "64G"] },
  // { id: 1608188117184, specs: ["红色", "套餐三", "128G"] },
  // { id: 1608188117185, specs: ["红色", "套餐三", "256G"] },
  // { id: 1608188117186, specs: ["红色", "套餐四", "64G"] },
  // { id: 1608188117187, specs: ["红色", "套餐四", "128G"] },
  // { id: 1608188117188, specs: ["红色", "套餐四", "256G"] },
  // { id: 1608188117189, specs: ["紫色", "套餐一", "64G"] },
  // { id: 1608188117190, specs: ["紫色", "套餐一", "128G"] },
  // { id: 1608188117191, specs: ["紫色", "套餐一", "256G"] },
  { id: 1608188117192, specs: ['紫色', '套餐二', '64G'] },
  { id: 1608188117193, specs: ['紫色', '套餐二', '128G'] },
  { id: 1608188117194, specs: ['紫色', '套餐二', '256G'] },
  { id: 1608188117195, specs: ['紫色', '套餐三', '64G'] },
  { id: 1608188117196, specs: ['紫色', '套餐三', '128G'] },
  { id: 1608188117197, specs: ['紫色', '套餐三', '256G'] },
  { id: 1608188117198, specs: ['紫色', '套餐四', '64G'] },
  { id: 1608188117199, specs: ['紫色', '套餐四', '128G'] },
  { id: 1608188117200, specs: ['紫色', '套餐四', '256G'] },
  { id: 1608188117201, specs: ['白色', '套餐一', '64G'] },
  { id: 1608188117202, specs: ['白色', '套餐一', '128G'] },
  { id: 1608188117203, specs: ['白色', '套餐一', '256G'] },
  { id: 1608188117204, specs: ['白色', '套餐二', '64G'] },
  // { id: 1608188117205, specs: ["白色", "套餐二", "128G"] },
  // { id: 1608188117206, specs: ["白色", "套餐二", "256G"] },
  // { id: 1608188117207, specs: ["白色", "套餐三", "64G"] },
  // { id: 1608188117208, specs: ["白色", "套餐三", "128G"] },
  // { id: 1608188117209, specs: ["白色", "套餐三", "256G"] },
  // { id: 1608188117210, specs: ["白色", "套餐四", "64G"] },
  { id: 1608188117211, specs: ['白色', '套餐四', '128G'] },
  { id: 1608188117212, specs: ['白色', '套餐四', '256G'] },
  { id: 1608188117213, specs: ['黑色', '套餐一', '64G'] },
  { id: 1608188117214, specs: ['黑色', '套餐一', '128G'] },
  { id: 1608188117215, specs: ['黑色', '套餐一', '256G'] },
  { id: 1608188117216, specs: ['黑色', '套餐二', '64G'] },
  // { id: 1608188117217, specs: ["黑色", "套餐二", "128G"] },
  // { id: 1608188117218, specs: ["黑色", "套餐二", "256G"] },
  // { id: 1608188117219, specs: ["黑色", "套餐三", "64G"] },
  // { id: 1608188117220, specs: ["黑色", "套餐三", "128G"] },
  // { id: 1608188117221, specs: ["黑色", "套餐三", "256G"] },
  // { id: 1608188117222, specs: ["黑色", "套餐四", "64G"] },
  { id: 1608188117223, specs: ['黑色', '套餐四', '128G'] },
  { id: 1608188117224, specs: ['黑色', '套餐四', '256G'] },
];
// 第一步引入数据    这里引入的数据就是上面的 specList  skuList
export default {
  name: 'App',
  components: {
    VEmojiPicker,
  },
  data() {
    return {
      specList: [],
      skuList: [],
      selectSpec: {}, // 选择数据的对象 将已选的数据放在这个对象里面记录下来  用对象的好处在下面深拷贝处就能体验到了
      showDialog: true,
      selectEmojiVal: '',
    };
  },
  created() {
    //  第二步  处理数据
    this.skuList = skuList;
    // 初始化选择数据的对象
    specList.forEach(item => {
      this.$set(this.selectSpec, item.title, '');
    });
    // 将规格数据处理成我们视图所需要的数据类型
    this.specList = specList.map(item => ({
      title: item.title,
      list: item.list.map(its => {
        console.log(its, 'its');
        return {
          name: its,
          //  判断是否可以选择
          //  这里相当于init 初始化数据  this.isAble() 核心判断逻辑
          able: this.isAble(item.title, its), // 注释的调试看逻辑代码 false
        };
      }),
    }));
    // 注释的调试看逻辑代码
    // this.selectSpec = {
    //   '颜色':'',
    //   '套餐':'套餐一',
    //   '内存':'64G'
    // }
    // this.isAble('颜色', '红色')
  },
  methods: {
    // 核心判断逻辑
    // 判断规格是否可以被选择  核心函数 key当前的规格的title   value规格值
    isAble(key, value) {
      // 深拷贝 避免被影响
      const copySelectSpec = JSON.parse(JSON.stringify(this.selectSpec));
      // 用对象的好处就在这了 直接赋值当前验证项
      copySelectSpec[key] = value;
      // 用数组的 some 方法 效率高 符合条件直接退出循环
      const flag = this.skuList.some(item => {
        // 条件判断 核心逻辑判断
        console.log(item);
        let i = 0;
        // 判断当前所选商品在skuList列表中是否存在
        // 例如:所选{  '颜色':'','套餐':'套餐一','内存':'64G'},值为''也算存在,循环skuList每一项,直到找到颜色'',套餐一,64G,那一项后停止循环
        // eslint-disable-next-line no-restricted-syntax
        for (const k in copySelectSpec) {
          if (copySelectSpec[k] !== '' && item.specs.includes(copySelectSpec[k])) {
            console.log(item, '1');
            i++;
          } else if (copySelectSpec[k] === '') {
            i++;
          }
        }
        // 符合下面条件就退出了 不符合会一直循环知道循环结束没有符合的条件就 return false 了
        console.log(i, specList.length); // 注释的调试看逻辑代码
        return i === specList.length;
      });
      console.log(flag);
      return flag;
    },
    // 点击事件
    changeSpec(key, value, able) {
      if (!able) return;
      if (this.selectSpec[key] === value) {
        this.selectSpec[key] = '';
      } else {
        this.selectSpec[key] = value;
      }
      // forEach循环改变原数组
      this.specList.forEach(item => {
        item.list.forEach(its => {
          // eslint-disable-next-line no-param-reassign
          its.able = this.isAble(item.title, its.name);
          console.log(its.name, its.able);
        });
      });
    },
    selectEmoji(value) {
      this.selectEmojiVal = value.data;
      console.log(value);
    },
  },
};
</script>
<style lang="scss">
#app > div {
  margin: 10px 0;
}
.title {
  margin-bottom: 10px;
}
.spec-item {
  display: inline-block;
  margin-right: 10px;
}
.spec-item span {
  display: inline-block;
  border: 1px solid #eee;
  cursor: pointer;
  padding: 5px 10px;
}
.spec-item .active {
  border: 1px solid #09f;
  background-color: #09f;
  color: #fff;
}
.spec-item .disabled {
  color: #fff;
  cursor: not-allowed;
  background-color: #ccc;
  border-color: #ccc;
}
</style>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值