#vue.js #data-binding #custom-controls #vuejs3 #vue-composition-api
Вопрос:
Я следовал этому руководству, пытаясь создать пользовательский компонент формы в Vue 3 (api композиции, script setup
режим).
Когда я загружаю страницу, содержащую мой компонент, я получаю предупреждение консоли, подобное этому:
[Предупреждение Vue]: Отсутствует необходимая опора: «значение» в <ключ управления коммутатором=0 имя=»вопрос-8″ модель=не определена … >
Мой компонент (CSS опущен):
<template>
<input ref="switchElement"
v-bind="$attrs"
class="gui-switch"
@input="value = !value; emit('update:modelValue', value)"
type="checkbox"
role="switch"
:value="value" />
</template>
<script setup lang="ts">
import { defineEmit, defineProps, onMounted, ref } from "vue"
const props = defineProps<{
value: boolean | undefined,
}>()
const emit = defineEmit<{
(e: "update:modelValue", value: boolean | undefined): void,
}>()
const switchElement = ref<HTMLInputElement>()
onMounted(() => switchElement.value!.indeterminate = true)
</script>
Страница, содержащая его, использует его так:
<!-- v-for question in questions -->
<switch-control :name="`question-${question.id}`"
:model="feedbackData[`question-${question.id}`]"
:id="`question-${question.id}`" />
Я пробовал различные вещи, такие как изменение имени создаваемого события на input
или использование v-model
вместо :model
этого, но мне еще не удалось это исправить, и я не знаю, что еще можно попробовать.
ИЗМЕНИТЬ: Редактирование компонента для использования modelValue
таким образом:
<template>
<input ref="switchElement"
v-bind="$attrs"
class="gui-switch"
@input="modelValue = !modelValue; emit('update:modelValue', modelValue)"
type="checkbox"
role="switch"
:value="modelValue" />
</template>
<script setup lang="ts">
import { defineEmit, defineProps, onMounted, ref } from "vue"
const props = defineProps<{
modelValue: boolean | undefined,
}>()
const emit = defineEmit<{
(e: "update:modelValue", value: boolean | undefined): void,
}>()
const switchElement = ref<HTMLInputElement>()
onMounted(() => switchElement.value!.indeterminate = true)
</script>
Parent:
<!-- v-for question in questions -->
<switch-control :name="`question-${question.id}`"
v-model="feedbackData[`question-${question.id}`]"
:id="`question-${question.id}`" />
Leads to an outright error:
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next
at <SwitchControl key=0 name="question-8" modelValue=undefined ... >
Uncaught (in promise) TypeError: invalid 'instanceof' operand type
assertType runtime-core.esm-bundler.js:1877
validateProp runtime-core.esm-bundler.js:1841
validateProps runtime-core.esm-bundler.js:1817
initProps runtime-core.esm-bundler.js:1548
setupComponent runtime-core.esm-bundler.js:6500
mountComponent runtime-core.esm-bundler.js:4206
processComponent runtime-core.esm-bundler.js:4182
patch runtime-core.esm-bundler.js:3791
mountChildren runtime-core.esm-bundler.js:3975
EDIT2:
I managed to zoom in on whereabouts the problem is, but I still can’t quite figure out what’s happening.
I changed the component so that @input
is now @input="emit('update:modelValue', !modelValue)"
. I’ll include the relevant parts of the <script>
of the page that includes it:
import SwitchControl from "@/components/SwitchControl.vue"
import type { FeedbackQuestion } from "@/utils/api/story"
import { defineProps, ref } from "vue"
const props = defineProps<{
questions: {id: number}[],
}>()
const defaultModelValues = {
// These are hard-coded for debugging, ideally I'd want it to work with an empty initial object
"question-8": null,
"question-11": null,
}
const feedbackData = ref<Record<string, any>>(defaultModelValues)
Теперь симптомы:
- Когда код выглядит так, как описано выше , с определением prop и emit
boolean | undefined
, я получаю следующую ошибку, и весь цикл for не отображается:
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next
at <SwitchControl modelValue=null onUpdate:modelValue=fn<onUpdateModelValue> name="question-8" ... >
Uncaught (in promise) TypeError: invalid 'instanceof' operand type
- Если вместо этого я аннотирую опору и излучаю как просто
boolean
, элементы загружаются, и я получаю только предупреждение (см. Ниже). Если я затем попытаюсь изменить значение, нажав на элемент, я продолжу получать одно и то же предупреждение, и значение вообще не изменится, вместо чередования true и false, как и следовало ожидать.value
Атрибут в HTML, если я его проверю, ведет себя правильно (изначально»», затем чередуется между «истиной» и «ложью»).
[Vue warn]: Invalid prop: type check failed for prop "modelValue". Expected Boolean, got Null
at <SwitchControl modelValue=null onUpdate:modelValue=fn<onUpdateModelValue> name="question-8" ... >
Комментарии:
1. Я не могу воспроизвести проблему в этой демонстрации . Также обратите внимание, что реквизиты доступны только для чтения, поэтому ваш
@input
обработчик не должен пытаться переключатьсяmodelValue
.2. @tony19 Пожалуйста, посмотрите ПРАВКУ 2 к вопросу, может быть, это намекнет на то, что я не рассматриваю. Спасибо, что нашли время до сих пор.
3. Я не могу воспроизвести проблему EDIT2 в этой демонстрации . Можете ли вы поделиться ссылкой на репродукцию?
4. Я создал эту демонстрационную версию, максимально точно скопировав структуру моего реального приложения, но она по-прежнему не выдает ошибок, даже если это делает мое приложение. У вас есть какие-либо предложения по поводу того, что может вызвать проблему? У меня заканчиваются вещи, которые я мог бы попробовать. Константа-это ошибка
Uncaught (in promise) TypeError: invalid 'instanceof' operand type
, но я не вызываю никаких обещаний, и трассировка стека нигде не указывает на мой собственный код, только на esm-пакет.5. Ошибка исчезнет , только если я изменю
modelValue
тип для удаленияundefined
, но затем я получу предупреждение, потому что prop получил неопределенное значение вместо логического. Затем я должен жестко закодировать исходные значения модели, чтобы дать, и если я попытаюсь динамически вывести их из реквизитов следующим образом:feedbackData.value = Object.fromEntries(props.questions.map((q) => [
вопрос-${q.id}, false]))
Я снова получаю предупреждения: результирующий объект регистрируется как полностью пустой, какprops.questions
и он сам. Если я зарегистрирую переданный объект,:questions
он будет содержать ожидаемый массив вопросов…
Ответ №1:
В дочернем компоненте вы должны определить value
как modelValue
:
<input ref="switchElement"
...
:value="modelValue" />
</template>
.....
const props = defineProps<{
modelValue : boolean | undefined,
}>()
и в родительском использовании v-model
вместо :model
:
v-model="feedbackData[`question-${question.id}`]"
Комментарии:
1. Похоже, что это на правильном пути, но внесение этих изменений приводит к ошибке, из-за которой компонент и его родительский элемент теперь вообще не загружаются. Пожалуйста, проверьте правку исходного вопроса.