【问题标题】:Vuejs - AccordionVuejs - 手风琴
【发布时间】:2017-04-29 16:34:26
【问题描述】:

我正在尝试使用 vuejs 创建手风琴。

我在网上找了一些例子,但我想要的不一样。出于 SEO 的目的,我使用“is”和“inline-template”,所以手风琴是一种静态的,没有完全在 Vuejs 中创建。

我有 2 个问题/疑问:

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

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

这可能是因为我需要在实例级别设置它。但是“contentVisible”对于每个组件都有一个不同的值(真或假)。

所以我想在实例级别使用一个“contentVisible”数组和一个道具(通过实例)和子级的自定义事件来更新实例值。

2) 可以工作,但它是一个静态数组。如何制作动态数组(不知道item组件的数量)?

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

【问题讨论】:

    标签: javascript vue.js vue-component


    【解决方案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>
    

    【讨论】:

    • 它也适用于我。但是,我想始终打开第一个索引,当我单击另一个索引时,它应该同时打开和折叠第一个索引。你能建议我如何用这段代码实现它吗?谢谢
    【解决方案2】:

    第 1 点:

    您必须将contentVisible 定义为vue 实例变量,因为您已使用vue 指令v-show 访问它,它会在vue datawatchersmethods 等中搜索它,如果它没有找到任何参考,它会抛出这个错误。

    由于您的 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。您可以在此处查看文档。

    【讨论】:

    • 1) 我知道(我说过),但每个组件的 contentVisible 都不同。 2)我使用“inline-template”和“is”,将html源代码中的内容用于SEO目的(参见代码),所以在这种情况下我不能使用v-for,我需要以某种方式“阅读” " 来自 html 的组件数。
    • @user3541631 但new Vue() 中没有定义 contentVisible。
    • 是的,它不是,但如果我在 Vue() 中定义它可以有 2 个值:真或假(可见/隐藏)。如果我有 10 个项目(通过 contentVisible 属性控制),我该如何独立控制它们的可见性?
    • 如果我打开一个项目/面板时我关闭了其他项目/面板,您的解决方案有效,但如果我同时打开多个项目?另一件事,在前端可以添加一些我不知道的项目(后端生成的代码)。所以不知道n就不知道n,后端生成代码后如何获取?
    【解决方案3】:

    我很难理解您到底想要什么或为什么想要它,但我认为这样做可以吗?

    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>

    【讨论】:

    • 我想制作一架手风琴。 html 是由后端(python)而不是 Vue 生成的,就像你的答案一样。这就是我使用“inline-template”和 is=”item”(其中“item”是组件名称)的原因。当组件内的 div 内容处于活动/显示状态时,我需要将“is-active”类添加到组件 div。为此,我需要使用自定义事件从子级修改父属性 tabsactive,并且无法正常工作。检查以下代码: this.$emit('tabisactive', this.active) @tabisactive="tabsactive = $event" :class="{'is-active': tabsactive[1]}
    • 使用this.$parent是反模式,一个逃生舱口。因此不推荐。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 2017-10-26
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多