Skip to content

Commit 364cfbf

Browse files
feat: ✨ Input 组件新增clear-triger属性 (#476)
Closes: #462
1 parent bb3d329 commit 364cfbf

File tree

5 files changed

+106
-51
lines changed

5 files changed

+106
-51
lines changed

docs/component/input.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ function handleChange(event) {
4444
<wd-input v-model="value" clearable @change="handleChange"/>
4545
```
4646

47+
## 有值且聚焦时展示清空按钮
48+
设置 `clear-trigger` 属性,可以控制是否聚焦时才展示清空按钮。
49+
50+
```html
51+
<wd-input v-model="value" clear-trigger="focus" clearable @change="handleChange"/>
52+
```
53+
54+
## 点击清除按钮时不自动聚焦
55+
56+
设置`focus-when-clear` 属性,可以控制点击清除按钮时是否自动聚焦。
57+
58+
```html
59+
<wd-input type="text" :focus-when-clear="false" v-model="value" clearable />
60+
```
61+
4762
## 密码输入框
4863

4964
设置 `show-password` 属性。
@@ -150,6 +165,9 @@ function handleChange(event) {
150165
| no-border | 非 cell 类型下是否隐藏下划线 | boolean | - | false | - | - |
151166
| prop | 表单域 `model` 字段名,在使用表单校验功能的情况下,该属性是必填的 | string | - | - | - |
152167
| rules | 表单验证规则,结合`wd-form`组件使用 | `FormItemRule []` | - | `[]` | - |
168+
| clearTrigger | 显示清除图标的时机,always 表示输入框不为空时展示,focus 表示输入框聚焦且不为空时展示 | `InputClearTrigger` | `focus` / `always` | `always` | $LOWEST_VERSION$ |
169+
| focusWhenClear | 是否在点击清除按钮时聚焦输入框 | boolean | - | true | $LOWEST_VERSION$ |
170+
153171

154172

155173
### FormItemRule 数据结构

docs/component/search.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,6 @@ function changeSearchType({ item, index }) {
141141
<wd-search placeholder="请输入订单号/订单名称" cancel-txt="搜索" />
142142
```
143143

144-
<!-- 通过设置 `use-action-slot` 来自定义输入框左边内容,设置`use-action-slot` 使用自定义内容替换取消按钮。
145-
146-
```html
147-
<wd-search use-label-slot use-action-slot>
148-
<template #label>
149-
<view style="line-height: 14px;margin-right: 10px;">左侧</view>
150-
</template>
151-
<template #action>
152-
<view style="padding: 5px 10px;color: #ff0000;">右侧</view>
153-
</template>
154-
</wd-search>
155-
``` -->
156144

157145
## Attributes
158146

src/pages/input/Index.vue

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
<demo-block title="清空按钮">
1616
<wd-input type="text" @input="handleInput" v-model="value4" clearable @change="handleChange1" />
1717
</demo-block>
18+
<demo-block title="有值且聚焦时展示清空按钮">
19+
<wd-input type="text" clear-trigger="focus" @input="handleInput" v-model="value20" clearable @change="handleChange1" />
20+
</demo-block>
21+
<demo-block title="点击清除按钮时不自动聚焦">
22+
<wd-input type="text" :focus-when-clear="false" @input="handleInput" v-model="value21" clearable @change="handleChange1" />
23+
</demo-block>
1824
<demo-block title="密码框">
1925
<wd-input type="text" @input="handleInput" v-model="value5" clearable show-password @change="handleChange2" />
2026
</demo-block>
@@ -45,7 +51,7 @@
4551
<wd-input type="text" label="错误状态" v-model="value15" @input="handleInput" placeholder="请输入用户名" error />
4652
<wd-input type="text" label="必填" v-model="value16" @input="handleInput" placeholder="请输入用户名" required />
4753
<wd-input type="text" label="图标" v-model="value17" @input="handleInput" placeholder="请输入..." prefix-icon="dong" suffix-icon="list" />
48-
<wd-input type="text" label="自定义插槽" center v-model="value18" @input="handleInput" placeholder="请输入..." use-suffix-slot clearable>
54+
<wd-input type="text" label="自定义插槽" center v-model="value18" @input="handleInput" placeholder="请输入..." clearable>
4955
<template #suffix>
5056
<wd-button size="small" custom-class="button">获取验证码</wd-button>
5157
</template>
@@ -76,6 +82,8 @@ const value16 = ref<string>('')
7682
const value17 = ref<string>('')
7783
const value18 = ref<string>('')
7884
const value19 = ref<string>('')
85+
const value20 = ref<string>('')
86+
const value21 = ref<string>('')
7987
8088
function handleChange(event: any) {
8189
console.log(event)

src/uni_modules/wot-design-uni/components/wd-input/types.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeNumericProp, makeStringProp } from '../common/props'
22
import type { FormItemRule } from '../wd-form/types'
33

4+
export type InputClearTrigger = 'focus' | 'always'
5+
46
export const inputProps = {
57
...baseProps,
68
customInputClass: makeStringProp(''),
@@ -155,5 +157,16 @@ export const inputProps = {
155157
/**
156158
* 表单验证规则,结合wd-form组件使用
157159
*/
158-
rules: makeArrayProp<FormItemRule>()
160+
rules: makeArrayProp<FormItemRule>(),
161+
/**
162+
* 显示清除图标的时机,always 表示输入框不为空时展示,focus 表示输入框聚焦且不为空时展示
163+
*/
164+
clearTrigger: makeStringProp<InputClearTrigger>('always'),
165+
/**
166+
* 是否在点击清除按钮时聚焦输入框
167+
* 类型: boolean
168+
* 默认值: true
169+
* 最低版本: $LOWEST_VERSION$
170+
*/
171+
focusWhenClear: makeBooleanProp(true)
159172
}

src/uni_modules/wot-design-uni/components/wd-input/wd-input.vue

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
:placeholder="placeholder || translate('placeholder')"
3131
:disabled="disabled"
3232
:maxlength="maxlength"
33-
:focus="isFocus"
33+
:focus="focused"
3434
:confirm-type="confirmType"
3535
:confirm-hold="confirmHold"
3636
:cursor="cursor"
@@ -49,7 +49,7 @@
4949
@keyboardheightchange="handleKeyboardheightchange"
5050
/>
5151
<view v-if="readonly" class="wd-input__readonly-mask" />
52-
<view v-if="showClear || showPassword || suffixIcon || showWordCount || useSuffixSlot" class="wd-input__suffix">
52+
<view v-if="showClear || showPassword || suffixIcon || showWordCount || $slots.suffix" class="wd-input__suffix">
5353
<wd-icon v-if="showClear" custom-class="wd-input__clear" name="error-fill" @click="clear" />
5454
<wd-icon v-if="showPassword" custom-class="wd-input__icon" :name="isPwdVisible ? 'view' : 'eye-close'" @click="togglePwdVisible" />
5555
<view v-if="showWordCount" class="wd-input__count">
@@ -85,7 +85,7 @@ export default {
8585

8686
<script lang="ts" setup>
8787
import { computed, onBeforeMount, ref, watch } from 'vue'
88-
import { objToStyle, requestAnimationFrame } from '../common/util'
88+
import { isDef, objToStyle, requestAnimationFrame } from '../common/util'
8989
import { useCell } from '../composables/useCell'
9090
import { FORM_KEY, type FormItemRule } from '../wd-form/types'
9191
import { useParent } from '../composables/useParent'
@@ -102,45 +102,64 @@ const emit = defineEmits([
102102
'input',
103103
'keyboardheightchange',
104104
'confirm',
105-
'linechange',
106105
'clicksuffixicon',
107106
'clickprefixicon',
108107
'click'
109108
])
110109
const { translate } = useTranslate('input')
111110
112-
const showClear = ref<boolean>(false)
113-
const showWordCount = ref<boolean>(false)
114111
const isPwdVisible = ref<boolean>(false)
115-
const clearing = ref<boolean>(false)
116-
const isFocus = ref<boolean>(false) // 是否聚焦
112+
const clearing = ref<boolean>(false) // 是否正在清空操作,避免重复触发失焦
113+
const focused = ref<boolean>(false) // 控制聚焦
114+
const focusing = ref<boolean>(false) // 当前是否激活状态
117115
const inputValue = ref<string | number>('') // 输入框的值
118116
const cell = useCell()
119117
120118
watch(
121119
() => props.focus,
122120
(newValue) => {
123-
isFocus.value = newValue
121+
focused.value = newValue
124122
},
125123
{ immediate: true, deep: true }
126124
)
127125
128126
watch(
129127
() => props.modelValue,
130128
(newValue) => {
131-
const { disabled, readonly, clearable } = props
132129
if (newValue === undefined) {
133130
newValue = ''
134131
console.warn('[wot-design] warning(wd-input): value can not be undefined.')
135132
}
136133
inputValue.value = newValue
137-
showClear.value = Boolean(clearable && !disabled && !readonly && newValue)
138134
},
139135
{ immediate: true, deep: true }
140136
)
141137
142138
const { parent: form } = useParent(FORM_KEY)
143139
140+
/**
141+
* 展示清空按钮
142+
*/
143+
const showClear = computed(() => {
144+
const { disabled, readonly, clearable, clearTrigger } = props
145+
if (clearable && !readonly && !disabled && inputValue.value && (clearTrigger === 'always' || (props.clearTrigger === 'focus' && focusing.value))) {
146+
return true
147+
} else {
148+
return false
149+
}
150+
})
151+
152+
/**
153+
* 展示字数统计
154+
*/
155+
const showWordCount = computed(() => {
156+
const { disabled, readonly, maxlength, showWordLimit } = props
157+
return Boolean(!disabled && !readonly && isDef(maxlength) && maxlength > -1 && showWordLimit)
158+
})
159+
160+
/**
161+
* 表单错误提示信息
162+
*/
144163
const errorMessage = computed(() => {
145164
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
146165
return form.errorMessages[props.prop]
@@ -194,49 +213,58 @@ onBeforeMount(() => {
194213
195214
// 状态初始化
196215
function initState() {
197-
const { disabled, readonly, clearable, maxlength, showWordLimit } = props
198-
let newVal = ''
199-
if (showWordLimit && maxlength && inputValue.value.toString().length > maxlength) {
200-
newVal = inputValue.value.toString().substring(0, maxlength)
201-
}
202-
showClear.value = Boolean(!disabled && !readonly && clearable && inputValue.value)
203-
showWordCount.value = Boolean(!disabled && !readonly && maxlength && showWordLimit)
204-
inputValue.value = newVal || inputValue.value
216+
inputValue.value = formatValue(inputValue.value)
205217
emit('update:modelValue', inputValue.value)
206218
}
219+
220+
function formatValue(value: string | number) {
221+
const { maxlength } = props
222+
if (isDef(maxlength) && maxlength !== -1 && String(value).length > maxlength) {
223+
return value.toString().slice(0, maxlength)
224+
}
225+
return value
226+
}
227+
207228
function togglePwdVisible() {
208229
isPwdVisible.value = !isPwdVisible.value
209230
}
210231
function clear() {
232+
clearing.value = true
233+
focusing.value = false
211234
inputValue.value = ''
212-
requestAnimationFrame()
213-
.then(() => requestAnimationFrame())
214-
.then(() => requestAnimationFrame())
215-
.then(() => {
216-
isFocus.value = true
217-
emit('change', {
218-
value: ''
219-
})
220-
emit('update:modelValue', inputValue.value)
221-
emit('clear')
235+
if (props.focusWhenClear) {
236+
focused.value = false
237+
}
238+
requestAnimationFrame(() => {
239+
if (props.focusWhenClear) {
240+
focused.value = true
241+
focusing.value = true
242+
}
243+
emit('change', {
244+
value: ''
222245
})
246+
emit('update:modelValue', inputValue.value)
247+
emit('clear')
248+
})
223249
}
224250
function handleBlur() {
225-
isFocus.value = false
226-
emit('change', {
227-
value: inputValue.value
228-
})
229-
emit('update:modelValue', inputValue.value)
230-
emit('blur', {
231-
value: inputValue.value
251+
if (clearing.value) {
252+
clearing.value = false
253+
return
254+
}
255+
requestAnimationFrame(() => {
256+
focusing.value = false
257+
emit('blur', {
258+
value: inputValue.value
259+
})
232260
})
233261
}
234262
function handleFocus({ detail }: any) {
235263
if (clearing.value) {
236264
clearing.value = false
237265
return
238266
}
239-
isFocus.value = true
267+
focusing.value = true
240268
emit('focus', detail)
241269
}
242270
function handleInput({ detail }: any) {

0 commit comments

Comments
 (0)