mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-05-16 14:03:44 +08:00
feat: 番剧搜索框接口使用和交互完成
- 三种搜索触发来源 - 输入中 debounce 600ms 后触发搜索 - 按回车或点击搜索 icon 按钮后触发搜索 - 切换 provider 源站时触发搜索 - 渲染的番剧信息列表样式待调整 - 搜索框 placeholder / provider 展示样式/i18n 待调整
This commit is contained in:
@@ -2,35 +2,39 @@
|
||||
import {Down, Search} from '@icon-park/vue-next';
|
||||
import {ref} from 'vue';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
value: '',
|
||||
placeholder: '',
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits(['update:value', 'click-search']);
|
||||
const {site, providers, bangumiInfo$ } = storeToRefs(useSearchStore());
|
||||
const {getProviders, onInput} = useSearchStore();
|
||||
const inputValue = ref<string>('');
|
||||
const selectingProvider = ref<boolean>(false);
|
||||
|
||||
const {input$, provider, providers, getProviders, bangumiList } = useSearchStore();
|
||||
|
||||
/**
|
||||
* - 输入中 debounce 600ms 后触发搜索
|
||||
* - 按回车或点击搜索 icon 按钮后触发搜索
|
||||
* - 切换 provider 源站时触发搜索
|
||||
*/
|
||||
|
||||
|
||||
function onInput (e: Event) {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
input$.next(value);
|
||||
inputValue.value = value;
|
||||
}
|
||||
|
||||
function onSearch () {
|
||||
input$.next(inputValue.value);
|
||||
}
|
||||
|
||||
function onSelect (site: string) {
|
||||
provider.value = site;
|
||||
selectingProvider.value = !selectingProvider.value
|
||||
onSearch();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getProviders();
|
||||
});
|
||||
|
||||
const selectedProvider = computed(() => {
|
||||
return site.value || '';
|
||||
});
|
||||
|
||||
const onSelect = ref(false);
|
||||
|
||||
function onSearch() {
|
||||
emit('click-search', props.value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -58,9 +62,9 @@ function onSearch() {
|
||||
|
||||
<input
|
||||
type="text"
|
||||
:value="value"
|
||||
:placeholder="placeholder"
|
||||
placeholder="Input to search"
|
||||
input-reset
|
||||
:value="inputValue"
|
||||
@keyup.enter="onSearch"
|
||||
@input="onInput"
|
||||
/>
|
||||
@@ -72,27 +76,23 @@ function onSearch() {
|
||||
w-100px
|
||||
is-btn
|
||||
class="provider-select"
|
||||
@click="() => onSelect = !onSelect"
|
||||
@click="() => selectingProvider = !selectingProvider"
|
||||
>
|
||||
<div text-h3 truncate>
|
||||
{{ selectedProvider }}
|
||||
{{ provider }}
|
||||
</div>
|
||||
<div class="provider-select">
|
||||
<Down/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="onSelect" abs top-84px left-540px w-100px rounded-12px shadow bg-white z-99 overflow-hidden>
|
||||
<div v-show="selectingProvider" abs top-84px left-540px w-100px rounded-12px shadow bg-white z-99 overflow-hidden>
|
||||
<div
|
||||
v-for="i in providers"
|
||||
:key="i"
|
||||
v-for="site in providers"
|
||||
:key="site"
|
||||
hover:bg-theme-row
|
||||
is-btn
|
||||
@click="() => {
|
||||
site = i;
|
||||
onSelect = false;
|
||||
}"
|
||||
|
||||
@click="() => onSelect(site)"
|
||||
>
|
||||
<div
|
||||
text-h3
|
||||
@@ -101,19 +101,20 @@ function onSearch() {
|
||||
p-12px
|
||||
truncate
|
||||
>
|
||||
{{ i }}
|
||||
{{ site }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="bangumiInfo$"
|
||||
abs top-84px left-200px z-98>
|
||||
abs top-84px left-200px z-98
|
||||
>
|
||||
<ab-bangumi-card
|
||||
:key="bangumiInfo$.id"
|
||||
:poster="bangumiInfo$.poster_link ?? ''"
|
||||
:name="bangumiInfo$.official_title"
|
||||
:season="bangumiInfo$.season"
|
||||
:group="bangumiInfo$.group_name"
|
||||
v-for="(item, index) in bangumiList"
|
||||
:key="index"
|
||||
:poster="item.poster_link ?? ''"
|
||||
:name="item.official_title"
|
||||
:season="item.season"
|
||||
:group="item.group_name"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
import {ref} from 'vue';
|
||||
import {
|
||||
Subject,
|
||||
debounceTime,
|
||||
filter,
|
||||
switchMap,
|
||||
tap,
|
||||
} from "rxjs";
|
||||
import type {BangumiRule} from "#/bangumi";
|
||||
|
||||
|
||||
export const useSearchStore = defineStore('search', () => {
|
||||
const input$ = new Subject<string>();
|
||||
const onInput = (e: Event) => input$.next(e.target.value);
|
||||
const providers = ref<string[]>(['mikan', 'dmhy', 'nyaa']);
|
||||
const site = ref<string>('mikan');
|
||||
export function useSearchStore () {
|
||||
const bangumiList = ref<BangumiRule[]>([]);
|
||||
|
||||
const bangumiInfo$ = apiSearch.get('魔女之旅');
|
||||
const providers = ref<string[]>(['mikan', 'dmhy', 'nyaa']);
|
||||
const provider = ref<string>('mikan');
|
||||
|
||||
const input$ = new Subject<string>();
|
||||
|
||||
const {execute: getProviders, onResult: onGetProvidersResult} = useApi(
|
||||
apiSearch.getProvider
|
||||
@@ -23,34 +25,25 @@ export const useSearchStore = defineStore('search', () => {
|
||||
providers.value = res;
|
||||
});
|
||||
|
||||
input$.pipe(
|
||||
debounceTime(1000),
|
||||
tap((input: string) => {
|
||||
console.log('input', input)
|
||||
// clear Search Result List
|
||||
|
||||
const bangumiInfo$ = input$.pipe(
|
||||
debounceTime(600),
|
||||
tap(() => {
|
||||
bangumiList.value = [];
|
||||
}),
|
||||
switchMap((input: string) => apiSearch.get(input, site.value)),
|
||||
tap((bangumi: BangumiRule) => console.log(bangumi)),
|
||||
filter(Boolean),
|
||||
switchMap((input: string) => apiSearch.get(input, provider.value)),
|
||||
tap((bangumi: BangumiRule) => {
|
||||
console.log('bangumi', bangumi)
|
||||
// set bangumi info to Search Result List
|
||||
bangumiList.value.push(bangumi);
|
||||
}),
|
||||
).subscribe({
|
||||
complete() {
|
||||
// end of stream, stop loading animation
|
||||
}
|
||||
}, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
return {
|
||||
input$,
|
||||
onInput,
|
||||
bangumiInfo$,
|
||||
site,
|
||||
provider,
|
||||
getProviders,
|
||||
providers,
|
||||
bangumiList,
|
||||
};
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user