Как реализовать подменю дочерних элементов текущего маршрута с помощью vue.js и vue router - PullRequest
0 голосов
/ 26 января 2019

Я пытаюсь использовать навигацию в моем приложении Vue, чтобы в главном меню располагались все маршруты корневого уровня и боковое меню, если у маршрута есть дочерние элементы. Вот так:

Goal

Текущий дизайн, который у меня есть, имеет основную навигацию со ссылками на маршрутизацию вверху с видом на маршрутизатор ниже. Мне удалось настроить боковое меню, чтобы оно отображалось только тогда, когда я выбираю Travelers и правильно обновляю компоненты / контент. Однако у меня возникают проблемы с правильной маршрутизацией, когда я нажимаю на одну из ссылок в подменю, она не добавляется к текущему пути. Поэтому, когда я нажимаю на View, когда я нахожусь в localhost / Traveler и нажимаю View , URL меняется на localhost / View / вместо localhost / Путешественник / View . Также выбор в верхнем меню становится невыбранным, когда я выбираю что-то в дочернем меню.

Unselecting

И я не могу попасть на страницы через что-то вроде localhost / Traveler / View * только 1024 * localhost / View

Я начал перечитывать документацию по вложенным маршрутам , когда начал писать этот пост, и я понял, что должен создавать новый маршрутизатор на каждом уровне, что я не делал в своем коде ниже .

Я также не уверен, как получить доступ к детям текущего маршрута. Я пытался отобразить их так:

  <h2>Route: {{ $route.name }}</h2>
  <ul id="example-1">
    <li v-for="child in $route.children">
      {{ child.name }}
    </li>
  </ul>

Но я ничего не получаю. Должны ли они быть переданы как Params или что-то? Или не так легко доступны?

Любой совет или помощь будут с благодарностью.

Root

Содержит главное меню Nav с ссылками на маршрутизатор и представлением маршрутизатора ниже.

<template>
  <div id="app" class="container-fluid">
    <div class="row">
      <div style="width:100%">
        <nav-menu params="route: route"></nav-menu>
      </div>

    </div>

    <div class="row">
      <div>
        <router-view></router-view>
      </div>
    </div>
  </div>
</template>
<script>
  import NavMenu from './nav-menu'

  export default {
    components: {
      'nav-menu': NavMenu
    },

    data() {
      return {}
    }
  }
</script>

Навигационное меню

Заполняется маршрутами

<template>
  <nav class="site-header sticky-top py-1">
    <div class="container d-flex flex-column flex-md-row justify-content-between">
      <a class="nav-item" v-for="(route, index) in routes" :key="index">
        <router-link :to="{path: route.path, params: { idk: 1 }}" exact-active-class="active">
          <icon :icon="route.icon" class="mr-2" /><span>{{ route.display }}</span>
        </router-link>
      </a>
    </div>
  </nav>
</template>
<script>
  import { routes } from '../router/routes'

  export default {
    data() {
      return {
        routes,
        collapsed: true
      }
    },
    methods: {
      toggleCollapsed: function (event) {
        this.collapsed = !this.collapsed
      }
    }
  }
</script>

Страница путешественника / просмотр

В настоящее время страница путешественника с боковым меню и другим представлением маршрутизатора для содержимого:

<template>
  <div id="app" class="container-fluid">
    <div class="wrapper">
      <traveler-menu params="route: route"></traveler-menu>

      <div id="content">
        <router-view name="travlerview"></router-view>
        </div>
      </div>
    </div>
</template>
<script>
  import TravelerMenu from './traveler-menu'
  export default {
    components: {
      'traveler-menu': TravelerMenu
    },
    data() {
      return {}
    }
  }
</script>

Боковая панель / Меню путешественника

<template>
    <nav id="sidebar">
      <div class="sidebar-header">
        <h3>Route's Children:</h3>
      </div>

      <ul class="list-unstyled components">
        <li>
          <a class="nav-item" v-for="(route, index) in travelerroutes" :key="index">
            <router-link :to="{path: route.path, params: { idk: 1 }}" exact-active-class="active">
              <icon :icon="route.icon" class="mr-2" /><span>{{ route.display }}</span>
            </router-link>
          </a>
        </li>
      </ul>

    </nav>

</template>

<script>
    import { travelerroutes } from '../../router/travelerroutes'
    export default {
    data() {
      console.log(travelerroutes);
        return {
          travelerroutes,
          collapsed: true
        }
      },
      methods: {
        toggleCollapsed: function (event) {
          this.collapsed = !this.collapsed
        }
      }
    }
</script>

Маршруты

import CounterExample from 'components/counter-example'
import FetchData from 'components/fetch-data'
import HomePage from 'components/home-page'
import TestPage from 'components/test-page'
import Travelers from 'components/Traveler/traveler-root'
import { travelerroutes } from './travelerroutes'

export const routes = [
  { name: 'home', path: '/', component: HomePage, display: 'Home', icon: 'home' },
  { name: 'counter', path: '/counter', component: CounterExample, display: 'Counter', icon: 'graduation-cap' },
  { name: 'fetch-data', path: '/fetch-data', component: FetchData, display: 'Fetch data', icon: 'list' },
  { name: 'test-page', path: '/test-page', component: TestPage, display: 'Test Page', icon: 'list' },
  {
    name: 'traveler-root', path: '/traveler', component: Travelers, display: 'Travelers', icon: 'list', children: travelerroutes
  }
]

Маршруты путешественников (travelerroutes.js)

import TestPage from 'components/test-page'
import ViewTravelers from 'components/Traveler/TravelerPages/view-travelers'

export const travelerroutes = [{
  name: 'View',
  path: '/View',
  display: 'View', icon: 'list',
  components: {
    travlerview: TestPage
  }
},
  {
    name: 'Create',
    path: '/Create',
    display: 'Create', icon: 'list',
    components: {
      travlerview: ViewTravelers
    }
  },
  {
    name: 'Edit',
    path: '/Edit',
    display: 'Edit', icon: 'list',
    components: {
      travlerview: ViewTravelers
    }
  }];

маршрутизатор / index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import { routes } from './routes'

Vue.use(VueRouter)

let router = new VueRouter({
  mode: 'history',
  routes
})

export default router

app.js

import Vue from 'vue'
import axios from 'axios'
import router from './router/index'
import store from './store'
import { sync } from 'vuex-router-sync'
import App from 'components/app-root'
import { FontAwesomeIcon } from './icons'

// Registration of global components
Vue.component('icon', FontAwesomeIcon)

Vue.prototype.$http = axios

sync(store, router)

const app = new Vue({
  store,
  router,
  ...App
})

export {
  app,
  router,
  store
}

Дайте мне знать, если вам нужно больше деталей, контекста или кода.

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Я внес несколько изменений в ответ DigitalDrifter, где я нахожу детей, использующих синтаксис шаблона. Я почти уверен, что мой ответ перестанет работать после следующего уровня детей, поэтому я скажу, что у DigitalDrifter все еще есть лучший ответ.

Также я не уверен, как сохранить маршрут подменю (localhost / Traveler), чтобы он не выполнял поиск потомков (locathost / Traveler / View), когда я нажимаю на что-то вроде представления. Прямо сейчас я делаю это каким-то ненормальным способом:

v-for="(route, index) in $router.options.routes.filter(x=>x.path==$route.path||$route.path.includes(x.path))"

Вот полный SFC без стайлинга здесь:

<template>
  <nav id="sidebar">
    <div class="sidebar-header">
      <h3>Bootstrap Sidebar</h3>
    </div>

    <ul class="list-unstyled components" v-for="(route, index) in $router.options.routes.filter(x=>x.path==$route.path||$route.path.includes(x.path))">
      <li v-for="child in route.children">
        <a class="nav-item" :key="index">
          <router-link :to="{path: route.path+'/'+child.path}" exact-active-class="active">
            <icon :icon="route.icon" class="mr-2" /><span>{{ child.path }}</span>
          </router-link>
        </a>
      </li>
    </ul>

  </nav>

</template>

<script>
  export default {
    data() {
      return {
      }
    },
    methods: {
    }
  }
</script>

Редактировать: я знаю, что у vue есть данные, которые я хочу связать с представлениями маршрутизаторов, как показано здесь,

Vue Dev Tools

Я просто не уверен, как получить доступ к этим свойствам.

Обновление 29.01.2009:

Я понял, что все, что вам нужно сделать, чтобы получить путь, это использовать $ Route.matched [0] .path , вы можете узнать больше здесь.

Теперь я смог упростить меню до SFC следующим образом:

<template>
    <nav id="sidebar">
      <div class="sidebar-header">
        <h3>Bootstrap Sidebar</h3>
      </div>

      <ul class="list-unstyled components" v-for="(route, index) in $router.options.routes.filter(x=>x.path==$route.matched[0].path)">
        <li v-for="child in route.children">
          <a class="nav-item"  :key="index">
            <router-link :to="route.path+'/'+child.path" exact-active-class="active">
              <icon :icon="route.icon" class="mr-2" /><span>{{ child.name }}</span>
            </router-link>
          </a>
        </li>
      </ul>

    </nav>

</template>

<script>
    export default {
    data() {
        return {
        }
      }
    }
</script>

CSS не входит.

Редактировать: Я сделал этот мой предпочтительный ответ, потому что он позволяет мне использовать боковое меню в любом месте, просто ссылаясь на компонент. Мне не нужно ничего передавать в него, и оно должно работать где угодно. Мне нравится ответ digitaldrifter, потому что у него есть скрипка для этого.

0 голосов
/ 26 января 2019

Вам не нужно создавать новые экземпляры маршрутизатора, вместо этого следите за свойством $route и создавайте навигационное меню боковой панели по мере его изменения. Вам нужно будет вытащить дочерние маршруты из $router.options.routes. Вот пример:

const router = new VueRouter({
  routes: [{
      name: 'home',
      path: '/',
      component: {
        template: '<div>Home</div>'
      }
    },
    {
      name: 'foo',
      path: '/foo',
      component: {
        template: '<div>Foo<router-view></router-view></div>'
      },
      children: [{
        name: 'foo.baz',
        path: '/baz',
        component: {
          template: '<div>Baz</div>'
        }
      }, {
        name: 'foo.tar',
        path: '/tar',
        component: {
          template: '<div>Tar</div>'
        }
      }]
    },
    {
      name: 'bar',
      path: '/bar',
      component: {
        template: '<div>Bar<router-view></router-view></div>'
      },
      children: [{
        name: 'bar.zim',
        path: '/zim',
        component: {
          template: '<div>Zim</div>'
        }
      }, {
        name: 'bar.zug',
        path: '/zug',
        component: {
          template: '<div>Zug</div>'
        }
      }]
    }
  ]
})

new Vue({
  el: '#app',
  router,
  data() {
    return {
      children: []
    }
  },
  watch: {
    $route: function(current) {
      const route = this.$router.options.routes.find(route => route.path === current.path)

      if (route && Array.isArray(route.children)) {
        this.children = route.children
      } else if (route) {
        this.children = []
      }
    }
  }
})
* {
  margin: 0;
  padding: 0;
}

html,
body,
#app {
  width: 100%;
  height: 100%;
}

#top {
  border: 1px solid black;
}

#top ul {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  list-style-type: none;
}

li {
  padding: 1rem;
  text-align: center;
  text-transform: uppercase;
}

li a {
  text-decoration: none;
  font-weight: bold;
  color: black;
}

#sidebar {
  height: 50%;
  width: 100px;
  border: 1px solid black;
}

#content {
  width: 50%;
}

#content,
#content>div {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://npmcdn.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <div id="top">
    <ul>
      <li v-for="item in $router.options.routes" :key="item.path" :style="{ 'background-color': $route.name.includes(item.name) ? 'rgba(197,225,165,1)' : 'white' }">
        <router-link :to="item.path">{{ item.name }}</router-link>
      </li>
    </ul>
  </div>
  <div style="display: flex; flex-direction: row; height: 100%; width: 100%;">
    <div id="sidebar">
      <ul>
        <li v-for="item in children" :key="item.path" :style="{ 'background-color': $route.name === item.name ? 'rgba(197,225,165,1)' : 'white' }">
          <router-link :to="item.path">{{ item.name.split('.').pop() }}</router-link>
        </li>
      </ul>
    </div>
    <div id="content">
      <router-view></router-view>
    </div>
  </div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...