vue3实现搜索项超过n行就折叠的思路详解

目录
  • 实现效果
  • 实现思路
  • 实现组件的布局
  • 事件绑定与事件销毁
  • 高度判断和图标的显示与隐藏
  • 完整代码
    • 布局
    • css代码
    • script
    • 组件使用
  • 总结

    我们在做列表查询的时候,会有很多查询项,如何实现超过n行查询项的时候自动折叠起来呢?

    实现效果

    实现思路

    • 实现组件的布局。
    • 绑定监听事件和销毁监听事件
    • 高度判断和图标的显示与隐藏

    实现组件的布局

    外层盒子(限制高度)、折叠的图标或者文字(用来显示和隐藏多余的行)、插槽(挖个坑给搜索行占位)。

    事件绑定与事件销毁

    需要绑定一个resize事件。resize事件是在窗口大小发生变化时就会触发。resize事件触发我们就要重新计算盒子查询项的高度,判断是否需要折叠或者显示。mounted生命周期触发计算组件实例高度。并计算查询项高度。resize事件要在组件销毁前的生命周期中进行销毁。不影响其他组件。

    高度判断和图标的显示与隐藏

    首先图标盒子绑定状态,用来显示和隐藏。 其次外层盒子需要设置一个高度临界点,即多大高度时不折叠,超过了这个高度就折叠。盒子高度需要你计算,比如,你需要4行不折叠,需要算出四行的高度并加上图标的高度。如果大于高度则显示图标、如果小于隐藏图标。

    完整代码

    布局

    <template>
      <div class="fold_box">
        <div
          class="fold_box_over"
          :style="{height: mainHeight > 0 ? mainHeight + 'px' : ''}"
          :class="{'fold_box_over_max': isOver}"
        >
          <div
            ref="foldBoxMain"
            class="fold_box_main"
          >
            <slot></slot>
          </div>
          <div
            v-show="isOverChange"
            class="fold_box_over_show"
          >
            <div
              class="fold_box_over_btn"
              @click="showOver"
            >
            <el-icon :class="{'fold_box_over_btn_rotate': !isOver}" :size="14">
                <ArrowDown />
            </el-icon>
    
            </div>
          </div>
        </div>
      </div>
    </template>

    css代码

    <style lang="less" scoped>
    .fold_box {
      width: 100%;
      .fold_box_over {
        overflow: hidden;
        position: relative;
        transition: all 0.4s ease;
      }
      .fold_box_over_max {
        height: 159px !important;
      }
      .fold_box_main {
        width: 100%;
      }
      .fold_box_over_show {
        height: 15px;
        position: absolute;
        width: 100%;
        background-color: #fff;
        bottom: 0;
        left: 0;
      }
      .fold_box_over_btn {
        width: 20px;
        height: 15px;
        cursor: pointer;
        text-align: center;
        line-height: 15px;
        margin: 0 auto;
        el-icon svg{
          font-weight: bold;
          transition: all 0.4s ease;
        }
        &:hover {
          color: #00caab;
        }
      }
      .fold_box_over_btn_rotate svg{
        transform: rotate(180deg);
      }
    }
    </style>

    script

    <script>
    import { reactive, toRefs, ref,onMounted,onBeforeUnmount,getCurrentInstance } from "vue";
    export default {
      setup() {
        const state = reactive({
          boxWidth: 0,
          mainHeight: 0,
          isOver: false,
          isOverChange: false
        });
        const { ctx } = getCurrentInstance()
        const changeSize = () => {
          let el = ctx.$el
          state.boxWidth = el.offsetWidth
          countMainHeight()
        }
        window.addEventListener('resize', changeSize)
        const countMainHeight = () => {
          if (ctx.$refs['foldBoxMain']) {
            let el= ctx.$refs['foldBoxMain']
            state.mainHeight = el.offsetHeight + 15
            if (state.mainHeight > 129) {
                state.isOverChange = true
                state.isOver = true
              } else {
                state.isOverChange = false
                state.isOver = false
              }
            }
        }
        onMounted(() => {
          changeSize()
        })
        onBeforeUnmount(()=> {
          window.removeEventListener('resize', changeSize)
        })
        const showOver = () => {
           state.isOver = !state.isOver
        }
        return {
          ...toRefs(state),
          changeSize,
          countMainHeight,
          showOver
        };
      },
    };
    </script>

    组件使用

    <template>
      <FoldBox ref="foldBox">
        <div class="item" v-for="(item,index) in boxList" :key="index">{{item}}</div>
      </FoldBox>
    </template>
    <script>
    import { reactive, toRefs, ref } from "vue";
    import FoldBox from './FoldBox.vue'
    export default {
      components:{
        FoldBox
      },
      setup() {
        const state = reactive({
          boxList: [1,2,3,4,5]
        });
        return {
          ...toRefs(state),
        };
      },
    };
    </script>
    <style scoped>
    .item {
      height: 30px;
      margin: 6px;
      background-color: skyblue;
    }
    </style>

    总结

    • resize事件的使用
    • vue3中getCurrentInstance获取组件实例以及获取ref属性的使用
    • vue3的生命周期onMounted、onBeforeUnmount、setup的使用
    • css3 transition和transform的使用
    • offsetHeight和offsetWidth的使用

    本文转自网络,如有侵权请联系客服删除。