问题
I am creating a features page for a product. When you click the feature name, it should expand a box below and provide a description.
I took a small snippet of my data which is basically structured like this:
{
"Section": {
"Page1": {
"FeatureName": "Feature desc",
"FeatureName": "Feature desc"
},
"Page2": {
"FeatureName": "Feature desc",
"FeatureName": "Feature desc"
}
}
}
I have figured out a few ways to do this, but personally don't think any of them are great approaches.
Looping through the json/object and adding a show property to each feature. Then I can just toggle bool to show/hide
From my backend server, actually provide the show property to begin with so its ready to use with vue
Neither solution will make these components re-usable (ie, I can use this as an accordion in the future, but I have to pollute my source data with show properties OR do some heavy iterating to add properties, which I dont always know the depth/levels of.)
So I ask, is there a better approach or is what I have listed the only ways?
回答1:
Implementing expand/collapse to show more details is a pretty common problem. Here are a few ways you can do it:
- Add a boolean property to each object in the collection. This is effectively what both of your approaches boil down to. I wouldn't expect the server to get involved, this is entirely a UI concern.
- Store the show/hide values in a separate array/object. Just a big array or object of booleans. This is horrible but it does avoid mutating the original data. In your case the original data is in an object so you'd also use an object for the booleans, keyed by the same keys as the original object.
- Another way to avoid mutating the original data is to wrap each object. e.g.
{ Page1: { show: false, page: { FeatureName: ... } }. The downside with this structure is that the template must be written to handle the extra nesting. - Create a component to hold the relevant state for each item. This is usually the best solution but the problem is that the show/hide state is internal to the component so it isn't easy to change it from the outside. This makes implementing something like 'Show all' a pain. So long as you don't need access to that state from outside it is a neat solution. Example at the end.
All of this assumes that each of the expand boxes should act independently. If you want them to be linked so that only one can be open at once it all gets much simpler as you can just store the id of the currently expanded item as a data property.
Now, as promised, an example of using a component to hold the relevant state for each item:
const expander = {
props: ['item'],
data () {
return {
expanded: false
}
},
template: `
<div>
<h4>{{ item.title }}</h4>
<button @click="expanded = !expanded">Toggle</button>
<p v-if="expanded">{{ item.description }}</p>
</div>
`
}
new Vue({
el: '#app',
components: {
expander
},
data () {
return {
"Section": {
"Page1": {
"title": "Title 1",
"description": "Blah blah blah blah"
},
"Page2": {
"title": "Title 2",
"description": "More more more more"
}
}
}
}
})
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
<expander
v-for="(item, propertyName) in Section"
:key="propertyName"
:item="item"
></expander>
</div>
来源:https://stackoverflow.com/questions/58721567/how-to-show-hide-parts-of-an-object-after-in-vue