问题形容

teambition软件是企业办公协同软件,置信局部敌人的公司应该用过这款软件。外面的筛选性能挺有意思,本篇文章,就是仿写其性能。咱们先看一下最终做进去的效果图

大抵的性能成果有如下

  • 需要一:罕用筛选条件放在下面间接看到,不罕用筛选条件放在增加筛选条件外面
  • 需要二:筛选的形式有输入框筛选、下拉框筛选、工夫选择器筛选等
  • 需要三:如果感觉罕用筛选条件比拟多的话,能够鼠标移入点击删除,使之进入不罕用的筛选条件里
  • 需要四:也能够从不罕用的筛选条件外面点击对应筛选条件使之“蹦到”罕用筛选条件里
  • 需要五:点击重置使之复原到初试的筛选条件
  • 需要六:用户若是没输出内容点击确认按钮,就提醒用户要输出筛选条件

思路剖析

  • 对于需要一和需要二,咱们首先要搞两个全屏幕弹框,而后在data中定义两个数组,一个是放罕用条件的数组,另外一个是放不罕用条件的数组,罕用条件v-for到第一个弹框外面,不罕用条件v-for到第二个弹框外面。数组外面的每一项都要配置好对应内容,比方要有筛选字段名字,比方姓名、年龄什么的。有了筛选筛选字段名字当前,还有有一个类型type,在html中咱们要写三个类型的组件、比方input输入框组件,select组件,工夫选择器组件。应用依据type类型通过v-show显示对应字段,比方input的type为1,select的type为2,工夫选择器的type为3。是哪个type,就显示哪个组件。

对应两个数组如下:

topData: [ // 配置罕用的筛选项        {          wordTitle: "姓名",          type: 1, // 1 为input 2为select 3为DatePicker          content: "", // content为输入框绑定的输出数据          options: [], // options为所有的下拉框内容,能够发申请拿到存进来,这里是模仿          optionArr: [], // optionArr为选中的下拉框内容          timeArr: [], // timeArr为日期抉择区间        },        {          wordTitle: "年龄",          type: 1,          content: "",          options: [],          optionArr: [],          timeArr: [],        },        {          wordTitle: "授课班级",          type: 2,          content: "",          options: [ // 发申请获取下拉框选项            {              id: 1,              value: "一班",            },            {              id: 2,              value: "二班",            },            {              id: 3,              value: "三班",            },          ],          optionArr: [],          timeArr: [],        },        {          wordTitle: "入职工夫",          type: 3,           content: "",           options: [],           optionArr: [],           timeArr: [],         },      ],      bottomData: [ // 配置不罕用的筛选项        {          wordTitle: "工号",          type: 1,          content: "",          options: [],          optionArr: [],          timeArr: [],        },        {          wordTitle: "性别",          type: 2,          content: "",          options: [            {              id: 1,              value: "男",            },            {              id: 2,              value: "女",            },          ],          optionArr: [],          timeArr: [],        },      ],

对应html代码如下:

                <div class="rightright">                  <el-input                    v-model.trim="item.content"                    clearable                    v-show="item.type == 1"                    placeholder="请输出"                    size="small"                    :popper-append-to-body="false"                  ></el-input>                  <el-select                    v-model="item.optionArr"                    v-show="item.type == 2"                    multiple                    placeholder="请抉择"                  >                    <el-option                      v-for="whatItem in item.options"                      :key="whatItem.id"                      :label="whatItem.value"                      :value="whatItem.id"                      size="small"                    >                    </el-option>                  </el-select>                  <el-date-picker                    v-model="item.timeArr"                    v-show="item.type == 3"                    type="daterange"                    range-separator="至"                    start-placeholder="开始日期"                    end-placeholder="完结日期"                    format="yyyy-MM-dd"                    value-format="yyyy-MM-dd"                  >                  </el-date-picker>                </div>
残缺代码在最初,大家先顺着思路看哦
  • 对于需要三需要四,可形容为,删除下面的掉到上面。点击上面的蹦到下面。所以对应操作就是把下面数组某一项追加到上面数组,而后把下面数组的这一项删掉;把上面数组的某一项追加到下面数组,而后把这一行删掉。(留神还有一个索引)对应代码如下:
/* 点击某一项的删除小图标,把这一项增加到bottomData数组中       而后把这一项从topData数组中删除掉(依据索引判断是哪一项)        最初删除一个就把索引置为初始索引 -1   */    clickIcon(i) {      this.bottomData.push(this.topData[i]);      this.topData.splice(i, 1);      this.whichIndex = -1;    },    // 点击底部的项的时候,通过事件对象,看看点击的是底部的哪一项    // 而后把对应的那一项追加到topData中用于展现,同时把bottom数组    // 中的哪一项进行删除    clickBottomItem(event) {      this.bottomData.forEach((item, index) => {        if (item.wordTitle == event.target.innerText) {          this.topData.push(item);          this.bottomData.splice(index, 1);        }      });    },
  • 对于需要五需要六就简略了,对应代码如下,残缺代码正文中曾经写好了

残缺代码

<template>  <div id="app">    <div class="filterBtn">      <el-button type="primary" size="small" @click="filterMaskOne = true">        数据筛选<i class="el-icon-s-operation el-icon--right"></i>      </el-button>      <transition name="fade">        <div          class="filterMaskOne"          v-show="filterMaskOne"          @click="filterMaskOne = false"        >          <div class="filterMaskOneContent" @click.stop>            <div class="filterHeader">              <span>数据筛选</span>            </div>            <div class="filterBody">              <div class="outPrompt" v-show="topData.length == 0">                暂无筛选条件,请增加筛选条件...              </div>              <div                class="filterBodyCondition"                v-for="(item, index) in topData"                :key="index"              >                <div                  class="leftleft"                  @mouseenter="mouseEnterItem(index)"                  @mouseleave="mouseLeaveItem(index)"                >                  <span                    >{{ item.wordTitle }}:                    <i                      class="el-icon-error"                      v-show="whichIndex == index"                      @click="clickIcon(index)"                    ></i>                  </span>                </div>                <div class="rightright">                  <el-input                    v-model.trim="item.content"                    clearable                    v-show="item.type == 1"                    placeholder="请输出"                    size="small"                    :popper-append-to-body="false"                  ></el-input>                  <el-select                    v-model="item.optionArr"                    v-show="item.type == 2"                    multiple                    placeholder="请抉择"                  >                    <el-option                      v-for="whatItem in item.options"                      :key="whatItem.id"                      :label="whatItem.value"                      :value="whatItem.id"                      size="small"                    >                    </el-option>                  </el-select>                  <el-date-picker                    v-model="item.timeArr"                    v-show="item.type == 3"                    type="daterange"                    range-separator="至"                    start-placeholder="开始日期"                    end-placeholder="完结日期"                    format="yyyy-MM-dd"                    value-format="yyyy-MM-dd"                  >                  </el-date-picker>                </div>              </div>            </div>            <div class="filterFooter">              <div class="filterBtn">                <el-button                  type="text"                  icon="el-icon-circle-plus-outline"                  @click="filterMaskTwo = true"                  >增加筛选条件</el-button                >                <transition name="fade">                  <div                    class="filterMaskTwo"                    v-show="filterMaskTwo"                    @click="filterMaskTwo = false"                  >                    <div class="filterMaskContentTwo" @click.stop>                      <div class="innerPrompt" v-show="bottomData.length == 0">                        暂无内容...                      </div>                      <div                        class="contentTwoItem"                        @click="clickBottomItem"                        v-for="(item, index) in bottomData"                        :key="index"                      >                        <div class="mingzi">                          {{ item.wordTitle }}                        </div>                      </div>                    </div>                  </div>                </transition>              </div>              <div class="resetAndConfirmBtns">                <el-button size="small" @click="resetFilter">重置</el-button>                <el-button type="primary" size="small" @click="confirmFilter"                  >确认</el-button                >              </div>            </div>          </div>        </div>      </transition>    </div>  </div></template><script>export default {  name: "app",  data() {    return {      filterMaskOne: false, // 别离用于管制两个弹框的显示与暗藏      filterMaskTwo: false,      whichIndex: -1, // 用于记录点击的索引      apiFilterArr:[], //存储用户填写的筛选内容      topData: [ // 配置罕用的筛选项        {          wordTitle: "姓名",          type: 1, // 1 为input 2为select 3为DatePicker          content: "", // content为输入框绑定的输出数据          options: [], // options为所有的下拉框内容          optionArr: [], // optionArr为选中的下拉框内容          timeArr: [], // timeArr为日期抉择区间        },        {          wordTitle: "年龄",          type: 1,          content: "",          options: [],          optionArr: [],          timeArr: [],        },        {          wordTitle: "授课班级",          type: 2,          content: "",          options: [ // 发申请获取下拉框选项            {              id: 1,              value: "一班",            },            {              id: 2,              value: "二班",            },            {              id: 3,              value: "三班",            },          ],          optionArr: [],          timeArr: [],        },        {          wordTitle: "入职工夫",          type: 3,           content: "",           options: [],           optionArr: [],           timeArr: [],         },      ],      bottomData: [ // 配置不罕用的筛选项        {          wordTitle: "工号",          type: 1,          content: "",          options: [],          optionArr: [],          timeArr: [],        },        {          wordTitle: "性别",          type: 2,          content: "",          options: [            {              id: 1,              value: "男",            },            {              id: 2,              value: "女",            },          ],          optionArr: [],          timeArr: [],        },      ],    };  },  mounted() {    // 在初始化加载的时候,咱们就把咱们配置的罕用和不罕用的筛选项保留一份    // 当用户点击重置按钮的时候,再取出来使其复原到最后的筛选条件状态    sessionStorage.setItem("topData",JSON.stringify(this.topData))    sessionStorage.setItem("bottomData",JSON.stringify(this.bottomData))  },  methods: {    //鼠标移入显示删除小图标    mouseEnterItem(index) {      this.whichIndex = index;    },    // 鼠标来到将索引回复到默认-1    mouseLeaveItem() {      this.whichIndex = -1;    },    /* 点击某一项的删除小图标,把这一项增加到bottomData数组中       而后把这一项从topData数组中删除掉(依据索引判断是哪一项)        最初删除一个就把索引置为初始索引 -1   */    clickIcon(i) {      this.bottomData.push(this.topData[i]);      this.topData.splice(i, 1);      this.whichIndex = -1;    },    // 点击底部的项的时候,通过事件对象,看看点击的是底部的哪一项    // 而后把对应的那一项追加到topData中用于展现,同时把bottom数组    // 中的哪一项进行删除    clickBottomItem(event) {      this.bottomData.forEach((item, index) => {        if (item.wordTitle == event.target.innerText) {          this.topData.push(item);          this.bottomData.splice(index, 1);        }      });    },    // 点击确认筛选    async confirmFilter() {      // 如果所有的输入框的content内容为空,且选中的下拉框数组为空,且工夫选择器选中的数组为空      // 就阐明用户没有输出内容,那么咱们就提醒用户要输出内容当前再进行筛选      let isEmpty = this.topData.every((item)=>{        return (item.content == "") && (item.optionArr.length == 0) && (item.timeArr.length == 0)      })      if(isEmpty == true){         this.$alert('请输出内容当前再进行筛选', '筛选提醒', {          confirmButtonText: '确定'        });      }else{        // 收集参数发筛选申请,这里要分类型,把不为空的既有用户输出内容的        // 存到存到数据筛选的数组中去,而后发申请给后端。        this.topData.forEach((item)=>{          if(item.type == 1){            if(item.content != ""){              let filterItem = {                field:item.wordTitle,                value:item.content              }              this.apiFilterArr.push(filterItem)            }          }else if(item.type == 2){            if(item.optionArr.length > 0){              let filterItem = {                field:item.wordTitle,                value:item.optionArr              }              this.apiFilterArr.push(filterItem)            }          }else if(item.type == 3){            if(item.timeArr.length > 0){              let filterItem = {                field:item.wordTitle,                value:item.timeArr              }              this.apiFilterArr.push(filterItem)            }          }         })        // 把筛选的内容放到一个数组外面,传递给后端(当然不肯定把参数放到数组外面)        // 具体以怎么的模式传递给后端,能够具体磋商        console.log("带着筛选内容发申请",this.apiFilterArr);      }    },    // 重置时,再把最后的配置筛选项取出来赋给对应的两个数组    resetFilter() {      this.topData = JSON.parse(sessionStorage.getItem("topData"))      this.bottomData = JSON.parse(sessionStorage.getItem("bottomData"))    },  },};</script><style lang="less" scoped>.filterBtn {  width: 114px;  height: 40px;  .filterMaskOne {    top: 0;    left: 0;    position: fixed;    width: 100%;    height: 100%;    z-index: 999;    background-color: rgba(0, 0, 0, 0.3);    .filterMaskOneContent {      position: absolute;      top: 152px;      right: 38px;      width: 344px;      height: 371px;      background-color: #fff;      box-shadow: 0px 0px 4px 3px rgba(194, 194, 194, 0.25);      border-radius: 4px;      .filterHeader {        width: 344px;        height: 48px;        border-bottom: 1px solid #e9e9e9;        span {          display: inline-block;          font-weight: 600;          font-size: 16px;          margin-left: 24px;          margin-top: 16px;        }      }      .filterBody {        width: 344px;        height: 275px;        overflow-y: auto;        overflow-x: hidden;        box-sizing: border-box;        padding: 12px 24px 0 24px;        .outPrompt {          color: #666;        }        .filterBodyCondition {          width: 100%;          min-height: 40px;          display: flex;          margin-bottom: 14px;          .leftleft {            width: 88px;            height: 40px;            display: flex;            align-items: center;            margin-right: 20px;            span {              position: relative;              font-size: 14px;              color: #333;              i {                color: #666;                right: -8px;                top: -8px;                position: absolute;                font-size: 15px;                cursor: pointer;              }              i:hover {                color: #5f95f7;              }            }          }          .rightright {            width: calc(100% - 70px);            height: 100%;            /deep/ input::placeholder {              color: rgba(0, 0, 0, 0.25);              font-size: 13px;            }            /deep/ .el-input__inner {              height: 40px;              line-height: 40px;            }            /deep/ .el-select {              .el-input--suffix {                /deep/ input::placeholder {                  color: rgba(0, 0, 0, 0.25);                  font-size: 13px;                }                .el-input__inner {                  border: none;                }                .el-input__inner:hover {                  background: rgba(95, 149, 247, 0.05);                }              }            }            .el-date-editor {              width: 100%;              font-size: 12px;            }            .el-range-editor.el-input__inner {              padding-left: 2px;              padding-right: 0;            }            /deep/.el-range-input {              font-size: 13px !important;            }            /deep/ .el-range-separator {              padding: 0 !important;              font-size: 12px !important;              width: 8% !important;              margin: 0;            }            /deep/ .el-range__close-icon {              width: 16px;            }          }        }      }      .filterFooter {        width: 344px;        height: 48px;        display: flex;        justify-content: space-between;        align-items: center;        box-sizing: border-box;        padding-left: 24px;        padding-right: 12px;        border-top: 1px solid #e9e9e9;        .filterBtn {          .filterMaskTwo {            position: fixed;            top: 0;            left: 0;            width: 100%;            height: 100%;            background-color: rgba(0, 0, 0, 0.3);            z-index: 1000;            .filterMaskContentTwo {              width: 240px;              height: 320px;              background: #ffffff;              box-shadow: 0px 0px 4px 3px rgba(194, 194, 194, 0.25);              border-radius: 4px;              position: absolute;              top: 360px;              right: 180px;              overflow-y: auto;              box-sizing: border-box;              padding: 12px 0 18px 0;              overflow-x: hidden;              .innerPrompt {                color: #666;                width: 100%;                padding-left: 20px;                margin-top: 12px;              }              .contentTwoItem {                width: 100%;                height: 36px;                line-height: 36px;                font-size: 14px;                color: #333333;                cursor: pointer;                .mingzi {                  width: 100%;                  height: 36px;                  box-sizing: border-box;                  padding-left: 18px;                }              }              .contentTwoItem:hover {                background: rgba(95, 149, 247, 0.05);              }            }          }        }      }    }  }}// 管制淡入淡出成果.fade-enter-active,.fade-leave-active {  transition: opacity 0.3s;}.fade-enter,.fade-leave-to {  opacity: 0;}</style>

总结

这外面须要留神的就是鼠标移入移出显示对应的删除小图标。思路大抵就这样,敲代码不易,咱们共同努力。