vue 封装搜索查询组件

实现一:

 一、组件 search.vue 

<template>
  <div class="search-area">
    <!-- <div class="search-area__container" :style="{height:`${contentHeight}px`, 'transition-duration': duration }" :class="{ limitHeight: limitHeight && itemLen > splitNum }"> -->
    <div class="search-area__container" :style="{'transition-duration': duration }" :class="{ limitHeight: limitHeight && itemLen > splitNum }">
      <div ref="content" class="search-area__content">
        <slot />
      </div>
    </div>
    <div class="search-area__btn">
      <el-button type="primary" icon="el-icon-search" @click="$emit('search')">查 询</el-button>
      <el-button class="btn-theme" icon="el-icon-refresh-left" @click="$emit('clear')">重 置</el-button>
      <el-button v-if="itemLen > splitNum" class="btn-theme" :icon="limitHeight ? 'el-icon-arrow-down' : 'el-icon-arrow-up'" @click="searchMore">高级查询</el-button>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'Search',
    props: {
      splitNum: {
        type: Number,
        default: 3
      },
      twoCol: {
        type: Array,
        default: () => {
          return []
        }
      },
      limitHeightParam: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        instanceTemCom: null,
        contentHeight: 0,
        duration: 0,
        // limitHeight: true,
        limitHeight: this.limitHeightParam,
        itemLen: 0,
        labelWidth: 95
      }
    },
    mounted() {
      this.initSettings()
      const height = this.$refs.content.scrollHeight < 40 ? 40 : this.$refs.content.scrollHeight
      this.contentHeight = height + 10
      this.duration = (this.contentHeight + 10) * 0.7 + 'ms'

      const hasChildNodesArr = []
      const childNodesArr = this.$refs.content.childNodes
      childNodesArr?.forEach((item, index) => {
        if (item?.childNodes[0]) {
          hasChildNodesArr.push(item?.childNodes[0])
        }
      })
      this.itemLen = hasChildNodesArr?.length || 0

    },
    created() {
      // this.itemLen = this.$slots.default.length
    },
    methods: {
      initSettings() {
        const len = this.$refs.content.childNodes.length
        const notMarginIndex = len - len % this.splitNum - 1

        let fNum = 0
        const splitMap = {
          1: 'one-in-line',
          2: 'two-in-line',
          3: 'three-in-line',
          4: 'four-in-line'
        }
        Array.from(Array(len)).forEach((item, index) => {
          if (this.$refs.content.childNodes[index].childNodes[0]) {
            fNum = Math.max(fNum, this.$refs.content.childNodes[index].childNodes[0].innerText.length)
          }

          // fNum = Math.max(fNum, this.$refs.content.childNodes[index].childNodes[0].innerText.length)
        })
        Array.from(Array(len)).forEach((item, index) => {
          if (this.$refs.content.childNodes[index].childNodes[0]) {
            this.$refs.content.childNodes[index].childNodes[0].style.width = `${fNum * 14}px`
            this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ` ${splitMap[this.splitNum]}`).trim()
          }

          // this.$refs.content.childNodes[index].childNodes[0].style.width = `${fNum * 12}px`
          // this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ` ${splitMap[this.splitNum]}`).trim()

          if (this.twoCol.length && this.twoCol.includes(index)) {
            this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ' two-col').trim()
          } else {
            if (index <= notMarginIndex && this.$refs.content.childNodes[index]) {
              this.$refs.content.childNodes[index].className = (this.$refs.content.childNodes[index].className + ' m-b-10').trim()
            }
          }
        })
      },
      searchMore() {
        this.contentHeight = this.$refs.content.scrollHeight + 10
        this.limitHeight = !this.limitHeight
        this.$emit('clickSearchMore')
      }
    }
  }
</script>

<style lang="scss" scoped>
  .search-area {
    display: flex;
    margin-bottom: 15px;
    .search-area__container {
      display: flex;
      flex-grow: 1;
      overflow: hidden;
      transition: height .3s ease-in-out;

      // transition-property: height;
      // transition-duration: .3s;
      // transition-timing-function: linear;
      // transition: height .3s ease;
      // transform: scale(1);
      // transition: transform 1s linear;

      &.limitHeight {
        height: 40px !important;
      }
    }

    .search-area__content {
      flex-wrap: wrap;
      display: flex;
      width: 100%;
      // font-size: 12px;
      font-size: 14px;

      > div {
        display: flex;
        align-items: center;
        padding-right: 20px;
        box-sizing: content-box;

        &.one-in-line {
          flex-basis: 100%;
        }

        &.two-in-line {
          flex-basis: calc(50% - 20px);
        }

        &.three-in-line {
          flex-basis: calc(33.3% - 20px);
        }

        &.four-in-line {
          flex-basis: calc(25% - 20px);
        }

        &.two-col {
          flex-basis: calc(66.6% - 20px);
        }

        &.m-b-10 {
          margin-bottom: 8px;
        }

        > span {
          flex-shrink: 0;
          text-align: right;
          margin-right: 12px;
        }
      }

      .el-select {
        width: 100%;
      }

      .el-range-editor.el-input__inner {
        width: 100%;
      }
    }

    .search-area__btn{
      display: flex;
      height: 32px;
      .btn-theme {
        border: 1px solid #e0e2f0;
      }
    }
  }
</style>

 二、组件使用

<template>
    <div class="searchBox">
        <Search
          :key="boxType"
          v-show="showSearch"
          label-width="100"
          :limit-height-param="false"
          @search="handleQuery"
          @clear="resetQuery"
        >
          <div>
            <span class="label">公司</span>
            <el-select v-model="queryParams.companyCode1" placeholder="请选择公司" clearable filterable default-first-option size="small">
              <el-option
                v-for="dict in companyCodeOptions"
                :key="dict.dictValue"
                :label="dict.dictLabel"
                :value="dict.dictValue"
              />
            </el-select>
          </div>
          <div v-if="iscode">
            <span class="label">公司</span>
            <el-select v-model="queryParams.companyCode2" placeholder="请选择公司" clearable filterable default-first-option size="small">
              <el-option
                v-for="dict in companyCodeOptions"
                :key="dict.dictValue"
                :label="dict.dictLabel"
                :value="dict.dictValue"
              />
            </el-select>
          </div>
          <div v-if="iscode">
            <span class="label">公司</span>
            <el-select v-model="queryParams.companyCode3" placeholder="请选择公司" clearable filterable default-first-option size="small">
              <el-option
                v-for="dict in companyCodeOptions"
                :key="dict.dictValue"
                :label="dict.dictLabel"
                :value="dict.dictValue"
              />
            </el-select>
          </div>
          <div v-if="iscode">
            <span class="label">公司</span>
            <el-select v-model="queryParams.companyCode4" placeholder="请选择公司" clearable filterable default-first-option size="small">
              <el-option
                v-for="dict in companyCodeOptions"
                :key="dict.dictValue"
                :label="dict.dictLabel"
                :value="dict.dictValue"
              />
            </el-select>
          </div>
        </Search>
    </div>
</template>

<script>
  export default {
    data() {
      return {
        // 查询参数
        queryParams: {
          pageNum: 1,
          pageSize: 20,
          companyCode1: null,
          companyCode2: null,
          companyCode3: null,
          companyCode4: null,
        },
        companyCodeOptions: [],
        // 显示搜索条件
        showSearch: true,
        // boxType改变 searchBox 重新加载
        boxType: '',
        iscode: false,
      }
    },
    methods: {
      /** 搜索按钮操作 */
      handleQuery() {
        this.queryParams.pageNum = 1
        this.getList()
      },
      /** 重置按钮操作 */
      resetQuery() {
        this.queryParams = this.$options.data().queryParams
        this.handleQuery()
      },
    }
  }
</script>

实现二:


<script>
  export default {
    name: 'Search',
    props: {
      labelWidth: {
        type: [String, Number],
        default: 'auto'
      }
    },
    data() {
      return {
        isExpand: false,
        conditionNum: 0
      }
    },
    watch: {
      conditionNum(val) {
        this.$nextTick(this.initSettings)
      }
    },
    updated() {
      const len = this.$slots.default.filter(item => item.tag).length
      if (this.conditionNum !== len) { this.conditionNum = len }
    },
    methods: {
      initSettings() {
        const defaultSearchList = this.$refs.defaultSearch.childNodes
        const moreSearchList = this.$refs.moreSearch ? this.$refs.moreSearch.childNodes : []
        const allSearchList = [...defaultSearchList, ...moreSearchList].filter(item => item.nodeType !== 8)

        allSearchList.forEach((item, index) => {
          const childrenList = item.childNodes
          if (childrenList[0] && childrenList[0].tagName && childrenList[0].tagName.toLowerCase() === 'span') {
            childrenList[0].style.width = isNaN(parseFloat(this.labelWidth)) ? 'auto' : `${parseFloat(this.labelWidth)}px`
          }

          if (index > 3) {
            const lastLineIndex = allSearchList.length % 4
            item.className = item.className.replace(/\s*no-margin-bottom/g, '')
            if (allSearchList.length - (lastLineIndex || 4) <= index) {
              item.className = (item.className + ' no-margin-bottom').trim()
            }
          }
        })
      },
      searchBtn() {
        this.$emit('search')
      }
    },
    render(h) {
      const slotList = this.$scopedSlots.default()

      // this.moreSearchHeight = 0

      return (
      <div class='search-area'>
        <div class='search__default' ref='defaultSearch'>
          { [...slotList.slice(0, 3), ...Array(3).fill(h('div'))].slice(0, 3) }
          <div class='search-area__btn'>
            <el-button type='primary' size='small' class='btn-search' onClick={ this.searchBtn }>搜索</el-button>
            <el-button size='small' onClick={() => this.$emit('clear')}>重置</el-button>
            {
              slotList.length > 3
                ? <el-button size='small' onClick={ () => { this.isExpand = !this.isExpand } }>
                    高级查询
                    <i class={ this.isExpand ? 'el-icon-arrow-up' : 'el-icon-arrow-down' }></i>
                  </el-button>
                : ''
            }
          </div>
        </div>
        { slotList.length > 3
          ? <div class={{ 'search__more': true, 'no-expand': !this.isExpand }} style={{ maxHeight: '350px' }} ref='moreSearch'>
            { slotList.slice(3) }
            </div>
          : ''
        }
      </div>
    )
    }
  }
</script>

<style lang="scss" scoped>
  .search-area {
    overflow: hidden;
    margin-bottom: 20px;
  }
  .search__default,
  .search__more {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    width: 100%;
    font-size: 12px;

    > div {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      width: calc((100% - 45px) / 4);
      margin-bottom: 8px;
      box-sizing: border-box;

      &.no-margin-bottom {
        margin-bottom: 0;
      }

      &:not(:nth-of-type(4n)) {
        margin-right: 15px;
      }

      > span {
        flex-shrink: 0;
        text-align: right;
      }
    }
  }

  .search__default {
    min-height: 32px;
  }

  .search__more {
    transition: all .3s ease-in-out;

    &.no-expand {
      max-height: 0 !important;
    }
  }

  .search-area__btn{
    display: flex;
    height: 32px;
  }

</style>

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值