我正在使用Vue 2和Vuetify(不是Vue 3)创建表单构建器网站。在发现有问题之前,我一直做得很好。就是这种情况。我使用以下代码从反应性数组渲染了文本字段(输入)。
<template>
// ... some other unrelated code
<template v-if="answer.type !== 1">
<v-col
v-for="(_, i) in answer.options"
:key="`#question-${answer.id}-${i}`"
cols="12"
>
<div class="flex flex-row justify-between items-center">
<TextField
v-model="answer.options[i]"
class="ml-4"
label="Option"
underlined
hideLabel
/>
<v-btn @click="deleteOption(i)" icon>
<v-icon>mdi-close</v-icon>
</v-btn>
</div>
</v-col>
<v-col>
<TextButton @click="addOption()" text="+ ADD OPTION" />
</v-col>
</template>
// ... some other unrelated code
</template>
<script>
import { reactive, ref, watch } from '@vue/composition-api'
import useInquiry from '@/composables/useInquiry'
import TextButton from '@/components/clickables/TextButton.vue'
import TextField from '@/components/inputs/TextField.vue'
export default {
components: { TextField, TextButton },
setup() {
const { answer, addOption, deleteOption } = useInquiry()
return { answer, addOption, deleteOption }
}
}
</script>
这是我的useInquiry可组合逻辑
import { reactive, watch, se } from '@vue/composition-api'
import ID from '@/helpers/id'
export default () => {
const answer = reactive({
id: ID(), // this literally just generates an ID
type: 2,
options: ['', '']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = []
answer.options = temp
};
return { answer, addOption, deleteOption }
}
最后,这是我的TextField.vue
<template>
<v-text-field
v-model="inputValue"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
</template>
<script>
import { ref, watch } from '@vue/composition-api'
export default {
model: {
props: 'value',
event: 'change'
},
props: {
label: String,
value: String,
password: Boolean,
underlined: Boolean,
large: Boolean,
hideLabel: Boolean
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return { inputValue }
}
}
</script>
问题是,每当单击删除按钮时,即使我没有单击最后一个,被删除的输入也始终是数组中的最后一个。我试图通过使用Vue的composition watch方法观看它来记录我的反应性数组。显然,数据已正确更新。问题在于v模型看起来不同步,最后一个输入始终是被删除的输入。
答案 0 :(得分:1)
对我很好.... TextField.vue
问题在TextField.vue
中。您在setup
的{{1}}内部实际所做的是(Vue 2 API):
TextField.vue
...这是data() {
return {
inputValue: this.value
}
}
数据成员的一次一次初始化,其值为inputValue
prop。因此,当删除value
之一并重用组件时(因为Vue一直都在这样做-尤其是在options
中使用索引时):key
不会更新为新值inputValue
道具中的...
您根本不需要value
或inputValue
选项,只需将其删除并使用此模板即可:
model
请注意,在我的示例中,我使用的是<v-text-field
:value="value"
@input="$emit('input', $event)"
:label="label"
:single-line="hideLabel"
:type="password ? 'password' : 'text'"
:outlined="!underlined"
:dense="!large"
hide-details="auto"
/>
而不是$event.target.value
,因为我使用的是本机$event
元素,而不是Vuetify的自定义组件输入...
工作示例...
<input>
const {
reactive,
ref,
watch
} = VueCompositionAPI
Vue.use(VueCompositionAPI)
const BrokenInput = {
model: {
props: 'value',
event: 'change'
},
props: {
value: String,
},
setup(props, context) {
const inputValue = ref(props.value)
watch(inputValue, (currInput, prevInput) => {
context.emit('change', currInput)
})
return {
inputValue
}
},
template: `<input type="text" v-model="inputValue" />`
}
const FixedInput = {
props: {
value: String,
},
template: `<input type="text" :value="value" @input="$emit('input', $event.target.value)"/>`
}
const useInquiry = () => {
const answer = reactive({
id: 1,
type: 2,
options: ['1', '2', '3', '4', '5']
})
const addOption = () => {
answer.options.push('')
}
const deleteOption = at => {
const temp = answer.options.filter((_, i) => i !== at)
answer.options = temp
};
return {
answer,
addOption,
deleteOption
}
}
const app = new Vue({
components: { 'broken-input': BrokenInput, 'fixed-input': FixedInput },
setup() {
return useInquiry()
},
})
app.$mount('#app')