• vue 自定义下拉选择table组件


    element ui的select组件对大量数据的渲染性能差,自己用table+input跟着捣鼓一下。。参考select源码但驾驭不住。(目前就抄了css)

    呸,自己实现,能用就行。(菜是原罪)

    效果:

    代码:

    <template>
      <div :id="createdId">
        <div class="input-select el-input__inner" v-if="showSelect">
          <div class="tags">
            <el-tag v-for="(item, index) in multipleSelectionTags" :key="index" closable @close="handleCloseTag(item)" size="small"
              type="info" effect="plain">{{item[keywordKey] || ''}}</el-tag>
            <input type="text" ref="selectInput" :value="value" :placeholder="placeholderForTag" @focus="onfocus"
              @input="changeValue($event.target.value)">
            <i class="el-icon-arrow-down select-down" :class="visible&&'rotate180'"></i>
          </div>
        </div>
        <el-input v-else :value="value" @input="changeValue" @focus="onfocus" @blur="onblur" clearable
          :placeholder="placeholder" ref="inputValue"></el-input>
        <div class="el-picker-panel" :style="pStyle" v-show="visible" ref="elcombogrid">
          <div class="table-container">
            <el-table v-loading="listLoading" :data="list" @row-click="rowClick" stripe size="mini"
              element-loading-text="Loading" ref="comboGridTable" fit border highlight-current-row
              @selection-change="handleSelectionChange" @select="handleSingelSelectionChange">
              <el-table-column type="selection" v-if="showSelect" width="55" align="center" />
              <el-table-column v-if="showIndex" label="序号" type="index" align="center" width="50"></el-table-column>
              <el-table-column v-for="item in columns" :type="item.type" :key="item.key" :label="item.label"
                :prop="item.key" :align="item.align" :width="item.width" :header-align="item.headerAlign">
                <template slot-scope="scope">
                  <span>{{ scope.row[item.key] }}</span>
                </template>
              </el-table-column>
            </el-table>
            <el-pagination v-show="pagination" small :total="total" :page-size="5" layout="prev, pager, next, total"
              @current-change="changePage" />
          </div>
        </div>
      </div>
    </template>
    <script>
    import request from '@/utils/request';
    
    export default {
      name: "el-combo-grid",
      props: {
        placeholder: { type: String },
        value: { type: String },
        requestConfig: {
          default: () => {
            return {
              url: '',
              method: 'get'
            }
          }
        },
        columns: { type: Array },
        panelStyle: { type: String },
        keywordKey: { type: String },
        showIndex: { type: Boolean },
        pagination: { type: Boolean, default: true },
        otherParams: { default: () => { } },
        showSelect: { default: false }
      },
      data() {
        return {
          visible: false,
          pStyle: '500px',
          list: [],
          total: 0,
          listLoading: true,
          listQuery: {
            pageNum: 1,
            pageSize: 5
          },
          keyword: '',
          createdId: '0',
          multipleSelection: [],
          multipleSelectionTags: [],
          placeholderForTag: ''
        }
      },
      mounted() {
        this.createdId = String(new Date().getTime()) // 给个随机id 判断是否clickoutside
        this.placeholderForTag = this.placeholder
      },
      methods: {
        changePage(cur) {
          this.listQuery.pageNum = cur
          this.getList()
        },
        changeValue(val) {
          this.$emit('input', val)//向上级传送数据
          this.keyword = val
          this.listQuery.pageNum = 1
          this.getList()
        },
        onfocus(el) {
          this.pStyle = this.panelStyle + ';position:absolute;z-index:999999;'
          this.visible = true
          this.keyword = el.target.value
          document.removeEventListener('click', this.clickOutFn)
          document.addEventListener('click', this.clickOutFn)
          this.getList()
        },
        onblur(el) {
        },
        getList() {
          for (let key in this.otherParams) {
            this.listQuery[key] = this.otherParams[key]
          }
          if (this.pagination) {
            this.listQuery[this.keywordKey] = this.keyword
          } else {
            if (this.keyword) {
              this.listQuery[this.keywordKey] = this.keyword
            } else {
              this.listLoading = false
              return //如果不分页,无keyword不查询数据(避免大数据量)
            }
          }
          this.listLoading = true
          this.multipleSelection.length = 0
          this.queryTableData(this.listQuery).then(response => {
            this.list = response.data.rows
            this.total = response.data.total
            this.listLoading = false
            this.$nextTick(() => {
              // multipleSelectionTags 引用问题,无法与table数据全等。。。
              let ids = this.multipleSelectionTags.map(item => item.id)
              this.list.length && this.list.forEach((item, index) => {
                if (ids.includes(item.id)) {
                  this.$refs.comboGridTable.toggleRowSelection(item)
                }
              })
            })
          })
        },
        queryTableData(params) {
          const reqObj = {
            url: this.requestConfig.url,
            method: this.requestConfig.method
          }
          let p = this.requestConfig.method === 'get' ? 'params' : 'data'
          reqObj[p] = params
          return request(reqObj)
        },
        rowClick: function (row, column, event) {
          if (this.showSelect) {
            this.$refs.comboGridTable.toggleRowSelection(row);
            this.$emit('input', '')
          } else {
            this.visible = false
            this.$emit('row-select-event', row, column, event)
            this.$emit('input', row[this.keywordKey])
            document.removeEventListener('click', this.clickOutFn)
          }
        },
        clickOutFn(e) {
          if (e.path.some(item => item.id === this.createdId)) return
          this.visible = false
          document.removeEventListener('click', this.clickOutFn)
        },
        /**
         * 根据选择与上次的选择进行对比,处理tags
         * todo 聚焦状态。。。触发太多,暂不处理
         */
        handleSelectionChange(val) {
          if (this.multipleSelection.length === 0 && val.length === 0) return
          if (val.length > this.multipleSelection.length) {
            for (let item of val) {
              if (!this.multipleSelection.some(mitem => mitem.id === item.id)) {
                let ids = this.multipleSelectionTags.map(item => item.id)
                !ids.includes(item.id) && (this.multipleSelectionTags = this.multipleSelectionTags.concat(item))
              }
            }
          } else {
            for (let item of this.multipleSelection) {
              if (!val.some(mitem => mitem.id === item.id)) {
                let index = this.multipleSelectionTags.findIndex(mitem => mitem.id === item.id)
                index > -1 && this.multipleSelectionTags.splice(index, 1)
              }
            }
          }
          this.multipleSelection = val
          this.placeholderForTag = this.multipleSelectionTags.length ? '' : this.placeholder
          this.$emit('getSelect', this.multipleSelectionTags)
          // this.$refs.selectInput.focus() todo..
        },
        /**
         * 处理单个复选框选择
         */
        handleSingelSelectionChange() {
          this.$emit('input', '')
        },
        handleCloseTag(item) {
          this.multipleSelectionTags.splice(this.multipleSelectionTags.findIndex(mitem => mitem.id === item.id), 1)
          this.$refs.comboGridTable.toggleRowSelection(item)
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .input-select {
      display: inline-block;
      position: relative;
       100%;
      height: auto;
      min- 240px;
      -webkit-appearance: none;
      background-color: #fff;
      background-image: none;
      border-radius: 4px;
      border: 1px solid #dcdfe6;
      box-sizing: border-box;
      color: #606266;
      font-size: inherit;
      outline: none;
      padding: 0 15px;
      transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
      .select-down {
        position: absolute;
        top: 50%;
        right: 10px;
        transform: translateY(-50%);
        transition: all 0.5s;
        &.rotate180 {
          transform: translateY(-50%) rotate(180deg);
        }
      }
      .tags {
        min-height: 36px;
        flex-wrap: wrap;
        line-height: normal;
        white-space: normal;
        z-index: 1;
    
        display: inline-flex;
        align-items: center;
        flex-wrap: wrap;
        /deep/ .el-tag {
          margin-right: 3px;
          margin-bottom: 1px;
        }
        input {
          flex: 1;
          border: none;
          outline: none;
          padding: 0;
          color: #666;
          font-size: 14px;
          appearance: none;
          height: 28px;
          background-color: transparent;
          &::-webkit-input-placeholder {
            color: #c0c4cc;
          }
          &::-moz-placeholder {
            /* Mozilla Firefox 19+ */
            color: #c0c4cc;
          }
          &:-moz-placeholder {
            /* Mozilla Firefox 4 to 18 */
            color: #c0c4cc;
          }
          &:-ms-input-placeholder {
            /* Internet Explorer 10-11 */
            color: #c0c4cc;
          }
        }
      }
    }
    </style>

    调用:

    <inputTable  v-model="form.deviceName"
                              v-if="open" // 用v if 处理各种疑难杂症
                              placeholder="请选择"
                              :requestConfig="{url: '/api/as/my/list', method: 'get'}"
                              :pagination="true" // 是否分页
                              :columns="myColumns" //
                              :showIndex="true" // 显示序号
                              keywordKey="name" // 请求的keyword
                              :panelStyle="'550px'" // 样式
                              :otherParams="{deviceBind: 1}" // 其他请求参数
                              :showSelect="true" // 是否多选
                              @getSelect="getRowsSelect" // 返回的多选
                             @row-select-event="getRowSelect" // 单行点击事件
                            />
    
    myColumns:[{label:'asdasd', key: 'Name'},{label:'6666', key: 'code'}]
    
    getRowSelect(row, column, event) {
         // dosomething
     },
    getRowsSelect(arr) {
                  this.form.ids= arr.map(item=>item.id)
                },
                        

    参考地:https://blog.csdn.net/raozhangqiang/article/details/108715580

  • 相关阅读:
    【转载】openCV轮廓操作
    求两个已排序数组的中位数
    朴素贝叶斯分类
    Different Ways to Add Parentheses
    QSerialPort
    opencv鼠标绘制直线 C++版
    Word Break
    C++中 指针 与 引用 的区别
    敲入url到浏览器后会发生什么
    Sort List 分类: leetcode 算法 2015-07-10 15:35 1人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/wilsunson/p/14217126.html
Copyright © 2020-2023  润新知