Nuxt-link uses Bootstrap-vue to refresh the page problem
P粉512729862
P粉512729862 2023-12-07 08:58:02
0
1
739

I'm using nuxt and bootstrap to build a custom hover dropdown menu for navigation. The problem I'm having is that my navigation submenu NuxtLinks are refreshing the entire page instead of smoothly changing the application content within the Nuxt block. The navigation bar is dynamically generated in the default.vue layout and uses the b-dropdown-hover component with a NuxtLink wrapping the content. Why does the page completely refresh for these links/anchors, but my b-navbar-brand image transitions smoothly? Sorry, I'm new to Nuxt. This video @ ~1:35:00 demonstrates what I'm trying to do.

components/BDropdownHoverRight.vue

<template>
  <nuxt-link :to="aTo">
    <div class="ddr-top" @mouseover="onOver1($event.target)" @mouseleave="onLeave1($event.target)">
      <b-dropdown ref="dropdown_ddr" :text="cText" class="m-md-2 ddr">
        <slot></slot>
      </b-dropdown>
    </div>
  </nuxt-link>
</template>

<script>
export default {
  name: 'BDropdownHoverRight',
  props: {
    cText: {
      type: String,
    },
    aTo: {
      type: String,
    },
  },
  methods: {
    onOver1(t) {
      if (t.nodeName === 'DIV') {
        console.log(t)
        console.log(t.nodeName)
        let num_child_nodes = 0
        try {
          if (t.querySelectorAll(':scope > ul')[0].getElementsByTagName('div').length >= 0) {
            num_child_nodes = t.querySelectorAll(':scope > ul')[0].getElementsByTagName('div').length
          }
        } catch (e) {
          if (t.querySelectorAll(':scope > div > ul')[0].getElementsByTagName('div').length >= 0) {
            num_child_nodes = t.querySelectorAll(':scope > div > ul')[0].getElementsByTagName('div').length
          }
        }

        if (num_child_nodes > 0) {
          try {
            t.querySelectorAll(':scope > div > ul')[0].style.display = 'block'
          } catch (e) {
            try {
              t.querySelectorAll(':scope > ul')[0].style.display = 'block'
            } catch (e) {}
          }
        }
      }
    },
    onLeave1(t) {
      try {
        t.querySelectorAll(':scope > div > ul')[0].style.display = 'none'
      } catch (e) {
        try {
          t.querySelectorAll(':scope > ul')[0].style.display = 'none'
        } catch (e) {}
      }
    },
  },
}
</script>

layouts/default.vue

<template>
  <div>
    <b-navbar id="top-nav-bar" toggleable="lg" type="light" sticky>
      <b-navbar-brand to="/">
        <Rabbit id="tl-logo" />
      </b-navbar-brand>

      <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>

      <b-collapse id="nav-collapse" is-nav>
        <b-navbar-nav>
          <template v-for="dir in navtop_dd">
            <b-dropdown-hover
              :key="dir.id"
              :c-text="dir.name"
              :a-to="dir.hasOwnProperty('ato') ? dir.ato : '/nolink'"
            >
              <template v-if="'submenus' in dir && dir.submenus.length > 0">
                <template v-for="dir1 in dir.submenus">
                  <b-dropdown-hover-right
                    :key="dir1.id"
                    :c-text="dir1.name"
                    :a-to="dir1.hasOwnProperty('ato') ? dir1.ato : '/nolink'"
                  >
                    <template v-if="'submenus' in dir1 && dir1.submenus.length > 0">
                      <template v-for="dir2 in dir1.submenus">
                        <b-dropdown-hover-right
                          :key="dir2.id"
                          :c-text="dir2.name"
                          :a-to="dir2.hasOwnProperty('ato') ? dir2.ato : '/nolink'"
                        >
                        </b-dropdown-hover-right>
                      </template>
                    </template>
                  </b-dropdown-hover-right>
                </template>
              </template>
            </b-dropdown-hover>
          </template>
        </b-navbar-nav>

        <!-- Right aligned nav items -->
        <b-navbar-nav class="ml-auto">
          <b-nav-form>
            <b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
            <b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
          </b-nav-form>

          <b-nav-item-dropdown right>
            <!-- Using 'button-content' slot -->
            <template #button-content>
              <b-img src="../assets/imgs/account-circle.svg" style="height: 35px"> </b-img>
              <!-- <em>User</em> -->
            </template>
            <b-dropdown-item href="#">Profile</b-dropdown-item>
            <b-dropdown-item href="#">Sign Out</b-dropdown-item>
          </b-nav-item-dropdown>
        </b-navbar-nav>
      </b-collapse>
    </b-navbar>
    <b-container id="app-content">
      <Nuxt />
    </b-container>
    <div id="footer">
      <div style="height: 100%; padding: 5px">© 2021</div>
    </div>
  </div>
</template>

<script>
import BDropdownHover from '@/components/BDropdownHover'
import BDropdownHoverRight from '@/components/BDropdownHoverRight'

export default {
  components: {
    BDropdownHover,
    BDropdownHoverRight,
  },
  data() {
    return {
      navtop_dd: [
        {
          id: 1,
          name: 'Transactions',
          ato: '/transactions',
          submenus: [
            {
              id: '1a',
              name: 'Sales Orders',
              ato: '/transactions/salesorders',
              submenus: [
                {
                  id: '1b',
                  name: 'New',
                },
                {
                  id: '2b',
                  name: 'List',
                },
              ],
            },
            {
              id: '2a',
              name: 'Item Fulfillments',
              ato: '/transactions/itemfulfillments',
              submenus: [
                {
                  id: '1b',
                  name: 'New',
                },
                {
                  id: '2b',
                  name: 'List',
                },
              ],
            },
          ],
        },
        {
          id: 2,
          name: 'Inventory',
        },
        {
          id: 3,
          name: 'Reports',
        },
        {
          id: 4,
          name: 'Setup',
        },
        {
          id: 5,
          name: 'Support',
        },
      ],
    }
  },
  mounted() {
    var x = document.querySelectorAll('.b-dropdown.navtop-dd')
    for (var i = 0; i < x.length; i++) {
      if (x[i].querySelectorAll(':scope > ul')[0].getElementsByTagName('div').length == 0) {
        var btn = x[i].querySelectorAll(':scope > .btn')[0]
        btn.classList += ' no-content-after'
      }
    }
    var x = document.querySelectorAll('.b-dropdown.ddr')
    for (var i = 0; i < x.length; i++) {
      if (x[i].querySelectorAll(':scope > ul')[0].getElementsByTagName('div').length == 0) {
        var btn = x[i].querySelectorAll(':scope > .btn')[0]
        btn.classList += ' no-content-after'
      }
    }
  },
}
</script>

<style>
#top-nav-bar {
  border-bottom: 1px solid green;
}

#tl-logo {
  height: 40px;
  margin: 5px;
}

#footer {
  height: 40px;
  color: black;
  border-top: 1px solid green;
  margin: auto;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.navtop-dd button {
  background: none !important;
  color: #6c757d !important;
  border: none !important;
}

#app-content {
  margin: 20px auto;
}

.ddr > button::after {
  display: inline-block;
  margin-left: 0.555em;
  right: 0px;
  content: "";
  border-top: 0.25em solid transparent;
  border-right: 0.3em solid transparent;
  border-bottom: 0.25em solid transparent;
  border-left: 0.35em solid;
  vertical-align: 0.075em;
}

.b-dropdown {
  width: 100%;
}

.ddr > button {
  text-align: left;
}

.no-content-after::after {
  content: none !important;
}

.ddr > ul {
  top: -1.2rem;
  left: calc(100% - 0.5rem);
}

.dropdown-menu {
  min-width: 0 !important;
}

.dropdown-item {
  color: #6C757D;
}

.ddr-top:hover {
  background-color: #e4ffda;
}

a:hover {
  text-decoration: none !important;
}
</style>

P粉512729862
P粉512729862

reply all(1)
P粉569205478

There is a lot of irrelevant code here. I took the time to format it properly. Please work on it yourself next time (only format and type the interesting bits).

Additionally, the video itself already gives the answer on how to solve the problem. This video is discussing the difference between the a and nuxt-link tags.

This is related to this part of the Bootstrap Vue documentation where you can see

So, you should use something like this


I also noticed that your code is very different from the video. You shouldn't use querySelector, you don't have to import the Nuxt component, and you'll encounter several ESlint warnings/errors.

I do recommend trying to focus on a single part of your study rather than mixing everything up. It's okay to want to go further, but be careful not to get lost in too many abstractions when you're learning a lot of new concepts (Vue/Nuxt).


By the way, if you want to continue learning Nuxt, you can check this out: https://masteringnuxt.com/ (Created by Nuxt Ambassadors and other big names in the Vue ecosystem)

Enjoy creating projects with Nuxt!

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template