Input.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <template>
  2. <div
  3. class="input"
  4. :class="{
  5. 'disabled': disabled,
  6. 'focused': focused,
  7. 'simple': simple,
  8. }"
  9. >
  10. <span class="prefix">
  11. <slot name="prefix"></slot>
  12. </span>
  13. <input
  14. type="text"
  15. ref="inputRef"
  16. :disabled="disabled"
  17. :value="value"
  18. :placeholder="placeholder"
  19. :maxlength="maxlength"
  20. @input="$event => handleInput($event)"
  21. @focus="$event => handleFocus($event)"
  22. @blur="$event => handleBlur($event)"
  23. @change="$event => emit('change', $event)"
  24. @keydown.enter="$event => emit('enter', $event)"
  25. @keydown.backspace="$event => emit('backspace', $event)"
  26. />
  27. <span class="suffix">
  28. <slot name="suffix"></slot>
  29. </span>
  30. </div>
  31. </template>
  32. <script lang="ts" setup>
  33. import { useTemplateRef, ref } from 'vue'
  34. withDefaults(defineProps<{
  35. value: string
  36. disabled?: boolean
  37. placeholder?: string
  38. simple?: boolean
  39. maxlength?: number
  40. }>(), {
  41. disabled: false,
  42. placeholder: '',
  43. simple: false,
  44. })
  45. const emit = defineEmits<{
  46. (event: 'update:value', payload: string): void
  47. (event: 'input', payload: Event): void
  48. (event: 'change', payload: Event): void
  49. (event: 'blur', payload: Event): void
  50. (event: 'focus', payload: Event): void
  51. (event: 'enter', payload: Event): void
  52. (event: 'backspace', payload: Event): void
  53. }>()
  54. const focused = ref(false)
  55. const handleInput = (e: Event) => {
  56. emit('update:value', (e.target as HTMLInputElement).value)
  57. }
  58. const handleBlur = (e: Event) => {
  59. focused.value = false
  60. emit('blur', e)
  61. }
  62. const handleFocus = (e: Event) => {
  63. focused.value = true
  64. emit('focus', e)
  65. }
  66. const inputRef = useTemplateRef<HTMLInputElement>('inputRef')
  67. const focus = () => {
  68. if (inputRef.value) inputRef.value.focus()
  69. }
  70. defineExpose({
  71. focus,
  72. })
  73. </script>
  74. <style lang="scss" scoped>
  75. .input {
  76. background-color: #fff;
  77. border: 1px solid #d9d9d9;
  78. padding: 0 5px;
  79. border-radius: $borderRadius;
  80. transition: border-color .25s;
  81. font-size: 13px;
  82. display: flex;
  83. input {
  84. min-width: 0;
  85. height: 30px;
  86. outline: 0;
  87. border: 0;
  88. line-height: 30px;
  89. vertical-align: top;
  90. color: $textColor;
  91. padding: 0 5px;
  92. flex: 1;
  93. font-size: 13px;
  94. font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';
  95. &::placeholder {
  96. color: #bfbfbf;
  97. }
  98. }
  99. &:not(.disabled):hover, &.focused {
  100. border-color: $themeColor;
  101. }
  102. &.disabled {
  103. background-color: #f5f5f5;
  104. border-color: #dcdcdc;
  105. color: #b7b7b7;
  106. input {
  107. color: #b7b7b7;
  108. }
  109. }
  110. &.simple {
  111. border: 0;
  112. }
  113. .prefix, .suffix {
  114. display: flex;
  115. justify-content: center;
  116. align-items: center;
  117. line-height: 30px;
  118. user-select: none;
  119. }
  120. }
  121. </style>