Vue2-“TypeError:无法读取未定义的属性(读取‘值’)”
2022-03-06
3983
我有一个带有自定义输入组件的应用,我试图在保存时向父组件发出更改事件,并通过提交/分派将这些值发送到 $store。我确认父组件可以在我之前调试组件时接收这些值(正在检索最初从此应用中的随机器生成的相同值,并且不明白为什么我会收到此错误:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read properties of undefined (reading 'value')"
found in
---> <CustomInput>
它仅在用户尝试手动编辑新标题/副标题时显示,并在每次击键后显示。这是计时错误吗??
自定义输入:
<template>
<div>
<label for="title">Edit Title: </label>
<input
type="text"
id="title"
:updateTitle="updateTitle"
v-model="inputTitle"
/>
<label for="title">Edit Subtitle: </label>
<input
type="text"
id="subtitle"
:updateSubtitle="updateSubtitle"
v-model="inputSubtitle"
/>
</div>
</template>
<script>
export default {
name: 'CustomInput',
props: {
value: {
type: Object,
required: true,
},
},
computed: {
updateTitle() {
console.log('updateTitle: ', this.value.title);
return this.value.title;
},
updateSubtitle() {
console.log('updateSubtitle: ', this.value.subtitle);
return this.value.subtitle;
},
inputTitle: {
get() {
return this.value.title;
},
set(title) {
console.log('setting new title: ', title);
this.$emit('input', title);
},
},
inputSubtitle: {
get() {
return this.value.subtitle;
},
set(subtitle) {
console.log('setting new subtitle: ', subtitle);
this.$emit('input', subtitle);
},
},
},
};
</script>
父组件:
<template>
<main class="home-page page">
<div v-if="!editMode" class="display-information">
<div class="title">
<span class="bold">Title: </span>{{title}}
</div>
<div class="subtitle">
<span class="bold">Subtitle: </span>{{subtitle}}
</div>
<div class="controls">
<button id="randomize-button" class="control-button" @click="randomizeTitleAndSubtitle">
Randomize
</button>
<button id="edit-button" class="control-button" @click="onEdit">Edit</button>
</div>
</div>
<div v-else class="edit-controls">
<CustomInput
:value="{ title, subtitle }"
@input="onSave(v = { title, subtitle }, $event.target.value)"
/>
<div class="controls">
<button id="cancel-button" class="control-button" @click="onCancel">Cancel</button>
<button id="save-button" class="control-button" @click="onSave">Save</button>
</div>
</div>
</main>
</template>
<script>
import CustomInput from '@/components/CustomInput.vue';
import { mapState, mapActions } from 'vuex';
export default {
name: 'Home',
components: {
CustomInput,
},
data() {
return {
editMode: false,
};
},
computed: {
...mapState(['title', 'subtitle']),
},
methods: {
...mapActions(['randomizeTitleAndSubtitle', 'updateTitleAndSubtitle']),
onEdit() {
this.editMode = true;
},
onCancel() {
this.editMode = false;
},
onSave(v) {
this.editMode = false;
console.log('returned value object: ', v);
this.$store.dispatch('UPDATE_TITLE', v.title);
this.$store.dispatch('UPDATE_SUBTITE', v.subtitle);
},
},
mounted() {
this.randomizeTitleAndSubtitle();
},
};
</script>
2个回答
错误指向
@input
:
<CustomInput
:value="{ title, subtitle }" ❌
@input="onSave(v = { title, subtitle }, $event.target.value)"
/>
CustomInput
发出带有字符串的
input
事件:
export default {
⋮
computed: {
⋮
inputTitle: {
⋮
set(title) { 👇
this.$emit('input', title);
},
},
inputSubtitle: {
⋮
set(subtitle) { 👇
this.$emit('input', subtitle);
},
},
},
};
因此
$event
就是该字符串,它不包含
target
属性,从而导致您观察到的错误。
我认为您可能已从
<input>
元素上的
@input
复制了该代码,在这种情况下
$event
应该是
InputEvent
对象。
解决方案
解决问题,从标记中删除
.target.value
:
<CustomInput
:value="{ title, subtitle }" ✅
@input="onSave(v = { title, subtitle }, $event)"
/>
tony19
2022-03-07
弄清楚并清理与我最初寻找的内容相关的代码。在数据中添加一个空对象作为来自自定义输入组件发出的对象值的占位符,并从自定义输入组件中删除不必要的代码。将其清理为仅包含两个单独的 $emit 事件的最小值 ~ 只有一个!
自定义输入:
<template>
<div>
<label for="title">Edit Title: </label>
<input
type="text"
id="title"
:setTitle="setTitle"
ref="title"
:value="value.title"
@input="updateValue()"
/>
<label for="title">Edit Subtitle: </label>
<input
type="text"
id="subtitle"
:setSubtitle="setSubtitle"
ref="subtitle"
:value="value.subtitle"
@input="updateValue()"
/>
</div>
</template>
<script>
export default {
name: 'CustomInput',
props: {
value: {
type: Object,
required: true,
},
},
computed: {
setTitle() {
// console.log('set title: ', this.value.title);
return this.value.title;
},
setSubtitle() {
// console.log('set subtitle: ', this.value.subtitle);
return this.value.subtitle;
},
},
methods: {
updateValue() {
this.$emit('input', {
title: this.$refs.title.value,
subtitle: this.$refs.subtitle.value,
});
},
},
};
</script>
父级:
<template>
<main class="home-page page">
<!-- <span class="bold">Title:</span> {{ title }} <br>
<span class="bold">Subtitle:</span> {{ subtitle }}
<hr> -->
<div v-if="!editMode" class="display-information">
<div class="title">
<span class="bold">Title: </span>{{title}}
</div>
<div class="subtitle">
<span class="bold">Subtitle: </span>{{subtitle}}
</div>
<div class="controls">
<button id="randomize-button" class="control-button" @click="randomizeTitleAndSubtitle">
Randomize
</button>
<button id="edit-button" class="control-button" @click="onEdit">Edit</button>
</div>
</div>
<div v-else class="edit-controls">
<CustomInput
:value="{ title, subtitle }"
@input="v => onEdit(v)"
/>
<div class="controls">
<button id="cancel-button" class="control-button" @click="onCancel">Cancel</button>
<button id="save-button" class="control-button" @click="onSave(v)">Save</button>
</div>
</div>
</main>
</template>
<script>
// @ is an alias to /src
import CustomInput from '@/components/CustomInput.vue';
import { mapState, mapActions } from 'vuex';
export default {
name: 'Home',
components: {
CustomInput,
},
data() {
return {
editMode: false,
v: {},
};
},
computed: {
...mapState(['title', 'subtitle']),
},
methods: {
...mapActions(['randomizeTitleAndSubtitle', 'updateTitleAndSubtitle']),
onEdit(v) {
this.editMode = true;
this.v = v;
console.log('returned value object: ', v);
},
onCancel() {
this.editMode = false;
},
onSave() {
this.editMode = false;
this.$store.dispatch('updateTitleAndSubtitle', this.v);
},
},
mounted() {
this.randomizeTitleAndSubtitle();
},
};
</script>
<style lang="stylus" scoped>
.bold
font-weight bold
.controls
width 100%
display flex
justify-content space-around
max-width 20rem
margin-top 2rem
margin-left auto
margin-right auto
.control-button
height 2.5rem
border-radius 1.25rem
background-color white
border 0.125rem solid black
padding-left 1.25rem
padding-right 1.25rem
&:hover
cursor pointer
background-color rgba(0, 0, 0, 0.1)
</style>
Waffles
2022-03-07