zoukankan      html  css  js  c++  java
  • vue开发个性化select,带分页以及搜索功能的组件

    前提:必须先安装了element-ui

    自定义开发带分页以及搜索框的select

     

     

    用法

    select.vue文件

    <template>
      <div v-clickoutside="()=>visible=false" class="com-select" :class="{'is-disabeled' : disabled}">
        <div ref="reference" class="com-select-input" @click="clickSelectInput">
          <div class="one"></div>
          <!-- tags展示 -->
          <div v-if="value.length>0" class="two">
            <!-- <template v-if="isCheckAll">
              <el-tag
                size="small"
                closable
                hit
                type="info"
                disable-transitions
                @close="cancelCheckAll()">
                <span class="el-select__tags-text">全选</span>
              </el-tag>
            </template>
            <template v-else> -->
            <el-tag
              v-for="item in selectedArr"
              :key="item[listKey]"
              size="small"
              closable
              hit
              type="info"
              disable-transitions
              @close="deleteTag(item)">
              <span class="el-select__tags-text">{{ item[listVal] }}</span>
            </el-tag>
            <!-- </template> -->
          </div>
          <div v-else class="two" style="color: #c4c9db;">请选择</div>
          <div
            class="three"
            @mouseenter.stop="inputHovering = true"
            @mouseleave.stop="inputHovering = false"
          >
            <i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click.stop="cancelCheckAll"></i>
            <i v-else :class="`el-icon-arrow-${visible ? 'up' : 'down'} el-select__caret el-input__icon`"></i>
          </div>
        </div>
        <transition name="el-zoom-in-top">
          <!-- 下拉框 -->
          <the-select-menu
            v-show="visible"
            ref="popper"
            append-to-body>
            <!-- 搜索框 -->
            <el-input v-model="queryVal" placeholder="请输入" size="small" clearable @input="handleSearch" @keyup.enter.native="handleSearch">
              <el-button slot="append" icon="el-icon-search" @click="handleSearch"></el-button>
            </el-input>
            <!-- select选项 -->
            <div class="com-select-body">
              <div
                v-for="(item, i) in list"
                v-show="isShowFilterArr ? item._isShow : item.isShow"
                :key="item[listKey]"
                :title="item[listVal]"
                :style="formatColumn()"
                :class="['com-option', {'selected': item.selected,}]"
                @click="selectOptionClick(item, i)"
              >
                {{ item[listVal] }}
              </div>
              <div v-if="list.length === 0" class="com-select-nodata">
                <img :src="require('@/assets/image/nodatatable.png')" />
                <div>暂无数据</div>
              </div>
              <template v-if="nextPageStaus">
                <i v-for="v in 3" :key="'AA' + v" :style="formatColumn()"></i>
              </template>
            </div>
            <!-- 分页 -->
            <div class="com-footer-page">
              <el-button size="small" :disabled="prePageStaus" @click="prePage">上一页</el-button>
              <el-button type="primary" size="small" @click="checkAll">全选</el-button>
              <el-button size="small" :disabled="nextPageStaus" @click="nextPage">下一页</el-button>
            </div>
          </the-select-menu>
        </transition>
      </div>
    </template>
    
    <script>
    import TheSelectMenu from './select-dropdown.vue';
    import Clickoutside from 'element-ui/src/utils/clickoutside';
    import { valueEquals } from 'element-ui/src/utils/util';
    export default {
      name: 'SelectPro',
      components: { TheSelectMenu },
      directives: { Clickoutside },
      props: {
        value: { // 默认选中的值
          type: Array,
          default: () => [],
          required: true
        },
        options: { // 传进来的选项数组
          type: Array,
          default: () => []
        },
        props: {
          type: Object,
          default: () => ({ label: 'label', value: 'value' })
        },
        column: { // 展示多少列 暂时支持1-4列
          type: Number,
          default: 3
        },
        disabled: { // 置灰
          type: Boolean,
          default: false
        },
        selectAll: { // 初始化是否全选
          type: Boolean,
          default: false
        }
      },
      data() {
        return {
          optionArr: this.initOptions(),
          inputHovering: false,
          selectedArr: [],
          filterArr: [],
          queryVal: '',
          visible: false,
          pageSize: this.column * 4,
          currentPage: 1,
          filterCurrentPage: 1
        };
      },
      computed: {
        list() {
          return this.isShowFilterArr ? this.filterArr : this.optionArr;
        },
        listKey() {
          return this.props['value'] || 'value';
        },
        listVal() {
          return this.props['label'] || 'label';
        },
        isCheckAll() {
          return this.selectedArr.length === this.optionArr.length;
        },
        isShowFilterArr() {
          return this.filterArr.length > 0 || this.queryVal !== '';
        },
        showClose() {
          return this.selectedArr.length > 0 && this.inputHovering && !this.disabled;
        },
        prePageStaus() {
          if (this.isShowFilterArr ? this.filterCurrentPage === 1 : this.currentPage === 1) {
            return true;
          }
          return false;
        },
        nextPageStaus() {
          const len = Math.ceil(this.list.length / this.pageSize);
          if (len === 0) return true;
          if (this.isShowFilterArr ? this.filterCurrentPage === len : this.currentPage === len) {
            return true;
          }
          return false;
        }
      },
      watch: {
        selectedArr(val) {
          const arr = val.map(item => {
            return item[this.listKey];
          });
          this.$emit('input', arr);
        },
        value(val, oldVal) {
          if (!valueEquals(val, oldVal)) {
            this.selectedArr = [];
            this.optionArr.forEach(item => {
              if (this.selectAll || val.includes(item[this.listKey])) {
                item.selected = true;
                this.selectedArr.push(item);
              } else {
                item.selected = false;
              }
            });
          }
        },
        options() {
          this.optionArr = this.initOptions();
          // 重置默认选中
          this.selectedArr = [];
          this.optionArr.forEach(item => {
            if (this.selectAll || this.value.includes(item[this.listKey])) {
              this.selectedArr.push(item);
            }
          });
          // 重置分页
          this.currentPage = 1;
          this.filterCurrentPage = 1;
        }
      },
      mounted() {
        // 默认选中
        this.optionArr.forEach(item => {
          if (this.selectAll || this.value.includes(item[this.listKey])) {
            this.selectedArr.push(item);
          }
        });
      },
      methods: {
        initOptions() { // 初始化选项数组
          return this.options.map((item, i) => {
            return {
              isShow: i < this.column * 4,
              _isShow: false,
              selected: this.selectAll || this.value.includes(item[this.props['value'] || 'value']),
              ...item
            };
          });
        },
        deleteTag(item) { // 删除当前tag
          if (this.disabled) return;
          this.selectedArr.some((v, i) => {
            if (v[this.listKey] === item[this.listKey]) {
              item.selected = false;
              this.selectedArr.splice(i, 1);
              return true;
            }
          });
        },
        handleSearch() { // 搜索过滤
          if (this.queryVal === '') { // 输入框清空时
            this.filterArr = [];
            return;
          }
          console.log(this.queryVal);
          // 搜索前清除之前搜索的
          this.filterArr = [];
          // 重置搜索数组分页
          this.filterCurrentPage = 1;
          let num = 0;
          this.optionArr.forEach(item => {
            if (item[this.listVal].indexOf(this.queryVal) !== -1) { // 如果like 输入值
              item._isShow = num < this.pageSize; // 只展示一页的结果
              this.filterArr.push(item);
              num++;
            }
          });
        },
        clickSelectInput() { // 点击输入框
          if (this.disabled) return;
          this.visible = !this.visible;
        },
        selectOptionClick(item, index) { // 单击check
          item.selected = !item.selected;
          // 如果已经选过
          if (this.selectedArr.some(v => v[this.listKey] === item[this.listKey])) {
            this.deleteTag(item);
          } else {
            this.selectedArr.push(item);
          }
        },
        checkAll() { // 全选
          this.selectedArr = [];
          this.optionArr.forEach(item => {
            item.selected = true;
            this.selectedArr.push(item);
          });
        },
        cancelCheckAll() { // 取消全选
          if (this.disabled) return;
          this.optionArr.forEach(item => {
            item.selected = false;
          });
          this.selectedArr = [];
        },
        prePage() { // 上一页
          if (this.isShowFilterArr) { // 搜索展示时
            this.changeFilterPageShow(false);
            this.filterCurrentPage--;
            this.changeFilterPageShow(true);
          } else {
            this.changePageShow(false);
            this.currentPage--;
            this.changePageShow(true);
          }
        },
        nextPage() { // 下一页
          if (this.isShowFilterArr) { // 搜索展示时
            this.changeFilterPageShow(false);
            this.filterCurrentPage++;
            this.changeFilterPageShow(true);
          } else {
            this.changePageShow(false);
            this.currentPage++;
            this.changePageShow(true);
          }
        },
        changePageShow(isOrNo) { // 改变当前页状态
          const num = (this.currentPage - 1) * this.pageSize;
          const num2 = num + this.pageSize;
          for (let index = num; index < num2; index++) {
            if (this.optionArr[index]) this.optionArr[index].isShow = isOrNo;
          }
        },
        changeFilterPageShow(isOrNo) { // 改变搜索当前页状态
          const num = (this.filterCurrentPage - 1) * this.pageSize;
          const num2 = num + this.pageSize;
          for (let index = num; index < num2; index++) {
            if (this.filterArr[index]) this.filterArr[index]._isShow = isOrNo;
          }
        },
        formatColumn() {
          // 展示多少列
          if (this.column === 1) {
            return {  '100%' };
          } else if (this.column === 2) {
            return {  '49%' };
          } else if (this.column === 3) {
            return {  '32%' };
          } else {
            return {  '24%' };
          }
        }
      }
    };
    </script>
    <style lang="less" scoped>
    .com-select {
      border-radius: 4px;
      border: 1px solid #DCDFE6;
      box-sizing: border-box;
      cursor: pointer;
      background: #ffffff;
      min- 230px;
      min-height: 32px;
      .com-select-input {
        display: flex;
        align-items: center;
        .one {
           10px;
        }
        .two {
          flex: 1;
          line-height: 29px;
          padding: 0 0 1px 0;
          /deep/ .el-tag {
            background-color: #f4f4f5;
            border-color: #e9e9eb;
            color: #909399;
            margin-right: 6px;
          }
          /deep/ .el-tag__close.el-icon-close {
            background-color: #C0C4CC;
          }
        }
        .three {
           30px;
        }
      }
    }
    .is-disabeled {
      cursor: not-allowed;
      background-color: #F5F7FA;
      border-color: #E4E7ED;
    }
    .el-select-dropdown {
      height: 280px;
      padding: 10px;
      border: 1px solid #E4E7ED;
      border-radius: 4px;
      box-shadow: 1px 2px 6px 0px #7d7d7d;
      box-sizing: border-box;
      cursor: default;
      .com-select-body {
        margin-top: 6px;
        height: 178px;
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        align-content: flex-start;
        .com-option {
          //  32%;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          color: #797D82;
          // background-color: rgb(240, 248, 250);
          border: 1px solid #dcdfe6;
          height: 32px;
          line-height: 32px;
          box-sizing: border-box;
          position: relative;
          text-align: center;
          margin-bottom: 10px;
          cursor: pointer;
          &:hover {
            border-color: #409EFF;
            color: #409EFF;
          }
        }
        // 选中样式
        .selected {
          border-color: #409EFF;
          &::after{
            content: '';
             15px;
            height: 14px;
            background: url("~@/assets/image/checked.png") no-repeat 0 0;
            position: absolute;
            right: 0;
            bottom: 0;
          }
        }
        .com-select-nodata {
          color: #C0C4CC;
           100%;
          text-align: center;
        }
      }
      // 分页样式
      .com-footer-page {
        display: flex;
        justify-content: space-between;
      }
    }
    </style>

    select-down.vue文件

    <template>
      <div
        class="el-select-dropdown el-popper"
        :style="{  width }">
        <slot></slot>
      </div>
    </template>
    
    <script>
    export default {
      name: 'MySelectDropdown',
      data() {
        return {
           ''
        };
      },
      mounted() {
        this.width = this.$parent.$el.clientWidth + 'px';
        window.addEventListener('resize', this.resizeWidth);
      },
      beforeDestroy() {
        window.removeEventListener('resize', this.resizeWidth);
      },
      methods: {
        resizeWidth() {
          this.width = this.$parent.$el.clientWidth + 'px';
        }
      }
    };
    </script>
  • 相关阅读:
    有用的java工具
    AOP在大规模软件开发项目中的应用(图)
    java并发编程实践笔记
    深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题
    JVM相关问答
    软件架构设计的六大原则
    JVM 运行时数据区域
    JVM 类加载过程
    JVM 垃圾回收算法
    Memcached内存分配优化及使用问题
  • 原文地址:https://www.cnblogs.com/bobo1/p/14998508.html
Copyright © 2011-2022 走看看