Vuejs - 手风琴

时间:2016-12-14 11:04:17

标签: vue.js vue-component

我试图用vuejs创建手风琴。

我在网上找到了一些例子,但我想要的是不同的。对于SEO目的,我使用"是"和"内联模板",所以手风琴是在Vuejs中没有完全创建的静态。

我有2个问题/问题:

1)我需要添加一个类" is-active"在基于用户交互(点击)的组件上,因此我收到以下错误。

  

属性或方法" contentVisible"没有在实例上定义但是   在渲染期间引用。确保声明反应数据   数据选项中的属性。

这可能是因为我需要在实例级别设置它。但是" 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
    }
})

更新 我创建了以下代码,但是将修改从组件发送到实例的自定义事件不起作用,tabactive未更改

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>

3 个答案:

答案 0 :(得分:1)

第1点:

您必须将contentVisible定义为vue实例变量,因为您已使用vue指令v-show访问它,它会在vue datawatchers,{ {3}}等,如果找不到任何引用,则会抛出此错误。

由于您的accordion元素与父组件相关联,您可能需要在其中添加contentVisible数据,如下所示:

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

如果您有多个项目,您可以使用其他技术来展示其中一个项目,例如数据变量visibleItemIndex可以从1更改为n-1,其中n是项目数。

在这种情况下,HTML中会有v-show="visibleItemIndex == currentIndex"

您也可以使用哈希来保存要显示的索引以及要折叠的索引。

第2点:

如果您有动态数组,则可以使用methods。你可以在这里看到文档。

答案 1 :(得分:0)

这对我有用:

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

答案 2 :(得分:-1)

我真的很难理解你想要的是什么或为什么你想要它,但我认为这样做了吗?

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>