如何将焦点设置在新(自动)渲染的 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" />

demo

虽然这在技术上是可行的,但此 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 分叉)