仿有赞选择配送方式(省市)

400 阅读2分钟

使用了ant-design的多选框组件和气泡组件。

1.数据格式


其中,val表示多选的框的值,selected表示该元素的city是否有选中的,也就是控制多选的样式,tag表示该多选框选中,如果是第一级则她的city的tag也全为true。show表示在页面中是否显示这个多选框~

2.html部分

1.图片


鼠标移入一级值的时候气泡组件会显示出对应city的值

2.代码

<template>
  <div class="box">
    <div class="box-option">
      <div :style="{ borderBottom: '1px solid #E9E9E9' }">
        <a-checkbox
          :indeterminate="indeterminate"
          :checked="checkAll"
          @change="onCheckAllChange"
        >
          Check all
        </a-checkbox>
      </div>
      <br />
      <div v-for="(item, index) in plainOptions" :key="item.val">
        <a-checkbox
          v-if="item.show"
          :indeterminate="item.selectd"
          :checked="item.tag"
          @change="(e) => onChangePro(index, e)"
        >
          <a-popover placement="bottom">
            <template slot="content">
              <div v-for="(city, cityIndex) in item.city" :key="cityIndex">
                <a-checkbox
                  v-if="city.show"
                  :checked="city.tag"
                  @change="(e) => onchangeCity(index, cityIndex, e)"
                >
                  {{ city.val }}
                </a-checkbox>
              </div>
            </template>
            <template slot="title"></template>
            {{ item.val }}
          </a-popover>
        </a-checkbox>
      </div>
    </div>
    <div class="box-result">
      <a-button type="primary" @click="onSubmitSelected">
        提交
      </a-button>
      <div v-for="(item, index) in resultList" :key="index" class="row-data">
        <h3 v-for="(val, idx) in item" :key="idx">{{ val }}</h3>
        <a-button @click="onUpdateResult(item, index)">
          修改
        </a-button>
        <a-button @click="onDeleteResult(item, index)">
          删除
        </a-button>
      </div>
    </div>
  </div>
</template>

3.js部分

1.图片

2.代码

export default {
  data() {
    return {
      indeterminate: false,
      checkAll: false,
      plainOptions: [],
      resultList: [],
    };
  },
  watch: {
    //注意监听数组
    plainOptions: {
      handler(newVal, oldVal) {
        // 别忘了show
        // 但凡newVal中的tag有true的且是显示在页面上的,那么indeterminate就为true
        // 如果所有的tag(其实也就是省级的tag)全为tag,那么indeterminate就为false,而checkAll为true
        let falg = false;
        newVal.forEach((v) => {
          if (falg) {
            return;
          }
          v.city.forEach((k) => {
            if (k.tag && k.show) {
              this.indeterminate = true;
              this.checkAll = false;
              falg = true;
              return;
            }
          });
        });
        //全选
        let res = newVal.every((v) => {
          return v.tag == true;
        });
        this.checkAll = res;
        if (res) {
          this.indeterminate = false;
        }
        //全不选
        if (!falg) {
          this.indeterminate = false;
        }
      },
      deep: true,
    },
  },
  mounted() {
    this.getData();
  },
  methods: {
    getData() {
      this.$axios.get("/data/casc-demo.json").then((res) => {
        this.plainOptions = res.data;
      });
    },
    onChangePro(index, e) {
      this.plainOptions[index].tag = e.target.checked;
      this.plainOptions[index].selectd = false;
      this.handleProSelected(this.plainOptions[index]);
    },
    onchangeCity(index, cityIndex, e) {
      this.plainOptions[index].city[cityIndex].tag = e.target.checked;
      this.handleCitySelected(this.plainOptions[index], cityIndex);
    },
    onCheckAllChange(e) {
      //所有的数据都根据e的值变化
      this.plainOptions.forEach((v) => {
        v.tag = e.target.checked;
        v.selectd = false;
        v.city.forEach((k) => {
          k.tag = e.target.checked;
        });
      });
    },
    //省级选择,如果是选中会影响城市
    handleProSelected(proData) {
      proData.city.forEach((v) => {
        v.tag = proData.tag;
      });
    },
    //城市选择,查看省级是否需要选中
    handleCitySelected(proData, cityIndex) {
      let countTag = 0;
      proData.city.forEach((v) => {
        if (v.tag) {
          countTag++;
        }
      });
      if (countTag == 0) {
        proData.tag = false;
        proData.selectd = false;
      } else if (countTag == proData.city.length) {
        proData.tag = true;
        proData.selectd = false;
      } else {
        proData.tag = false;
        proData.selectd = true;
      }
    },
    /*提交数据,将选中的数据的show设置为false,这样下次就不会显示了
      需要得到的是市级,但是还有修改功能
         如果省级的tag为true,那么省级以及市级的show都为false,
         如果省级的selected为true,那么省级的show不变,而tag为true的市级的show为false
         同时存储市级的val值,太变态了!!!只能一个一个的找到,因为后端返回的也是这个
    */
    onSubmitSelected() {
      let submitData = [];
      this.plainOptions.forEach((v) => {
        if (v.tag && v.show) {
          v.show = false;
          v.city.forEach((k) => {
            k.show = false;
            submitData.push(k.val);
          });
        } else if (v.selectd) {
          v.selectd = false;
          v.city.forEach((k) => {
            if (k.tag && k.show) {
              k.show = false;
              submitData.push(k.val);
            }
          });
        }
      });
      this.resultList.push(submitData);
    },
    //修改表格数据
    onUpdateResult(val, idx) {
      //将参数的值放回数组
      this.handleChangeOptions(val, "update");
    },
    //删除该行
    onDeleteResult(val, idx) {
      this.resultList.splice(idx, 1);
      this.handleChangeOptions(val, "delete");
    },
    /*搞成一个函数,方便删除和修改使用
      根据参数,遍历数组,将show和tag修改
      但凡有一个city被修改了,那么省级也要被修改
    */
    handleChangeOptions(val, type) {
      val.forEach((v) => {
        this.plainOptions.forEach((k) => {
          let flag = false;
          k.city.forEach((z) => {
            if (v == z.val) {
              if (type == "delete") {
                z.tag = false;
              }
              z.show = true;
              flag = true;
            }
          });
          if (flag) {
            if (type == "delete") {
              k.tag = false;
              k.selectd = false;
            } else if (k.tag) {
              k.selectd = false;
            } else {
              k.selectd = true;
            }
            k.show = true;
          }
        });
      });
    },
  },
};

3.css部分

.box {
  margin: 20px;
}

.box-option {
  padding-bottom: 100px;
}

.box-result {
  padding-top: 20px;
}
.row-data {
  display: flex;
  padding: 10px 0;
  border-bottom: 1px solid forestgreen;
}
h3 {
  padding: 0 10px;
}