| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- <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 || inputValue || placeholderLeft" name="search" custom-class="wd-search__search-left-icon"></wd-icon>
- <input
- v-if="showInput || inputValue || placeholderLeft"
- :placeholder="placeholder || translate('search')"
- :placeholder-class="`wd-search__placeholder-txt ${placeholderClass}`"
- :placeholder-style="placeholderStyle"
- confirm-type="search"
- v-model="inputValue"
- :class="['wd-search__input', customInputClass]"
- @focus="handleFocus"
- @input="handleInput"
- @blur="handleBlur"
- @confirm="handleConfirm"
- :disabled="disabled"
- :maxlength="maxlength"
- :focus="isFocused"
- />
- <wd-icon v-if="inputValue" custom-class="wd-search__clear wd-search__clear-icon" name="error-fill" @click="handleClear" />
- </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 inputValue = ref<string>('') // 输入框的值
- const showPlaceHolder = ref<boolean>(true)
- const clearing = ref<boolean>(false)
- watch(
- () => props.modelValue,
- (newValue) => {
- inputValue.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: inputValue.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)
- }
- function handleInput(event: any) {
- inputValue.value = event.detail.value
- emit('update:modelValue', event.detail.value)
- emit('change', {
- value: event.detail.value
- })
- }
- async function handleClear() {
- inputValue.value = ''
- if (props.focusWhenClear) {
- clearing.value = true
- isFocused.value = false
- }
- await pause()
- if (props.focusWhenClear) {
- showPlaceHolder.value = false
- hackFocus(true)
- } else {
- showPlaceHolder.value = true
- hackFocus(false)
- }
- emit('change', {
- value: ''
- })
- emit('update:modelValue', '')
- emit('clear')
- }
- function handleConfirm({ detail: { value } }: any) {
- // 组件触发search事件
- emit('search', {
- value
- })
- }
- function handleFocus() {
- showPlaceHolder.value = false
- emit('focus', {
- value: inputValue.value
- })
- }
- async function handleBlur() {
- // 等待150毫秒,clear执行完毕
- await pause(150)
- if (clearing.value) {
- clearing.value = false
- return
- }
- // 组件触发blur事件
- showPlaceHolder.value = !inputValue.value
- showInput.value = !showPlaceHolder.value
- isFocused.value = false
- emit('blur', {
- value: inputValue.value
- })
- }
- function handleCancel() {
- emit('cancel', {
- value: inputValue.value
- })
- }
- </script>
- <style lang="scss" scoped>
- @import './index.scss';
- </style>
|