首页前端开发JavaScriptvue 使用饿了么UI仿写teambition的筛选功能

vue 使用饿了么UI仿写teambition的筛选功能

时间2024-01-31 23:55:03发布访客分类JavaScript浏览1076
导读:收集整理的这篇文章主要介绍了vue 使用饿了么UI仿写teambition的筛选功能,觉得挺不错的,现在分享给大家,也给大家做个参考。 目录问题描述大致的功能效果有如下思路分析完整代码总...
收集整理的这篇文章主要介绍了vue 使用饿了么UI仿写teambition的筛选功能,觉得挺不错的,现在分享给大家,也给大家做个参考。
目录
  • 问题描述
    • 大致的功能效果有如下
  • 思路分析
    • 完整代码
      • 总结

        问题描述

        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>
            

        总结

        这里面需要注意的就是鼠标移入移出显示对应的删除小图标。思路大致就这样,敲代码不易,咱们共同努力。

        以上就是vue 使用饿了么UI仿写teambition的筛选功能的详细内容,更多关于vue 仿写teambition的筛选功能的资料请关注其它相关文章!

        您可能感兴趣的文章:
        • vue项目创建并引入饿了么elementUI组件的步骤
        • vue.js template模板的使用(仿饿了么布局)
        • Vue2.0仿饿了么webapp单页面应用详细步骤
        • VUE饿了么树形控件添加增删改功能的示例代码
        • Vue 实现分页与输入框关键字筛选功能
        • VUE实现移动端列表筛选功能
        • 基于Vue实现的多条件筛选功能的详解(类似京东和淘宝功能)
        • 使用vue-router beforEach实现判断用户登录跳转路由筛选功能

        声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

        vue

        若转载请注明出处: vue 使用饿了么UI仿写teambition的筛选功能
        本文地址: https://pptw.com/jishu/594647.html
        three.js 实现露珠滴落动画效果的示例代码 一起来了解一下JavaScript的预编译(小结)

        游客 回复需填写必要信息