Vue.js 3中textarea组件内slot失效的最简替代方案
Vue.js 3 自定义textarea组件内容传递解决方案
原生<textarea>标签内部不支持Vue的<slot/>机制,直接在textarea里写slot无法生效。下面是两种简洁的替代方案:
方案一:使用defineModel(Vue 3.3+ 推荐)
利用Vue 3.3新增的defineModel语法糖,结合组件挂载时提取插槽文本作为初始值,代码最简洁:
组件代码:
<template> <textarea v-model="modelValue"></textarea> </template> <script setup> import { onMounted } from 'vue' const modelValue = defineModel({ default: '' }) // 挂载时自动把插槽文本设为初始内容(如果没传v-model的话) onMounted(() => { if (!modelValue.value && $slots.default) { // 提取插槽里的纯文本内容 modelValue.value = $slots.default()[0].children.join('').trim() } }) </script>
使用方式:
<c-textarea>hello world</c-textarea>
方案二:基于Props和自定义事件(兼容Vue 3.x全版本)
如果项目还没升级到Vue 3.3,可以用传统的props+emit方式:
组件代码:
<template> <textarea :value="displayContent" @input="$emit('update:content', $event.target.value)" ></textarea> </template> <script setup> import { computed } from 'vue' const props = defineProps({ content: { type: String, default: '' } }) const emit = defineEmits(['update:content']) // 优先用props传的内容,没有的话取插槽文本 const displayContent = computed(() => { if (props.content) return props.content return $slots.default ? $slots.default()[0].children.join('').trim() : '' }) </script>
使用方式:
<!-- 直接传初始文本 --> <c-textarea>hello world</c-textarea> <!-- 也支持双向绑定 --> <c-textarea v-model:content="myText"></c-textarea>
注意事项
- 以上方案默认插槽里是纯文本,如果插槽包含HTML标签,需要额外处理(比如过滤标签只保留文本)
- 插槽文本会作为初始值,后续修改textarea内容不会影响插槽本身(符合表单组件的预期)
内容的提问来源于stack exchange,提问作者Danial Qsk
相关产品推荐
相关产品推荐

