英文:
Access child element of a component from a parent component
问题
我有一个Form
组件,它渲染了3个InputContainer
组件。我想在表单的submit
事件中访问input
元素的值。目前,我的submitResource
函数记录了包含label
和input
元素的div
。
如果不是必要的话,我不想使用@change
处理程序发出任何事件。我唯一成功访问input
元素的方式是通过console.log(titleRef.value.$el.querySelector('input'));
,但我认为这不是正确的方式。
谢谢!
Form.vue
<template>
<form @submit.prevent="submitResource">
<InputContainer ref="titleRef" />
<InputContainer ref="descriptionRef"/>
<InputContainer ref="linkRef" />
<BaseButton type="submit" class="submit">Add Resource</BaseButton>
</form>
</template>
<script setup>
import BaseButton from './BaseButton.vue';
import InputContainer from './InputContainer.vue';
import { ref } from 'vue';
const titleRef = ref(null);
const descriptionRef = ref(null);
const linkRef = ref(null);
const submitResource = () => {
console.log(titleRef.value.$el);
};
</script>
InputContainer.vue
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
id="example"
name="example"
/>
</div>
</template>
英文:
I have a Form
component which renders 3 InputContainer
components. I want to access the value of the input
element on the submit
event of the form. Right now, my submitResource
function logs the div
which contains both label
and input
element.
If not necessary, I don't want to emit any events with @change handler. The only way I've managed to access the input
element is by console.log(titleRef.value.$el.querySelector('input'));
but I think its not the right way to do it.
Thank you!
Form.vue
<template>
<form @submit.prevent="submitResource">
<InputContainer ref="titleRef" />
<InputContainer ref="descriptionRef"/>
<InputContainer ref="linkRef" />
<BaseButton type="submit" class="submit">Add Resource</BaseButton>
</form>
</template>
<script setup>
import BaseButton from './BaseButton.vue';
import InputContainer from './InputContainer.vue';
import { ref } from 'vue';
const titleRef = ref(null);
const descriptionRef = ref(null);
const linkRef = ref(null);
const submitResource = () => {
console.log(titleRef.value.$el);
};
</script>
InputContainer.vue
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
id="example"
name="example"
/>
</div>
</template>
答案1
得分: 1
你可以使用 defineExpose
来将子组件的 ref 转发出去。
InputContainer.vue:
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
name="example"
ref="inputRef"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
const inputRef = ref(null);
defineExpose({
inputRef
});
</script>
然后,在 Form.vue
中,你可以这样访问它:
const submitResource = () => {
const titleInputEl = titleRef.value.inputRef;
};
英文:
You can use defineExpose
to forward a ref from the child.
InputContainer.vue:
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
name="example"
ref="inputRef"
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
const inputRef = ref(null);
defineExpose({
inputRef
});
</script>
Then, you can access it in Form.vue
.
const submitResource = () => {
const titleInputEl = titleRef.value.inputRef;
};
答案2
得分: 1
如果有帮助的话,在Vue中完成这个任务的典型方式是通过v-model
进行双向绑定。为了使其工作,您需要构建您的输入组件以通过:modelValue
属性接收值,并使它们触发@update:modelValue
事件:
Form.vue
<template>
<form @submit.prevent="submitResource">
<InputContainer v-model="formData.title" />
<InputContainer v-model="formData.description"/>
<InputContainer v-model="formData.link" />
<BaseButton type="submit" class="submit">Add Resource</BaseButton>
</form>
</template>
<script setup>
import BaseButton from './BaseButton.vue';
import InputContainer from './InputContainer.vue';
import { ref } from 'vue';
const formData = ref({
title: '',
description: '',
link: '',
});
const submitResource = () => {
console.log(formData.value);
};
</script>
InputContainer.vue
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
id="example"
:value="modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</div>
</template>
这种方法有几个优点,其中包括:
- 松耦合:父组件不需要了解子组件的内部结构
- 单一数据引用:所有数据都在数据层中表示,并且可靠地保持最新状态(而不是在模板中漂浮)- 这允许进行高效的验证、调试等。
- 可读性:绑定在模板中是显而易见的,而不是深藏在代码中的某个地方。
- 可移植性:几乎所有Vue组件都使用这种格式,您可以轻松地用您的输入组件替换其他组件,反之亦然。
- 无意外:如果其他开发人员与您的代码一起工作,他们会期望这种方式。
英文:
If it helps, the typical way to do this in Vue is through two-way binding with v-model
. For this to work, you build your input components to receive a value through the :modelValue
prop and have them emit an @update:modelValue
event:
Form.vue
<template>
<form @submit.prevent="submitResource">
<InputContainer v-model="formData.title" />
<InputContainer v-model="formData.description"/>
<InputContainer v-model="formData.link" />
<BaseButton type="submit" class="submit">Add Resource</BaseButton>
</form>
</template>
<script setup>
import BaseButton from './BaseButton.vue';
import InputContainer from './InputContainer.vue';
import { ref } from 'vue';
const formData = ref({
title: '',
description: '',
link: '',
});
const submitResource = () => {
console.log(formData.value);
};
</script>
InputContainer.vue
<template>
<div class="input-container">
<label for="example">Example</label>
<input
type="text"
id="example"
:value="modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</div>
</template>
This approach has several benefits, among them is:
- loose coupling: parent does not need to know about internal structure of child
- single source of reference: all data is represented in the data layer and reliably up to date (instead of floating around in the template) - this allows for efficient validation, debugging, etc.
- readability: binding is apparent in the template instead of buried somewhere in the code
- portability: pretty much all Vue components use this format, you can easily replace other input components with yours and vice versa
- no surprises: if other developers work with your code, this is what they'll expect
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论