vuecssuiant-designantdreactantantd-vueenterprisefrontendui-designvue-antdvue-antd-uivue3vuecomponent
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
5.1 KiB
169 lines
5.1 KiB
import type { PropType } from 'vue'; |
|
import { computed, shallowRef, defineComponent } from 'vue'; |
|
import classNames from '../_util/classNames'; |
|
import Input from './Input'; |
|
import SearchOutlined from '@ant-design/icons-vue/SearchOutlined'; |
|
import Button from '../button'; |
|
import { cloneElement } from '../_util/vnode'; |
|
import PropTypes from '../_util/vue-types'; |
|
import isPlainObject from 'lodash-es/isPlainObject'; |
|
import type { |
|
ChangeEvent, |
|
CompositionEventHandler, |
|
MouseEventHandler, |
|
} from '../_util/EventInterface'; |
|
import useConfigInject from '../config-provider/hooks/useConfigInject'; |
|
import omit from '../_util/omit'; |
|
import inputProps from './inputProps'; |
|
|
|
export default defineComponent({ |
|
compatConfig: { MODE: 3 }, |
|
name: 'AInputSearch', |
|
inheritAttrs: false, |
|
props: { |
|
...inputProps(), |
|
inputPrefixCls: String, |
|
// 不能设置默认值 https://github.com/vueComponent/ant-design-vue/issues/1916 |
|
enterButton: PropTypes.any, |
|
onSearch: { |
|
type: Function as PropType< |
|
(value: string, event?: ChangeEvent | MouseEvent | KeyboardEvent) => void |
|
>, |
|
}, |
|
}, |
|
setup(props, { slots, attrs, expose, emit }) { |
|
const inputRef = shallowRef(); |
|
const composedRef = shallowRef(false); |
|
const focus = () => { |
|
inputRef.value?.focus(); |
|
}; |
|
const blur = () => { |
|
inputRef.value?.blur(); |
|
}; |
|
expose({ |
|
focus, |
|
blur, |
|
}); |
|
|
|
const onChange = (e: ChangeEvent) => { |
|
emit('update:value', (e.target as HTMLInputElement).value); |
|
if (e && e.target && e.type === 'click') { |
|
emit('search', e.target.value, e); |
|
} |
|
emit('change', e); |
|
}; |
|
|
|
const onMousedown: MouseEventHandler = e => { |
|
if (document.activeElement === inputRef.value?.input) { |
|
e.preventDefault(); |
|
} |
|
}; |
|
|
|
const onSearch = (e: MouseEvent | KeyboardEvent) => { |
|
emit('search', inputRef.value?.input?.stateValue, e); |
|
}; |
|
|
|
const onPressEnter = (e: KeyboardEvent) => { |
|
if (composedRef.value || props.loading) { |
|
return; |
|
} |
|
onSearch(e); |
|
}; |
|
|
|
const handleOnCompositionStart: CompositionEventHandler = e => { |
|
composedRef.value = true; |
|
emit('compositionstart', e); |
|
}; |
|
|
|
const handleOnCompositionEnd: CompositionEventHandler = e => { |
|
composedRef.value = false; |
|
emit('compositionend', e); |
|
}; |
|
const { prefixCls, getPrefixCls, direction, size } = useConfigInject('input-search', props); |
|
const inputPrefixCls = computed(() => getPrefixCls('input', props.inputPrefixCls)); |
|
return () => { |
|
const { |
|
disabled, |
|
loading, |
|
addonAfter = slots.addonAfter?.(), |
|
suffix = slots.suffix?.(), |
|
...restProps |
|
} = props; |
|
let { enterButton = slots.enterButton?.() ?? false } = props; |
|
enterButton = enterButton || enterButton === ''; |
|
const searchIcon = typeof enterButton === 'boolean' ? <SearchOutlined /> : null; |
|
const btnClassName = `${prefixCls.value}-button`; |
|
|
|
const enterButtonAsElement = Array.isArray(enterButton) ? enterButton[0] : enterButton; |
|
let button: any; |
|
const isAntdButton = |
|
enterButtonAsElement.type && |
|
isPlainObject(enterButtonAsElement.type) && |
|
enterButtonAsElement.type.__ANT_BUTTON; |
|
if (isAntdButton || enterButtonAsElement.tagName === 'button') { |
|
button = cloneElement( |
|
enterButtonAsElement, |
|
{ |
|
onMousedown, |
|
onClick: onSearch, |
|
key: 'enterButton', |
|
...(isAntdButton |
|
? { |
|
class: btnClassName, |
|
size: size.value, |
|
} |
|
: {}), |
|
}, |
|
false, |
|
); |
|
} else { |
|
const iconOnly = searchIcon && !enterButton; |
|
button = ( |
|
<Button |
|
class={btnClassName} |
|
type={enterButton ? 'primary' : undefined} |
|
size={size.value} |
|
disabled={disabled} |
|
key="enterButton" |
|
onMousedown={onMousedown} |
|
onClick={onSearch} |
|
loading={loading} |
|
icon={iconOnly ? searchIcon : null} |
|
> |
|
{iconOnly ? null : searchIcon || enterButton} |
|
</Button> |
|
); |
|
} |
|
if (addonAfter) { |
|
button = [button, addonAfter]; |
|
} |
|
const cls = classNames( |
|
prefixCls.value, |
|
{ |
|
[`${prefixCls.value}-rtl`]: direction.value === 'rtl', |
|
[`${prefixCls.value}-${size.value}`]: !!size.value, |
|
[`${prefixCls.value}-with-button`]: !!enterButton, |
|
}, |
|
attrs.class, |
|
); |
|
return ( |
|
<Input |
|
ref={inputRef} |
|
{...omit(restProps, ['onUpdate:value', 'onSearch', 'enterButton'])} |
|
{...attrs} |
|
onPressEnter={onPressEnter} |
|
onCompositionstart={handleOnCompositionStart} |
|
onCompositionend={handleOnCompositionEnd} |
|
size={size.value} |
|
prefixCls={inputPrefixCls.value} |
|
addonAfter={button} |
|
suffix={suffix} |
|
onChange={onChange} |
|
class={cls} |
|
disabled={disabled} |
|
v-slots={slots} |
|
/> |
|
); |
|
}; |
|
}, |
|
});
|
|
|