Vuejs-手风琴
Vuejs - Accordion
我正在尝试使用 vuejs 创建手风琴。
我在网上找了一些例子,但我想要的不一样。出于 SEO 目的,我使用 "is" 和 "inline-template",所以手风琴是一种静态的,没有完全在 Vuejs 中创建。
我有2个problems/questions:
1) 我需要根据用户交互(点击)在组件上添加 class "is-active",因此我收到以下错误。
Property or method "contentVisible" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
这可能是因为我需要在实例级别设置它。但是 "contentVisible" 每个组件的值(真或假)都不同。
所以我想在实例级别使用一个 "contentVisible" 数组和一个道具(通过实例)和子项上的自定义事件来更新实例值。
2) 可以工作,但它是一个静态数组。如何制作动态数组(不知道项目组件的数量)?
<div class="accordion">
<div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
var item = {
data: function() {
return {
contentVisible: true
}
},
methods: {
toggle: function(){
this.contentVisible = !this.contentVisible
}
}
}
new Vue({
el:'.accordion',
components: {
'item': item
}
})
更新
我创建了以下代码,但是将修改从组件发送到实例的自定义事件不起作用,tabsactive 没有改变
var item = {
props: ['active'],
data: function() {
return {
contentVisible: false
}
},
methods: {
toggle: function(index){
this.contentVisible = !this.contentVisible;
this.active[index] = this.contentVisible;
**this.$emit('tabisactive', this.active);**
console.log(this.active);
}
}
}
new Vue({
el:'.accordion',
data: {
tabsactive: [false, false]
},
components: {
'item': item
}
})
<div class="accordion" **@tabisactive="tabsactive = $event"**>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[0]}">
<div>
<a @click="toggle(0)" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[1]}">
<div>
<a @click="toggle(1)" class="accordion-title" > Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
第 1 点:
您必须将 contentVisible
定义为 vue 实例变量,因为您已经使用 vue 指令 v-show, it searches this in vue data, watchers, methods 等访问它,如果它没有找到任何引用,则会抛出此错误。
由于您的 accordion
元素与父组件相关联,您可能必须在其中添加 contentVisible
数据,如下所示:
new Vue({
el:'.accordion',
data: {
contentVisible: true
}
components: {
'item': item
}
})
如果您有多个项目,您可以使用其他一些技术来显示其中一个,比如有一个数据变量 visibleItemIndex
,它可以从 1 变为 n-1,其中 n 是项目的数量。
在这种情况下,您将在 HTML 中得到 v-show="visibleItemIndex == currentIndex"
。
你也可以用散列来保存哪些索引要取消显示,哪些要折叠。
第 2 点:
如果您有动态数组,则可以使用 v-for。您可以在此处查看文档。
我真的很难理解你到底想要什么或者你为什么想要它,但我认为这样做可以吗?
Vue.component('accordion-item', {
template: '#accordion-item',
methods: {
toggle() {
if(this.contentVisible){
return
}
if(this.$parent.activeTab.length >= 2){
this.$parent.activeTab.shift()
}
this.$parent.activeTab.push(this)
}
},
computed: {
contentVisible() {
return this.$parent.activeTab.some(c => c === this)
}
}
})
const Accordion = Vue.extend({
data() {
return {
activeTab: []
}
},
methods: {
handleToggle($event) {
this.activeTab = []
}
}
})
document.querySelectorAll('.accordion').forEach(el => new Accordion().$mount(el))
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<template id="accordion-item">
<div class="accordion-item" :class="{ 'is-active': contentVisible}">
<a href="#" @click="toggle" class="accordion-title"><slot name="title"></slot></a>
<div v-show="contentVisible" class="accordion-content" @click="$emit('toggle', $event)">
<slot name="content"></slot>
</div>
</div>
</template>
<div class="accordion">
<accordion-item @toggle="handleToggle">
<p slot="title">a title</p>
<p slot="content">there are words here</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">titles are for clicking</p>
<p slot="content">you can also click on the words</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">and another</p>
<p slot="content">only two open at a time!</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">and #4</p>
<p slot="content">amazing</p>
</accordion-item>
</div>
这对我有用:
<template>
<div>
<ul>
<li v-for="index in list" :key="index._id">
<button @click="contentVisible === index._id ? contentVisible = false : contentVisible = index._id">{{ index.title }}</button>
<p v-if='contentVisible === index._id'>{{ index.item }}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "sameName",
data() {
return {
contentVisible: false,
list: [
{
_id: id1,
title: title1,
item: item1
},
{
_id: id2,
title: title2,
item: item2
}
]
};
},
};
</script>
我正在尝试使用 vuejs 创建手风琴。
我在网上找了一些例子,但我想要的不一样。出于 SEO 目的,我使用 "is" 和 "inline-template",所以手风琴是一种静态的,没有完全在 Vuejs 中创建。
我有2个problems/questions:
1) 我需要根据用户交互(点击)在组件上添加 class "is-active",因此我收到以下错误。
Property or method "contentVisible" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
这可能是因为我需要在实例级别设置它。但是 "contentVisible" 每个组件的值(真或假)都不同。
所以我想在实例级别使用一个 "contentVisible" 数组和一个道具(通过实例)和子项上的自定义事件来更新实例值。
2) 可以工作,但它是一个静态数组。如何制作动态数组(不知道项目组件的数量)?
<div class="accordion">
<div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :class="{ 'is-active': contentVisible}" >
<div>
<a @click="toggle" class="accordion-title"> Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
var item = {
data: function() {
return {
contentVisible: true
}
},
methods: {
toggle: function(){
this.contentVisible = !this.contentVisible
}
}
}
new Vue({
el:'.accordion',
components: {
'item': item
}
})
更新 我创建了以下代码,但是将修改从组件发送到实例的自定义事件不起作用,tabsactive 没有改变
var item = {
props: ['active'],
data: function() {
return {
contentVisible: false
}
},
methods: {
toggle: function(index){
this.contentVisible = !this.contentVisible;
this.active[index] = this.contentVisible;
**this.$emit('tabisactive', this.active);**
console.log(this.active);
}
}
}
new Vue({
el:'.accordion',
data: {
tabsactive: [false, false]
},
components: {
'item': item
}
})
<div class="accordion" **@tabisactive="tabsactive = $event"**>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[0]}">
<div>
<a @click="toggle(0)" class="accordion-title"> Title A1</a>
<div v-show="contentVisible" class="accordion-content">albatros</div>
</div>
</div>
<div class="accordion-item" is="item" inline-template :active="tabsactive" :class="{'is-active': tabsactive[1]}">
<div>
<a @click="toggle(1)" class="accordion-title" > Title A2</a>
<div v-show="contentVisible" class="accordion-content">lorem ipsum</div>
</div>
</div>
</div>
第 1 点:
您必须将 contentVisible
定义为 vue 实例变量,因为您已经使用 vue 指令 v-show, it searches this in vue data, watchers, methods 等访问它,如果它没有找到任何引用,则会抛出此错误。
由于您的 accordion
元素与父组件相关联,您可能必须在其中添加 contentVisible
数据,如下所示:
new Vue({
el:'.accordion',
data: {
contentVisible: true
}
components: {
'item': item
}
})
如果您有多个项目,您可以使用其他一些技术来显示其中一个,比如有一个数据变量 visibleItemIndex
,它可以从 1 变为 n-1,其中 n 是项目的数量。
在这种情况下,您将在 HTML 中得到 v-show="visibleItemIndex == currentIndex"
。
你也可以用散列来保存哪些索引要取消显示,哪些要折叠。
第 2 点:
如果您有动态数组,则可以使用 v-for。您可以在此处查看文档。
我真的很难理解你到底想要什么或者你为什么想要它,但我认为这样做可以吗?
Vue.component('accordion-item', {
template: '#accordion-item',
methods: {
toggle() {
if(this.contentVisible){
return
}
if(this.$parent.activeTab.length >= 2){
this.$parent.activeTab.shift()
}
this.$parent.activeTab.push(this)
}
},
computed: {
contentVisible() {
return this.$parent.activeTab.some(c => c === this)
}
}
})
const Accordion = Vue.extend({
data() {
return {
activeTab: []
}
},
methods: {
handleToggle($event) {
this.activeTab = []
}
}
})
document.querySelectorAll('.accordion').forEach(el => new Accordion().$mount(el))
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<template id="accordion-item">
<div class="accordion-item" :class="{ 'is-active': contentVisible}">
<a href="#" @click="toggle" class="accordion-title"><slot name="title"></slot></a>
<div v-show="contentVisible" class="accordion-content" @click="$emit('toggle', $event)">
<slot name="content"></slot>
</div>
</div>
</template>
<div class="accordion">
<accordion-item @toggle="handleToggle">
<p slot="title">a title</p>
<p slot="content">there are words here</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">titles are for clicking</p>
<p slot="content">you can also click on the words</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">and another</p>
<p slot="content">only two open at a time!</p>
</accordion-item>
<accordion-item @toggle="handleToggle">
<p slot="title">and #4</p>
<p slot="content">amazing</p>
</accordion-item>
</div>
这对我有用:
<template>
<div>
<ul>
<li v-for="index in list" :key="index._id">
<button @click="contentVisible === index._id ? contentVisible = false : contentVisible = index._id">{{ index.title }}</button>
<p v-if='contentVisible === index._id'>{{ index.item }}</p>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "sameName",
data() {
return {
contentVisible: false,
list: [
{
_id: id1,
title: title1,
item: item1
},
{
_id: id2,
title: title2,
item: item2
}
]
};
},
};
</script>