封装el-autocomplete,接口调用

组件

<template>
  <el-autocomplete
    v-model="selectedValue"
    :fetch-suggestions="fetchSuggestions"
    :placeholder="placeholder"
    @select="handleSelect"
    clearable
    v-bind="$attrs"
  />
</template>

<script lang="ts" setup>
import { ref, computed, onMounted, withDefaults } from 'vue'
import type { AutocompleteProps, AutocompleteEmits } from 'element-plus'

interface AutocompleteItem {
  value: string
  [key: string]: any
}

interface Props {
  placeholder?: string
  debounce?: number
  apiFn?: (query: string) => Promise<AutocompleteItem[]> // 模拟接口函数
  localData?: AutocompleteItem[] // 本地数据
  filterFn?: (query: string, item: AutocompleteItem) => boolean // 自定义过滤函数
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: '请输入内容',
  debounce: 300,
  localData: () => [],
  filterFn: undefined
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'select', item: AutocompleteItem): void
}>()

const selectedValue = ref('')
const loading = ref(false)
const suggestions = ref<AutocompleteItem[]>([])
let timeout: number | undefined

// 默认过滤函数 - 开头匹配(不区分大小写)
const defaultFilter = (query: string) => {
  const lowerQuery = query.toLowerCase()
  return (item: AutocompleteItem) => 
    item.value.toLowerCase().startsWith(lowerQuery)
}

// 模拟接口获取数据
const mockApiFetch = async (query: string): Promise<AutocompleteItem[]> => {
  // 这里模拟API请求延迟
  await new Promise(resolve => setTimeout(resolve, 500))
  
  // 模拟数据
  const mockData = [
    { value: 'Vue', link: 'https://vuejs.org' },
    { value: 'React', link: 'https://reactjs.org' },
    { value: 'Angular', link: 'https://angular.io' },
    { value: 'Svelte', link: 'https://svelte.dev' },
    { value: 'TypeScript', link: 'https://www.typescriptlang.org' },
  ]
  
  // 模拟接口过滤
  return mockData.filter(item => 
    item.value.toLowerCase().includes(query.toLowerCase())
  )
}

// 获取建议列表
const fetchSuggestions = async (
  query: string, 
  cb: (arg: AutocompleteItem[]) => void
) => {
  clearTimeout(timeout)
  
  if (!query) {
    cb(props.localData)
    return
  }
  
  loading.value = true
  
  timeout = setTimeout(async () => {
    try {
      let results: AutocompleteItem[] = []
      
      if (props.apiFn) {
        // 使用传入的接口函数获取数据
        results = await props.apiFn(query)
      } else if (props.localData.length) {
        // 使用本地数据过滤
        const filter = props.filterFn 
          ? (item: AutocompleteItem) => props.filterFn!(query, item)
          : defaultFilter(query)
        results = props.localData.filter(filter)
      } else {
        // 使用默认模拟接口
        results = await mockApiFetch(query)
      }
      
      suggestions.value = results
      cb(results)
    } catch (error) {
      console.error('获取建议列表失败:', error)
      cb([])
    } finally {
      loading.value = false
    }
  }, props.debounce) as unknown as number
}

// 选择事件
const handleSelect = (item: AutocompleteItem) => {
  emit('update:modelValue', item.value)
  emit('select', item)
}

// 暴露方法
defineExpose({
  focus: () => {
    // 这里可以访问el-autocomplete的方法
    // 需要在实际使用时通过ref获取组件实例
  }
})
</script>

<style scoped>
.el-autocomplete {
  width: 100%;
}
</style>

基本用法(使用内置模拟接口)

<template>
  <CustomAutocomplete v-model="selectedValue" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import CustomAutocomplete from './CustomAutocomplete.vue'

const selectedValue = ref('')
</script>

使用自定义接口函数

<template>
  <CustomAutocomplete 
    v-model="selectedValue"
    :api-fn="fetchDataFromApi"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import CustomAutocomplete from './CustomAutocomplete.vue'

const selectedValue = ref('')

const fetchDataFromApi = async (query: string) => {
  // 这里可以替换为真实的API调用
  console.log('查询:', query)
  return [
    { value: `${query}-结果1`, id: 1 },
    { value: `${query}-结果2`, id: 2 }
  ]
}
</script>

自定义过滤逻辑

<template>
  <CustomAutocomplete 
    v-model="selectedValue"
    :local-data="techList"
    :filter-fn="customFilter"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import CustomAutocomplete from './CustomAutocomplete.vue'

const selectedValue = ref('')
const techList = ref([
  { value: 'Vue.js', category: 'frontend' },
  { value: 'React', category: 'frontend' },
  { value: 'Express', category: 'backend' }
])

const customFilter = (query: string, item: any) => {
  // 同时匹配value和category
  return item.value.toLowerCase().includes(query.toLowerCase()) || 
         item.category.toLowerCase().includes(query.toLowerCase())
}
</script>

下面的代码是干什么用的,请生成说明注释,同时还有什么改进: <template> <div class="app-container"> <el-card class="box-table"> <el-form :inline="true" class="demo-form-inline" :model="searchForm"> <el-form-item label="账号"> <el-input placeholder="请输入账号" v-model="searchForm.username"></el-input> </el-form-item> <el-form-item label="姓名"> <el-input placeholder="请输入姓名" v-model="searchForm.name"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSearch">查询</el-button> <el-button @click="handleAdd">新增</el-button> </el-form-item> </el-form> <el-table v-loading="listLoading" :data="list" element-loading-text="Loading" border fit highlight-current-row size="small"> <el-table-column align="center" label="ID" prop="id"></el-table-column> <el-table-column align="center" label="账号" prop="username"></el-table-column> <el-table-column align="center" label="姓名" prop="name"></el-table-column> <el-table-column align="center" label="性别" prop="gender"> <template slot-scope="scope"> <el-tag type="success" v-if="scope.row.gender == 1">男</el-tag> <el-tag type="danger" v-else>女</el-tag> </template> </el-table-column> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button> <el-popconfirm title="确定删除吗?" @confirm="deleteCofirm(scope.row)"> <el-button type="text" slot="reference" size="small">删除</el-button> </el-popconfirm> </template> </el-table-column> </el-table> <el-pagination class="page-box" background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageNum" :page-sizes="[10, 20]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </el-card> <!-- 添加/修改的弹框 --> <el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible"> <el-form label-position="left" :model="dialogForm" label-width="80px"> <el-form-item label="账号"> <el-input placeholder="请输入账号" v-model="dialogForm.username" autocomplete="off"></el-input> </el-form-item> <el-form-item label="密码"> <el-input type="password" placeholder="请输入密码" v-model="dialogForm.password" autocomplete="off"></el-input> </el-form-item> <el-form-item label="姓名"> <el-input placeholder="请输入姓名" v-model="dialogForm.name" autocomplete="off"></el-input> </el-form-item> <el-form-item label="性别"> <el-select v-model="dialogForm.gender" placeholder="请选择"> <el-option v-for="item in genderOptions" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="dialogConfirm">确 定</el-button> </div> </el-dialog> </div> </template> <script> import { findAdminPageAPI, // 导入查询管理员信息的 API addAdminAPI, // 导入新增管理员的 API modifyAdminAPI, // 导入修改管理员信息的 API removeAdminAPI, // 导入删除管理员的 API } from "@/api/admin"; export default { data() { return { list: null, // 管理员列表数据 listLoading: true, // 列表加载状态 pageSize: 10, // 每页显示条数 pageNum: 1, // 当前页码 total: 0, // 总条数 searchForm: {}, // 搜索表单数据 dialogTitle: "添加", // 弹框标题,默认为添加 dialogFormVisible: false, // 弹框显示状态 dialogForm: {}, // 弹框表单数据 genderOptions: [ // 性别选项 { label: '男', value: 1 }, { label: '女', value: 2 } ], }; }, created() { this.fetchData(); }, methods: { handleSizeChange(val) {//每页显示条数改变 this.pageSize = val; this.fetchData(); }, handleCurrentChange(val) {//当前页码改变 this.pageNum = val; this.fetchData(); }, handleSearch() {//点击搜索按钮 this.fetchData(); }, async fetchData() {//查询数据 this.listLoading = true; let response = await findAdminPageAPI( this.pageNum, this.pageSize, this.searchForm ); this.list = response.data.records; this.total = response.data.total; this.listLoading = false; }, handleAdd() {//点击新增按钮-显示弹框 this.dialogTitle = "新增"; this.dialogFormVisible = true; this.dialogForm = {gender: 1}; }, handleEdit(row) {//点击修改按钮-显示弹框 this.dialogTitle = "修改"; this.dialogFormVisible = true; this.dialogForm = { ...row }; }, async dialogConfirm() {//点击弹框确定按钮 let res = null; if (this.dialogTitle == "新增") { res = await addAdminAPI(this.dialogForm); } else { res = await modifyAdminAPI(this.dialogForm); } if (res.flag) { this.dialogFormVisible = false; } this.$message({ message: res.message, type: res.flag ? "success" : "error", }); this.fetchData(); }, async deleteCofirm(row) {//点击确定删除按钮 this.pageNum = 1; const res = await removeAdminAPI(row.id); this.$message({ message: res.message, type: res.flag ? "success" : "error", }); this.fetchData(); }, }, }; </script> <style lang="less" scoped> .page-box { margin-top: 20px; } </style>
06-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值