staff/uni_modules/wot-design-uni/components/wd-search/wd-search.vue

202 lines
4.9 KiB
Vue

<template>
<view :class="rootClass" :style="customStyle">
<view class="wd-search__block">
<slot name="prefix"></slot>
<view class="wd-search__field">
<view v-if="!placeholderLeft" :style="coverStyle" class="wd-search__cover" @click="closeCover">
<wd-icon name="search" custom-class="wd-search__search-icon"></wd-icon>
<text :class="`wd-search__placeholder-txt ${placeholderClass}`">{{ placeholder || translate('search') }}</text>
</view>
<wd-icon v-if="showInput || str || placeholderLeft" name="search" custom-class="wd-search__search-left-icon"></wd-icon>
<input
v-if="showInput || str || placeholderLeft"
:placeholder="placeholder || translate('search')"
:placeholder-class="`wd-search__placeholder-txt ${placeholderClass}`"
:placeholder-style="placeholderStyle"
confirm-type="search"
v-model="str"
:class="['wd-search__input', customInputClass]"
@focus="searchFocus"
@input="inputValue"
@blur="searchBlur"
@confirm="search"
:disabled="disabled"
:maxlength="maxlength"
:focus="isFocused"
/>
<wd-icon v-if="str" custom-class="wd-search__clear wd-search__clear-icon" name="error-fill" @click="clearSearch" />
</view>
</view>
<slot v-if="!hideCancel" name="suffix">
<view class="wd-search__cancel" @click="handleCancel">
{{ cancelTxt || translate('cancel') }}
</view>
</slot>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-search',
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import wdIcon from '../wd-icon/wd-icon.vue'
import { type CSSProperties, computed, onMounted, ref, watch } from 'vue'
import { objToStyle, pause } from '../common/util'
import { useTranslate } from '../composables/useTranslate'
import { searchProps } from './types'
const props = defineProps(searchProps)
const emit = defineEmits(['update:modelValue', 'change', 'clear', 'search', 'focus', 'blur', 'cancel'])
const { translate } = useTranslate('search')
const isFocused = ref<boolean>(false) // 是否聚焦中
const showInput = ref<boolean>(false) // 是否显示输入框 用于实现聚焦的hack
const str = ref('')
const showPlaceHolder = ref<boolean>(true)
const clearing = ref<boolean>(false)
watch(
() => props.modelValue,
(newValue) => {
str.value = newValue
if (newValue) {
showInput.value = true
}
},
{ immediate: true }
)
watch(
() => props.focus,
(newValue) => {
if (newValue) {
if (props.disabled) return
closeCover()
}
}
)
onMounted(() => {
if (props.focus) {
closeCover()
}
})
const rootClass = computed(() => {
return `wd-search ${props.light ? 'is-light' : ''} ${props.hideCancel ? 'is-without-cancel' : ''} ${props.customClass}`
})
const coverStyle = computed(() => {
const coverStyle: CSSProperties = {
display: str.value === '' && showPlaceHolder.value ? 'flex' : 'none'
}
return objToStyle(coverStyle)
})
async function hackFocus(focus: boolean) {
showInput.value = focus
await pause()
isFocused.value = focus
}
async function closeCover() {
if (props.disabled) return
await pause(100)
showPlaceHolder.value = false
hackFocus(true)
}
/**
* @description input的input事件handle
* @param value
*/
function inputValue(event: any) {
str.value = event.detail.value
emit('update:modelValue', event.detail.value)
emit('change', {
value: event.detail.value
})
}
/**
* @description 点击清空icon的handle
*/
async function clearSearch() {
str.value = ''
clearing.value = true
if (props.focusWhenClear) {
isFocused.value = false
}
await pause(100)
if (props.focusWhenClear) {
showPlaceHolder.value = false
hackFocus(true)
} else {
showPlaceHolder.value = true
hackFocus(false)
}
emit('change', {
value: ''
})
emit('update:modelValue', '')
emit('clear')
}
/**
* @description 点击搜索按钮时的handle
* @param value
*/
function search({ detail: { value } }: any) {
// 组件触发search事件
emit('search', {
value
})
}
/**
* @description 输入框聚焦时的handle
*/
function searchFocus() {
if (clearing.value) {
clearing.value = false
return
}
showPlaceHolder.value = false
emit('focus', {
value: str.value
})
}
/**
* @description 输入框失焦的handle
*/
function searchBlur() {
if (clearing.value) return
// 组件触发blur事件
showPlaceHolder.value = !str.value
showInput.value = !showPlaceHolder.value
isFocused.value = false
emit('blur', {
value: str.value
})
}
/**
* @description 点击取消搜索按钮的handle
*/
function handleCancel() {
// 组件触发cancel事件
emit('cancel', {
value: str.value
})
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>