使用vue3+ts封装一个自动补全输入框Autocomplete组件

创建一个名为 Autocomplete.vue 的文件,在这个组件中,使用了 Vue 3 的 Composition API,包括 refwatchonMounted 等。组件接收 placeholderdebounceclearable 作为 props,并根据这些 props 来渲染输入框和下拉菜单

<template>
  <div class="autocomplete">
    <input
      v-model="query"
      :placeholder="placeholder"
      @input="handleInput"
      @focus="handleFocus"
      @blur="handleBlur"
      @keydown.delete="handleClear"
    />
    <div v-if="showDropdown" class="dropdown">
      <div
        v-for="(item, index) in filteredItems"
        :key="index"
        @click="handleSelect(item)"
      >
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, watch, onMounted } from 'vue';
import axios from 'axios';

interface Props {
  placeholder?: string;
  debounce?: number;
  clearable?: boolean;
}

export default defineComponent({
  props: {
    placeholder: {
      type: String,
      default: '请输入内容'
    },
    debounce: {
      type: Number,
      default: 300
    },
    clearable: {
      type: Boolean,
      default: true
    }
  },
  setup(props: Props) {
    const query = ref('');
    const showDropdown = ref(false);
    const items = ref<string[]>([]);
    const filteredItems = ref<string[]>([]);
    const timer = ref<number | null>(null);

    const handleInput = () => {
      if (timer.value) {
        clearTimeout(timer.value);
      }
      timer.value = setTimeout(fetchData, props.debounce);
    };

    const handleFocus = () => {
      showDropdown.value = true;
    };

    const handleBlur = () => {
      setTimeout(() => {
        showDropdown.value = false;
      }, 200);
    };

    const handleClear = () => {
      if (props.clearable) {
        query.value = '';
        showDropdown.value = false;
      }
    };

    const handleSelect = (item: string) => {
      query.value = item;
      showDropdown.value = false;
    };

    const fetchData = async () => {
      if (query.value.length > 0) {
        try {
          const response = await axios.get(`/api/search?query=${query.value}`);
          items.value = response.data.items;
          filteredItems.value = items.value.filter(item =>
            item.toLowerCase().includes(query.value.toLowerCase())
          );
          showDropdown.value = true;
        } catch (error) {
          console.error(error);
        }
      } else {
        showDropdown.value = false;
      }
    };

    onMounted(fetchData);

    watch(query, fetchData);

    return {
      query,
      showDropdown,
      filteredItems,
      handleInput,
      handleFocus,
      handleBlur,
      handleClear,
      handleSelect
    };
  }
});
</script>

<style scoped>
.autocomplete {
  position: relative;
  width: 300px;
}

input {
  width: 100%;
  padding: 8px;
  box-sizing: border-box;
}

.dropdown {
  position: absolute;
  width: 100%;
  border: 1px solid #ccc;
  background-color: #fff;
  z-index: 100;
  max-height: 200px;
  overflow-y: auto;
}

.dropdown div {
  padding: 8px;
  cursor: pointer;
}

.dropdown div:hover {
  background-color: #f0f0f0;
}
</style>

关注微信公众号温暖前端,不定期分享前端知识点和前端资料↓↓↓

你可能感兴趣的:(javascript,前端,vue.js)