Vuejs - Accordion

I am trying to create an accordion using vujs.

I found some examples on the Internet, but I want another. For SEO purposes, I use "is" and "inline-template", so the accordion is kind of static, not fully created in Vuejs.

I have 2 problems / questions:

1) I need to add the "is-active" class to the component based on user interaction (clicks), because of this I get the following error.

The property or method "contentVisible" is not defined in the instance, but is referenced during rendering. Be sure to declare the properties of the reactive data in the data option.

This is likely because I need to set it at instance level. But "contentVisible" has a value (true or false), different for each component.

Therefore, I thought about using the "contentVisible" array at the instance level, as well as the props (pass thru instance) and custom events for posterity to update the values ​​of the instance.

2) It can work, but it is a static array. How can I make a dynamic array (without knowing the number of component elements)?

<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
    }
})

Update I create the following code, but the custom event for sending the modification from component to instance does not work, the tab does not change

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>
+5
source share
3 answers

At point 1:

contentVisible vue, vue v-show, vue data, , .., , .

accordion , , , contentVisible , :

new Vue({
    el:'.accordion',
    data: {
       contentVisible: true
    }
    components: {
        'item': item
    }
})

, - , , visibleItemIndex, 1 n-1, n - .

v-show="visibleItemIndex == currentIndex" HTML.

, .

2:

v-for, . .

+1

:

<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>
0

It’s hard for me to understand what exactly you want or why you want, but I think it does?

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>
Run code
-1
source

Source: https://habr.com/ru/post/1663737/


All Articles