how to make bootstrap4 collapse work in vue?

前端 未结 3 975
长发绾君心
长发绾君心 2021-01-27 18:19

I am using bootstrap 4.3.1 and vue@2.6.10

I have this menu (is using collapse - and I don`t want to use JQuery):

 
  • <
  • 相关标签:
    3条回答
    • 2021-01-27 18:42

      No jQuery or bootstrap-vue ...

      Create a function in the Component to handle the normal Bootstrap class and timing logic...

        data() {
          return {
            classArr: ['collapse'],
            styleObj: {}
          };
        },
        methods: {
          toggleCollapse(ref) {
              let show = this.classArr.indexOf('show')>-1?false:'show'
              this.classArr = ['collapsing']
              setTimeout(() => {
                  if (show){
                      let height = this.$refs[ref].firstChild.clientHeight + 'px';
                      this.styleObj = { height }
                  }
                  else {
                      this.styleObj = {}  
                  }
              }, 10)
              setTimeout(() => {
                  this.classArr = ['collapse', show]
              }, 340)
          }
        }
      

      In the component template, bind the class and style attrs to the data manipulated by the method. The ref of the specific collapse is passed in to the method...

        <li class="nav-item">
              <a class="nav-link" href="#sidebar-products" role="button" @click="toggleCollapse('sidebar')">
                  <i class="ni ni-single-copy-04 text-primary"></i>
                  <span class="nav-link-text">Products</span>
              </a>
              <div :class="classArr" :style="styleObj" id="sidebar-products" ref="sidebar">
                  <ul class="nav nav-sm flex-column">
                      <li class="nav-item">
                          <a href="#" class="nav-link">Item List 1</a>
                      </li>
                      <li class="nav-item">
                          <a href="#" class="nav-link">Item List 2</a>
                      </li>
                  </ul>
              </div>
        </li>
      

      https://www.codeply.com/p/GA5CaNMzmc

      EDIT: I updated the demo to make it scaleable for multiple collapses

      0 讨论(0)
    • 2021-01-27 18:42

      I like the @sugars approach :)

      So...the final version is this:

      <li v-for="(navItem, i) in sidenavItems" class="nav-item">
                                  <router-link v-if="!navItem.isCollapsible" class="nav-link" @click.native="navItemCollapse(i)" active-class="active" :to="{name: navItem.route}" exact>
                                      <i :class="navItem.class"></i>
                                      <span class="nav-link-text">{{ navItem.name }}</span>
                                  </router-link>
      
                                  <a v-if="navItem.isCollapsible" class="nav-link" href="javascript:void(0)" @click="navItemCollapse(i)" data-toggle="collapse" :aria-expanded="navItem.expanded">
                                      <i :class="navItem.class"></i>
                                      <span class="nav-link-text">{{ navItem.name }}</span>
                                  </a>
                                  <div v-if="navItem.isCollapsible" class="collapse" :class="navItem.expanded ? 'show' : ''">
                                      <ul class="nav nav-sm flex-column">
                                          <li v-for="subItem in navItem.items" class="nav-item">
                                              <router-link class="nav-link" :to="{name: subItem.route}">{{ subItem.name }}</router-link>
                                          </li>
                                      </ul>
                                  </div>
                              </li>
      

      the sidenavItems:

       sidenavItems: [
                          {name: 'Dashboard', isCollapsible: false, route: 'dashboard', class: 'class1'},
                          {name: 'Categories', isCollapsible: false, route: 'category', class: 'class2'},
                          {name: 'Brands', isCollapsible: false, route: 'brand', class: 'class3'},
                          {name: 'Products', isCollapsible: true, expanded: false, class: 'class4', items: [{name: 'List', route: 'product'}]},
                          {name: 'Orders', isCollapsible: false, route: 'order', class: 'class5'},
                          {name: 'Blog', isCollapsible: true, expanded: false, class: 'class6', items: [{name: 'List', route: ''}]},
                      ],
      

      and the navItemCollapse method:

       navItemCollapse(index) {
           this.sidenavItems = this.sidenavItems.map( (item, i) => {
                      item.expanded = !item.expanded;
                      if(i !== index) {
                          item.expanded = false;
                      }
                      return item;
                  })
              }
      
      
      0 讨论(0)
    • 2021-01-27 18:48

      This is the implementation of no jquery

      new Vue({
        el: '#app',
        data() {
          return {
            menuList: [{
                name: 'Products',
                expand: false,
                items: [{
                    name: 'Item List 1',
                    link: ''
                  },
                  {
                    name: 'Item List 2',
                    link: ''
                  }
                ]
              },
              {
                name: 'Others',
                expand: false,
                items: [{
                    name: 'Other Item 1',
                    link: ''
                  },
                  {
                    name: 'Other Item 2',
                    link: ''
                  }
                ]
              }
            ]
          }
        },
        methods: {
          navItemCollapse(index) {
            this.menuList = this.menuList.map((item, i) => {
              item.expand = !item.expand
              if (i !== index) {
                item.expand = false
              }
              return item
            })
          }
        }
      })
      <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
      
      <ul id="app">
        <li v-for="(navItem,i) in menuList" :key="i" class="nav-item">
          <a class="nav-link" href="javascript:;" data-toggle="collapse" role="button" :aria-expanded="navItem.expand" aria-controls="sidebar-products" @click.prevent="navItemCollapse(i)">
            <i class="ni ni-single-copy-04 text-primary"></i>
            <span class="nav-link-text">{{navItem.name}}</span>
          </a>
          <div v-if="navItem.items.length>0" class="collapse" :class="{show: navItem.expand}">
            <ul class="nav nav-sm flex-column">
              <li v-for="(subItem,j) in navItem.items" :key="j" class="nav-item">
                <a href="#" class="nav-link">{{subItem.name}}</a>
              </li>
            </ul>
          </div>
        </li>
      </ul>

      I integrate the menu data into an array of objects. Each object has an expand flag to determine whether it is currently expanded. When you click on the menu, switch the expand flag of the current menu.

      Note: You don't need to care about the id of the <a> tag.

      0 讨论(0)
    提交回复
    热议问题