预览
Input | Vue3xy (chengbotao.github.io)
Input | Reactxy (chengbotao.github.io)
介绍
输入字符框
支持前后添加自定义内容
支持添加icon
Props 属性
支持原生
Input属性
| 属性名 | 属性类型 | 说明 | 默认值 |
|---|---|---|---|
model-value| v-model | string | number | 绑定值 | - |
disabled | boolean | 设置 Input 禁用 | false |
className | string | 自定义CSS类名 | - |
sized | oneOf "sm" | "lg" | 设置 Input 尺寸 | - |
icon | IconProp | 设置 Input 后面图标 | - |
Event 事件
| 事件名 | 参数类型 | 说明 |
|---|---|---|
input | MouseEvent | 在 Input 值改变时触发 |
focus | MouseEvent | Input 获得焦点时触发 |
blur | MouseEvent | Input 失去焦点时触发 |
change | MouseEvent | 仅当 modelValue 改变时且当输入框失去焦点或按 Enter 时触发 |
Slot 插槽
| 插槽名 | 说明 |
|---|---|
prepend | 输入框前置内容 |
append | 输入框后置内容 |
呈现
Vue3 实现
<template>
<div :class="classes">
<div v-if="slots.prepend" key="prepend" class="xy-input-group-prepend">
<slot name="prepend"></slot>
</div>
<div v-if="icon" key="icon" class="icon-wrapper">
<xyIcon :icon="icon"></xyIcon>
</div>
<input class="xy-input-inner" v-bind="$attrs" :disabled=disabled @focus="handleFocus" @blur="handleBlur"
@change="handleChange" @input="handleInput" :value="modelValue" />
<div v-if="slots.append" key="append" class="xy-input-group-append">
<slot name="append"></slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'XyInput',
inheritAttrs: false,
})
</script>
<script setup lang="ts">
import { useSlots } from "vue";
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import classNames from 'classnames';
type InputSize = 'lg' | 'sm';
interface InputProps {
modelValue?: string | number;
disabled?: boolean;
sized?: InputSize;
icon?: IconProp;
className?: string;
}
interface InputEmits {
(event: "input", payload: Event): void
(event: "focus", payload: FocusEvent): void
(event: "blur", payload: FocusEvent): void
(event: "change", payload: Event): void
(event: "update:modelValue", payload: string): void
}
// slots
const slots = useSlots();
// Props
const props = withDefaults(defineProps<InputProps>(), {
modelValue: ""
});
// Emits
const emits = defineEmits<InputEmits>();
// computed
const classes = classNames('xy-input-wrapper', props.className, {
[`xy-input-size-${props.sized}`]: props.sized,
'is-disabled': props.disabled,
'xy-input-group': slots?.prepend || slots?.append,
'xy-input-group-append': !!slots?.append,
'xy-input-group-prepend': !!slots?.prepend,
});
// methods
const handleInput = (event: Event) => {
emits("input", event)
emits("update:modelValue", (event.target as HTMLInputElement).value)
}
const handleFocus = (event: FocusEvent) => {
emits("focus", event)
}
const handleBlur = (event: FocusEvent) => {
emits("blur", event)
}
const handleChange = (event: Event) => {
emits("change", event)
}
// public 方法
defineExpose({})
</script>
Vue3 单元测试
// todo
React 实现
import React, { ChangeEvent, FC, InputHTMLAttributes, ReactElement } from 'react';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import classNames from 'classnames';
import Icon from '../icon/icon';
export type InputSize = 'lg' | 'sm';
export interface InputProps extends InputHTMLAttributes<HTMLElement> {
/** 设置 Input 禁用 */
disabled?: boolean;
/** 设置 Input 尺寸 */
sized?: InputSize;
/** 添加图标,在右侧悬浮添加一个图标,用于提示 */
icon?: IconProp;
/** 添加前缀 用于配置一些固定组合 */
prepend?: string | ReactElement;
/** 添加后缀 用于配置一些固定组合 */
append?: string | ReactElement;
/** 自定义 css 类名 */
className?: string;
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}
/**
* Input 组件
*
*/
export const Input: FC<InputProps> = (props) => {
const { disabled, sized, icon, prepend, append, className, ...restProps } = props;
const classes = classNames('xy-input-wrapper', className, {
[`xy-input-size-${sized}`]: sized,
'is-disabled': disabled,
'xy-input-group': prepend || append,
'xy-input-group-append': !!append,
'xy-input-group-prepend': !!prepend,
});
// 受控组件 || 非受控组件
const fixControlledValue = (value: unknown) => {
if (typeof value === 'undefined' || value === null) {
return '';
}
return value as string;
};
if ('value' in props) {
delete restProps.defaultValue;
restProps.value = fixControlledValue(props.value);
}
return (
<div className={classes} style={props.style}>
{prepend && <div className="xy-input-group-prepend">{prepend}</div>}
{icon && (
<div className="icon-wrapper">
<Icon icon={icon} title={`title-${icon}`} />
</div>
)}
<input className="xy-input-inner" disabled={disabled} {...restProps} />
{append && <div className="xy-input-group-append">{append}</div>}
</div>
);
};
export default Input;
React 单元测试
// todo
后记
感谢阅读,敬请斧正!