如何将焦点设置在新(自动)渲染的 dom 元素上?
How can i set focus on a newly (automatically) rendered dom element?
我有一个输入字段,它会根据用户输入的字符数自动替换为文本区域和相同的内容:
<textarea v-if="myString.length > 20" v-model="myString"/>
<input type="text" v-if="myString.length <= 20" v-model="myString"/>
我遇到的问题是,当用户输入第 21 个字符时,焦点会丢失。因此用户会感到恼火,因为当他键入第 22 个字符时,它不会出现在文本区域中(无焦点)。
那么我如何将焦点设置在新呈现的文本区域上?这里的问题是它会自动呈现。否则我可以在 textarea 上设置一个 ref 并调用 focus()。
另一个问题是第 21 个字符的删除以及从文本区域切换回输入元素。
您可以将 textarea
/input
包装在一个组件中,并使用其 mounted
挂钩调用其 focus()
,如该组件所示:
<!-- AutoFocusedInput.vue -->
<script setup>
import { ref, onMounted, computed, nextTick } from 'vue'
const input = ref()
onMounted(async () => {
await nextTick()
input.value.focus()
})
const props = defineProps({
modelValue: String,
textarea: Boolean,
})
const comp = computed(() => (props.textarea ? 'textarea' : 'input'))
</script>
<template>
<component
:is="comp"
ref="input"
v-bind="$attrs"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<AutoFocusedInput textarea v-if="myString.length > 20" v-model="myString" />
<AutoFocusedInput v-else v-model="myString" />
虽然这在技术上是可行的,但此 UX 可能并不理想,您应该考虑其他不需要像这样的聚焦输入的设计(如 @kien_coi_1997 所示)。
(从我的评论中复制,因为这可能会有帮助)
用 textarea
替换 input
元素可能会产生糟糕的用户体验。你为什么不从一开始就使用 textarea
呢?如果您希望样式根据输入长度发生变化,例如如果有 > 20 个字符,请增加高度,然后您可以使用 CSS 来做到这一点。
<script setup>
const props = defineProps({
modelValue: String,
})
</script>
<template>
<textarea
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
:rows="1"
:style="modelValue.length > 20 ? { minHeight: '100px' } : { minHeight: '0px' }"
/>
</template>
<AutoFocusedInput v-model="myString" />
demo(从@tony19 分叉)
我有一个输入字段,它会根据用户输入的字符数自动替换为文本区域和相同的内容:
<textarea v-if="myString.length > 20" v-model="myString"/>
<input type="text" v-if="myString.length <= 20" v-model="myString"/>
我遇到的问题是,当用户输入第 21 个字符时,焦点会丢失。因此用户会感到恼火,因为当他键入第 22 个字符时,它不会出现在文本区域中(无焦点)。 那么我如何将焦点设置在新呈现的文本区域上?这里的问题是它会自动呈现。否则我可以在 textarea 上设置一个 ref 并调用 focus()。
另一个问题是第 21 个字符的删除以及从文本区域切换回输入元素。
您可以将 textarea
/input
包装在一个组件中,并使用其 mounted
挂钩调用其 focus()
,如该组件所示:
<!-- AutoFocusedInput.vue -->
<script setup>
import { ref, onMounted, computed, nextTick } from 'vue'
const input = ref()
onMounted(async () => {
await nextTick()
input.value.focus()
})
const props = defineProps({
modelValue: String,
textarea: Boolean,
})
const comp = computed(() => (props.textarea ? 'textarea' : 'input'))
</script>
<template>
<component
:is="comp"
ref="input"
v-bind="$attrs"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<AutoFocusedInput textarea v-if="myString.length > 20" v-model="myString" />
<AutoFocusedInput v-else v-model="myString" />
虽然这在技术上是可行的,但此 UX 可能并不理想,您应该考虑其他不需要像这样的聚焦输入的设计(如 @kien_coi_1997 所示)。
(从我的评论中复制,因为这可能会有帮助)
用 textarea
替换 input
元素可能会产生糟糕的用户体验。你为什么不从一开始就使用 textarea
呢?如果您希望样式根据输入长度发生变化,例如如果有 > 20 个字符,请增加高度,然后您可以使用 CSS 来做到这一点。
<script setup>
const props = defineProps({
modelValue: String,
})
</script>
<template>
<textarea
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
:rows="1"
:style="modelValue.length > 20 ? { minHeight: '100px' } : { minHeight: '0px' }"
/>
</template>
<AutoFocusedInput v-model="myString" />
demo(从@tony19 分叉)