Files
uniapp-im-shop/TUIKit/components/TUISearch/search-input/index.vue

241 lines
5.9 KiB
Vue

<template>
<div
:class="[
'tui-search-input-container',
!isPC && 'tui-search-input-container-h5',
props.searchType === 'global'
? 'tui-search-input-container-global'
: 'tui-search-input-container-conversation'
]"
>
<div
v-if="!searchingStatus && props.searchType === 'global'"
:class="['tui-search-input', !isPC && 'tui-search-input-h5']"
>
<div class="tui-search-input-place" @click="onSearchInputClick">
<Icon
class="icon"
:file="searchIcon"
width="14px"
height="14px"
/>
<p>{{ props.placeholder }}</p>
</div>
</div>
<div
v-else
:class="['tui-search-input', !isPC && 'tui-search-input-h5']"
>
<div class="tui-search-input-left">
<Icon
class="icon"
:file="searchIcon"
width="14px"
height="14px"
/>
</div>
<input
v-model="searchValueModel"
class="tui-search-input-main"
type="text"
:placeholder="props.placeholder"
:focus="searchingStatus"
enterkeyhint="search"
@blur="onBlur"
@keyup.enter="search"
@confirm="search"
/>
<div
v-if="searchingStatus"
class="tui-search-input-right"
@click="endSearching"
>
<Icon class="icon" :file="closeIcon" width="14px" height="14px" />
</div>
</div>
<div
v-if="!isPC && searchingStatus && props.searchType === 'global'"
:class="[
'tui-search-input-cancel',
!isPC && 'tui-search-input-h5-cancel'
]"
@click="endSearching"
>
{{ TUITranslateService.t('TUISearch.取消') }}
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from '../../../adapter-vue'
import {
TUIStore,
StoreName,
TUITranslateService
} from '@tencentcloud/chat-uikit-engine-lite'
import { TUIGlobal } from '@tencentcloud/universal-api'
import Icon from '../../common/Icon.vue'
import searchIcon from '../../../assets/icon/search.svg'
import closeIcon from '../../../assets/icon/input-close.svg'
import { isPC } from '../../../utils/env'
import { ISearchInputValue, ISearchingStatus } from '../type'
const props = defineProps({
placeholder: {
type: String,
default: () => TUITranslateService.t('TUISearch.搜索')
},
searchType: {
type: String,
default: 'global', // "global" / "conversation"
validator(value: string) {
return ['global', 'conversation'].includes(value)
}
}
})
const searchValueModel = ref<string>('')
const currentSearchInputValue = ref<string>('')
const searchingStatus = ref<boolean>(false)
function onCurrentSearchInputValueChange(obj: ISearchInputValue) {
if (obj?.searchType === props?.searchType) {
currentSearchInputValue.value = obj?.value
searchValueModel.value = obj?.value
}
}
function onCurrentSearchingStatusChange(obj: ISearchingStatus) {
if (obj?.searchType === props?.searchType) {
searchingStatus.value = obj?.isSearching
}
}
onMounted(() => {
TUIStore.watch(StoreName.SEARCH, {
currentSearchInputValue: onCurrentSearchInputValueChange,
currentSearchingStatus: onCurrentSearchingStatusChange
})
})
onUnmounted(() => {
TUIStore.unwatch(StoreName.SEARCH, {
currentSearchInputValue: onCurrentSearchInputValueChange,
currentSearchingStatus: onCurrentSearchingStatusChange
})
})
const search = () => {
// Avoid duplicate searches
if (searchValueModel.value === currentSearchInputValue.value) {
return
}
TUIStore.update(StoreName.SEARCH, 'currentSearchInputValue', {
value: searchValueModel.value,
searchType: props.searchType
})
}
const endSearching = () => {
searchingStatus.value = false
TUIStore.update(StoreName.SEARCH, 'currentSearchingStatus', {
isSearching: false,
searchType: props.searchType
})
TUIStore.update(StoreName.SEARCH, 'currentSearchInputValue', {
value: '',
searchType: props.searchType
})
}
const onSearchInputClick = () => {
TUIStore.update(StoreName.SEARCH, 'currentSearchingStatus', {
isSearching: true,
searchType: props.searchType
})
}
const onBlur = () => {
TUIGlobal?.hideKeyboard?.()
}
</script>
<style lang="scss" scoped>
.tui-search-input-container {
display: flex;
flex-direction: row;
box-sizing: border-box;
border-radius: 8px;
padding: 0 2px;
&-global {
flex: 1;
}
.tui-search-input {
flex: 1;
display: flex;
flex-direction: row;
margin: 0 26rpx;
margin-top: 12rpx;
background: #F4F4F4;
justify-content: center;
align-items: center;
height: 64rpx;
border-radius: 64rpx;
margin-bottom: 12rpx;
&-main {
flex: 1;
background: transparent;
border: none;
caret-color: #007aff;
font-size: 14px;
&:focus {
border: none;
outline: none;
}
&::placeholder {
color: #666;
font-size: 12px;
}
}
&-left,
&-right {
display: flex;
width: 14px;
height: 14px;
padding: 0 7px;
}
}
.tui-search-input-place {
flex: 1;
display: flex;
gap: 5px;
justify-content: flex-start;
align-items: center;
font-family: PingFang SC;
font-weight: 400;
color: #bbbbbb;
padding-left: 32rpx;
}
}
.tui-search-input-container-h5 {
.tui-search-input-h5 {
height: 40px;
}
.tui-search-input-cancel {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #007aff;
font-size: 16px;
padding: 7px 10px 7px 3px;
font-family: 'PingFang SC', sans-serif;
}
}
</style>