如何在 VueJs 组件中正确引用 HTMLElement
Posted
技术标签:
【中文标题】如何在 VueJs 组件中正确引用 HTMLElement【英文标题】:How to correctly reference HTMLElement in VueJs component 【发布时间】:2021-08-01 22:54:06 【问题描述】:我有一个简单的组件,它包含文本区域。我还有另一个简单的组件,它呈现一个按钮。单击按钮时,我想将焦点设置到文本区域。
这个简化的例子失败了:
<template>
<MyCommand @resize="testResize" />
<TextArea ref="refElement" />
</template>
<script lang="ts">
// ...
export default defineComponent(
name: 'SimpleComponent',
setup(props, context)
const refElement = ref<htmlElement | null>(null)
const testResize = () =>
console.log('resize test')
if (refElement.value !== null)
refElement.value.focus()
return
refElement,
testResize,
</script>
TextArea 是一个很简单的组件,一些输入规范化,过于简单了:
<template>
<textarea v-model.trim="value" />
</template>
我在控制台中得到“resize test”,所以 testResize 方法正在运行,但 refElement 为空。
【问题讨论】:
可能是TextArea
的问题,您使用的是哪个库?看看如何将 ref 传递给 TextArea
@Naren 没有库,只是简单的组件,用于包装 textarea 输入并进行一些输入规范化。你是对的 - 当我尝试使用简单的 textarea 而不是组件时,它可以工作。任何提示如何在组件内引用包装的输入?
【参考方案1】:
当引用组件而不是 HTML 元素时,组件类型应该是 DefineComponent
而不是 HTMLElement
。
可以通过 $el 属性引用被包裹的元素:
<template>
<MyCommand @resize="testResize" />
<TextArea ref="refElement" />
</template>
<script lang="ts">
// ...
export default defineComponent(
name: 'SimpleComponent',
setup(props, context)
const refElement = ref<DefineComponent>()
const testResize = () =>
console.log('resize test')
if (refElement.value)
refElement.value.$el.focus()
return
refElement,
testResize,
</script>
我不确定这是否是“最佳实践”,在我看来它是一种 hack。如果有人知道更好的解决方案,请发表评论。
【讨论】:
【参考方案2】:您的退货中缺少refElement
return
testResize, refElement
更新
如果您正在处理一个组件,它会变得有点棘手。虽然您可以使用refElement.value.$el
,但我想说这不是一个好主意。这仅在组件具有第一个子组件textarea
时才有效。这将导致一个脆弱的实现,如果你需要在某个时候改变它,它就会崩溃。恕我直言,您最好将 ref 作为道具传递给子组件。这也不是最佳实践,因为您应该向下传递道具并向上发出事件,但这将是实现的相当大的开销。不过,将ref
作为道具传递也有其自身的问题。如果模板中有ref
,它会自动从 ref/propxy 转换为一个值。为了解决这个问题,您可以在设置中的函数refElement: () => refElement
中传递道具(不能这样做模板)。当然,YMMV,但这是我选择的路径。
const app = Vue.createApp(
setup(props, context)
const refElement = Vue.ref(null)
const testResize = () =>
if (refElement.value !== null)
refElement.value.focus()
return
testResize,
refElement: () => refElement
);
app.component("text-area",
template: `<textarea ref="taRef"></textarea></div></div>`,
props:
textarearef:
type: Function
,
setup(props)
const taRef = props.textarearef()
return
taRef
)
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.3/dist/vue.global.prod.js"></script>
<div id="app">
<text-area :textarearef="refElement"></text-area>
<button @click="testResize">?</button>
</div>
【讨论】:
谢谢,你说得对,我也要返回 refElement。不幸的是,这似乎只是问题的一部分——您的示例使用 textarea 输入(效果很好),但我正在尝试引用包含 textarea 的组件。任何提示如何引用包装的输入?我已经更新了我的问题。 更新答案。以上是关于如何在 VueJs 组件中正确引用 HTMLElement的主要内容,如果未能解决你的问题,请参考以下文章
如何将 vuetify 组件正确地动态传递到 vueJs 组件中