我试图根据父对象(App.vue)中数组的状态来呈现组件。我完全不确定这是该用例的正确方法(对Vue而言是新手,不是经验丰富的程序员),因此如果您认为这不是正确的考虑方式,我将很乐意为您提供建议。
我正在尝试构建一个由一系列问题组成的疑难解答程序。每个问题都是一个数据组成部分,如下所示:
data: function() {
return {
id: 2,
question: "Has it worked before?",
answer: undefined,
requires: [
{
id: 1,
answer: "Yes"
}
]
}
}
如果对问题1的回答为“是”,则假定显示此问题。
我的问题是我不确定如何有条件地渲染组件。当前的方法是在收到响应后从组件发送事件,并在父级中侦听该事件。事件触发时,父级更新一个数组,其中保存所有已回答问题的“状态”。现在,我需要检查每个组件中的该数组,以查看是否存在已回答的问题,如果满足正确的条件,请显示该问题。
我的问题是:如何检查父项中的数据并根据其显示/隐藏我的组件?而且-这是一个好主意还是我应该做些不同的事情?
还有更多代码可供参考:
App.vue
<template>
<div id="app">
<div class="c-troubleshooter">
<one @changeAnswer="updateActiveQuestions"/>
<two @changeAnswer="updateActiveQuestions"/>
</div>
</div>
</template>
<script>
import one from './components/one.vue'
import two from './components/two.vue'
export default {
name: 'app',
components: {
one,
two
},
data: function() {
return {
activeQuestions: []
}
},
methods: {
updateActiveQuestions(event) {
let index = this.activeQuestions.findIndex( ({ id }) => id === event.id );
if ( index === -1 ) {
this.activeQuestions.push(event);
} else {
this.activeQuestions[index] = event;
}
}
}
}
</script>
two.vue
<template>
<div v-if="show">
<h3>{{ question }}</h3>
<div class="c-troubleshooter__section">
<div class="c-troubleshooter__input">
<input type="radio" id="question-2-a" name="question-2" value="ja" v-model="answer">
<label for="question-2-a">Ja</label>
</div>
<div class="c-troubleshooter__input">
<input type="radio" id="question-2-b" name="question-2" value="nej" v-model="answer">
<label for="question-2-b">Nej</label>
</div>
</div>
</div>
</template>
<script>
export default {
data: function() {
return {
id: 2,
question: "Bla bla bla?",
answer: undefined,
requires: [
{
id: 1,
answer: "Ja"
}
]
}
},
computed: {
show: function() {
// Check in parent to see if requirements are there, if so return true
return true;
}
},
watch: {
answer: function() {
this.$emit('changeAnswer', {
id: this.id,
question: this.question,
answer: this.answer
})
}
}
}
</script>
答案 0 :(得分:1)
正如@Roy J在评论中建议的那样,问题数据可能属于父级。父母负责处理所有数据,并决定应提出哪些问题。但是,有很多策略可以做到这一点:
v-if
或v-show
有条件地显示问题:也许显示一些问题的逻辑根本不是通用的。它可能取决于更多的东西,用户设置...我不知道。如果是这种情况,只需直接在父项中有条件地呈现问题,因此您无需访问任何问题中的整个问题数据。代码应类似于以下内容:
<template>
<div id="app">
<div class="c-troubleshooter">
<one @changeAnswer="updateActiveQuestions" v-if="displayQuestion(1)"/>
<two @changeAnswer="updateActiveQuestions" v-if="displayQuestion(2)"/>
</div>
</div>
</template>
<script>
import one from './components/one.vue'
import two from './components/two.vue'
export default {
name: 'app',
components: {
one,
two
},
data: function() {
return {
activeQuestions: [],
}
},
methods: {
updateActiveQuestions(event) {
let index = this.activeQuestions.findIndex( ({ id }) => id === event.id );
if ( index === -1 ) {
this.activeQuestions.push(event);
} else {
this.activeQuestions[index] = event;
}
},
displayQuestion(index){
// logic...
}
},
}
</script>
如果只有在回答或查看前一个问题或类似问题时才可见任何问题,则可以将其作为每个问题的道具,以便他们知道是否必须提出:
<template>
<div id="app">
<div class="c-troubleshooter">
<one @changeAnswer="updateActiveQuestions"/>
<two @changeAnswer="updateActiveQuestions" prev="activeQuestions[0]"/>
</div>
</div>
</template>
在two.vue
中:
props: ['prev'],
computed: {
show: function() {
return this.prev && this.prev.status === 'ANSWERED';
// or some logic related to this, idk
}
},
编码时,您可以将整个问题数据作为道具传递给每个问题组件,然后在计算属性中使用它。这不是我要做的,而是有效的,并且由于对象是引用,所以不一定表现不佳。
每个问题都有一个one.vue
,two.vue
似乎很奇怪,而且肯定不能很好地扩展。
由于每个问题的模板可能有所不同,我不太确定如何模块化。例如,有些包含图片或自定义元素,而另一些则没有。
如果每个问题的模板真的不同,这可能会变得很复杂。但是,如果我怀疑它们共享公用的HTML结构,并在底部具有定义的标头或公用的“询问”按钮,并且这样的话,那么您should be able to address this using Vue slots。
除了模板问题外,我想您的应用程序中的每个问题都可以得到任意数量的“子问题”(因为two.vue
具有question-2-a
和question-2-b
)。这将需要用于问题数据的复杂灵活的数据结构(当您开始添加多个选择,多个可能的答案等时,该结构将变得更加复杂)。这可能会变得非常复杂,但您可能应该对此进行处理,直到可以使用单个question.vue
组件为止,这肯定会有所回报。
您正在v-model
模板中使用answer
到two.vue
,然后使用观察程序来跟踪answer
变量中的更改并发出事件。这很复杂且难以理解,您可以在@input
元素上使用@change
或<input>
事件:
<input type="radio" id="question-2-a" name="question-2" value="ja" v-model="answer" @input="emitAnswer">
然后用一个方法代替观察者:
emitAnswer() {
this.$emit('changeAnswer', {
id: this.id,
question: this.question,
answer: this.answer
})
答案 1 :(得分:0)
这是一个相当广泛的问题,但是我将尝试给出一些有用的指导。
第一个data
应该用于内部状态。很多时候,一个组件应该使用props
来处理您可能拥有的data
。情况就是这样:问题需要由父级协调,因此父级应拥有数据。这样,您就可以做出明智的功能来控制问题组件是否显示。
拥有父级数据的情况下,您还可以制作一个根据自己的道具进行配置的问题组件。或者,您可能有几种不同的问题组件类型(可以使用:is
选择正确的问题组件类型),但是几乎可以肯定的是,如果您将其问题/答案/其他信息传入,它们中的某些可以重用。
要更新答案,您将从问题组件中发出更改,并让父级实际更改值。我使用一个可计算的可设置表,以允许在组件中使用v-model
。
new Vue({
el: '#app',
data() {
return {
questions: [{
id: 1,
question: 'blah 1?',
answer: null
},
{
id: 2,
question: 'blah 2?',
answer: null,
// this is bound because data is a function
show: () => {
const q1 = this.questions.find((q) => q.id === 1);
return Boolean(q1.answer);
}
},
{
id: 3,
question: 'Shows anyway?',
answer: null
}
]
};
},
components: {
questionComponent: {
template: '#question-template',
props: ['props'],
computed: {
answerProxy: {
get() {
return this.answer;
},
set(newValue) {
this.$emit('change', newValue);
}
}
}
}
}
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
<div class="c-troubleshooter">
<question-component v-for="q in questions" v-if="!q.show || q.show()" :props="q" @change="(v) => q.answer = v" :key="q.id">
</question-component>
</div>
<h2>State</h2>
<div v-for="q in questions" :key="q.id">
{{q.question}} {{q.answer}}
</div>
</div>
<template id="question-template">
<div>
{{props.question}}
<div class="c-troubleshooter__input">
<input type="radio" :id="`question-${props.id}-a`" :name="`question-${props.id}`" value="ja" v-model="answerProxy">
<label :for="`question-${props.id}-a`">Ja</label>
</div>
<div class="c-troubleshooter__input">
<input type="radio" :id="`question-${props.id}-b`" :name="`question-${props.id}`" value="nej" v-model="answerProxy">
<label :for="`question-${props.id}-b`">Nej</label>
</div>
</div>
</template>