展开收起的搜索框动画的实现,基于elemenUI

219 阅读1分钟

背景

开发中有时会遇到搜索框没有合适位置摆放的情况,这时就需要通过一个按钮进行展开的搜索框。

  • 效果如下

GIF 2024-7-17 8-30-21.gif

点击按钮时展开搜索框,输入框失焦后关闭搜索框。

实现过程

废话不多说直接上代码

<template>
  <div ref="searchWrapper" class="search-wrapper">
    <transition name="expand" @after-leave="handleAfterLeave">
      <el-input
        v-show="isActive"
        ref="inputRef"
        v-model="searchText"
        placeholder="请输入"
        class="search-input"
        @keyup.enter.native="handleSearch"
      >
        <el-button
          slot="append"
          type="primary"
          icon="el-icon-search"
          circle
          @click="handleSearch"
        />
      </el-input>
    </transition>
    <transition name="fade">
      <el-button
        v-show="isButtonVisible"
        class="open-search"
        type="primary"
        icon="el-icon-search"
        @click="toggleSearch"
      />
    </transition>
  </div>
</template>

<script>
export default {
  name: "SearchButton",
  props: {
    value: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      isButtonVisible: true,
      isActive: false
    };
  },
  computed: {
    searchText: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit("input", value);
      }
    }
  },
  mounted() {
    document.addEventListener("click", this.handleClickOutside);
  },
  beforeDestroy() {
    document.removeEventListener("click", this.handleClickOutside);
  },
  methods: {
    handleSearch() {
      this.$emit("search");
    },
    /**
     * 点击外部区域关闭搜索框
     */
    handleClickOutside(event) {
      if (this.isActive && !this.$refs.searchWrapper.contains(event.target)) {
        this.toggleSearch();
        this.searchText = "";
      }
    },
    handleAfterLeave() {
      this.isButtonVisible = true;  // 当expand动画结束后,显示按钮
    },
    toggleSearch() {
      this.isActive = !this.isActive;
      if (this.isActive) {
        this.$nextTick(() => {
          this.$refs.inputRef.focus();
        });
        this.isButtonVisible = false;  // 当输入框激活时,不显示按钮
      }
    }
  }
};
</script>

<style lang="less" scoped>
.search-wrapper {
  border-radius: 10px;
  width: 233px;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;

  /deep/ .el-input__inner {
    border-radius: 30px;
    height: 45px;
    padding: 0 45px 0 15px;
  }

  /deep/ .el-input-group__append {
    color: #fff;
    border: none;
    padding: 0;
    background-color: transparent;

    .el-button {
      margin: -8px -43px;
      border-radius: 50%;
      padding: 12px;
    }
  }

  /deep/ .el-input__suffix {
    right: 45px;
  }

  .open-search {
    border-radius: 3px;
    position: absolute;
  }
}

.expand-enter-active,
.expand-leave-active {
  transition: transform 0.4s ease-in-out, opacity 0.4s ease-in-out;
  transform-origin: right center;
}

.expand-enter,
.expand-leave-to {
  transform: scaleX(0.2);
  opacity: 0;
}

.expand-enter-to,
.expand-leave {
  transform: scaleX(1);
  opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
  transition: transform 0.1s ease-in-out;
}

.fade-enter,
.fade-leave-to {
  transform: scaleX(0);
}
</style>