需求分析
- 展示切换动画
- 搜索框输入文字,自动发送请求
- 搜索结果展示
- 搜索状态维护
- 历史搜索展示,点击历史搜索后发送请求
- 历史搜索更多切换动画
- 效果

<script setup lang="ts">
import OpSearch from '@/components/OpSearch.vue'
import { ref } from 'vue'
import { fetchSearchData } from '@/api/search'
import type { ISearchResult } from '@/types'
import { useToggle } from '@/use/useToggle'
import { computed } from 'vue'
import { watch } from 'vue'
// 声明事件接口,接口中属性值是一个函数,函数名是cancel,返回值是一个函数void
interface IEmits {
(e: 'cancel'): void
}
const searchValue = ref('')
const searchResult = ref([] as ISearchResult[])
// 定义一个事件变量,用defineEmits方法实现,方法中引入声明的事件接口
const emits = defineEmits<IEmits>()
const HISTORY_TAGS = [
'披萨',
'标签2',
'标签3',
'标签4',
'标签5',
'标签6',
'标签7',
]
const [isHistoryTagShown, toggleHistoryTag] = useToggle(false)
const historyTags = computed(() => (isHistoryTagShown.value ? HISTORY_TAGS : HISTORY_TAGS.slice(0, 5)))
// 有三种状态:搜索初始化、搜索完成、搜索中
const [INIT, DONE, DOING] = [-1, 0, 1]
const searchState = ref(INIT)
const onSearch = async (v?: string | number) => {
console.log('onSearch', v)
// 防止搜索状态错误
try {
searchState.value = DOING
const { list } = await fetchSearchData(v as string)
searchResult.value = list
} finally {
searchState.value = DONE
}
}
const onTagClick = (v:string) => {
searchValue.value = v
onSearch(v)
}
watch(searchValue, (new_v) => {
if(!new_v) {
searchResult.value = []
return
}
onSearch(new_v)
})
</script>
<template>
<!-- 调用事件变量,传入事件名cancel // 模板代码中引入定义的事件,用来在父组件中使用对应的事件 -->
<div class=