使用 Vuetify 的导航栏中的动态按钮

Posted

技术标签:

【中文标题】使用 Vuetify 的导航栏中的动态按钮【英文标题】:Dynamic Buttons in Navigation Bar using Vuetify 【发布时间】:2018-09-29 10:04:30 【问题描述】:

我有问题... 我的 VueJS 应用程序使用 Vuetify。 我有一个<v-toolbar>,在右侧,我想放置一些按钮,这些按钮会根据<router-view> 中显示的组件而改变,但我无法从 $route 或 $route 访问组件属性以获取对象和方法绑定到我的组件的模型。

我想知道是否有任何方法可以从我的主要组件中分配模型。

我尝试过使用“命名路由”,但我不知道在由<router-view> 管理并实时更新的组件之间共享属性的方式是什么。

在简历中:

我的应用程序框架带有一个导航栏,另外在动态内容中我有一个<router-view>。根据<router-view> 中显示的组件,我希望在导航栏中看到与该组件相对应的按钮,这些按钮可以交互并更改组件的数据或执行方法。

App.vue

<template>
  <v-app>
		<router-view></router-view>
  </v-app>
</template>

<script>
	export default 
		name: 'App',
		data() 
			return 
				
			;
		
	;
</script>

index.js(路由器)

import Vue from 'vue'
import Router from 'vue-router'
import AppLogin from '@/components/AppLogin'
import Skeleton from '@/components/Skeleton'
import ShoppingCart from '@/components/ShoppingCart'
import ShoppingCartButtons from '@/components/ShoppingCartButtons'
import ProductSelection from '@/components/ProductSelection'
import ProductSelectionButtons from '@/components/ProductSelectionButtons'
import ProductDetail from '@/components/ProductDetail'

Vue.use(Router)

export default new Router(
  routes: [
    
      path : '/login',
      name : 'AppLogin',
      component : AppLogin
    ,
    
      path : '/app',
      name : 'Skeleton',
      component : Skeleton,
      children : [
          path : 'shopping-cart',
          components : 
            navigation : ShoppingCart,
            navButtons : ShoppingCartButtons
          
        , 
          path: 'product-selection',
          name : 'ProductSelection',
          components : 
            navigation : ProductSelection,
            navButtons : ProductSelectionButtons
          
        ,
        
          path: 'product-detail',
          name : 'ProductDetail',
          components : 
            navigation : ProductDetail
          ,
          props : true
        
      ]
    
  ]
)

骨架.vue

<template>
    <v-container fluid>
        <v-navigation-drawer
            persistent
            :mini-variant="miniVariant"
            :clipped="true"
            v-model="drawer"
            enable-resize-watcher
            fixed
            app
            >
            
            <v-list>

            <v-list-tile
                value="true"
                v-for="(item, i) in items"
                :key="i"
                :to="item.path">

                <v-list-tile-action>
                <v-icon v-html="item.icon"></v-icon>
                </v-list-tile-action>
                
                <v-list-tile-content>
                <v-list-tile-title v-text="item.title"></v-list-tile-title>
                </v-list-tile-content>
            </v-list-tile>
            </v-list>
        </v-navigation-drawer>

        <v-toolbar
            app
            :clipped-left="clipped"
        >
            <v-toolbar-side-icon @click.stop="drawer = !drawer">
            </v-toolbar-side-icon>
            
            <v-toolbar-title v-text="$route.meta.title"></v-toolbar-title>
            <v-spacer></v-spacer>
            <router-view name="navButtons"></router-view>

        </v-toolbar>
    
        <v-content>
            <router-view name="navigation"/>
        </v-content>

        <v-footer :fixed="true" app>
			<p style="text-align : center; width: 100%">&copy; CONASTEC 2018</p>
		</v-footer>
    </v-container>
</template>

<script>
export default 
  data() 
	return 
	  clipped: true,
	  drawer: false,
	  fixed: false,
	  items: [
		
		  icon: "shopping_cart",
		  title: "Carrito de Compras",
		  path : "/app/shopping-cart"
		,
		
		  icon: "attach_money",
		  title: "Facturas"
		,
		
		  icon: "account_balance_wallet",
		  title: "Presupuestos"
		,
		
		  icon: "insert_chart",
		  title: "Informes"
		,
		
		  icon: "local_offer",
		  title: "Productos"
		,
		
		  icon: "person",
		  title: "Clientes"
		,
		
		  icon: "layers",
		  title: "Cuenta"
		,
		
		  icon: "comment",
		  title: "Comentarios"
		,
		
		  icon: "settings",
		  title: "Ajustes"
		
	  ],
	  buttons : [],
	  miniVariant: false,
	  right: true,
	  rightDrawer: false
	;
  ,
  name: "Skeleton"
;
</script>

已编辑

我的解决方案是创建一个新组件工具栏,并为左右按钮添加插槽。

<template>
    <div>
        <v-navigation-drawer persistent :mini-variant="false" :clipped="true" v-model="drawer" enable-resize-watcher fixed app>
            <v-list>
                <v-list-tile value="true" v-for="(item, i) in items" :key="i" :replace="true" :to="item.path">
    
                    <v-list-tile-action>
                        <v-icon v-html="item.icon"></v-icon>
                    </v-list-tile-action>
    
                    <v-list-tile-content>
                        <v-list-tile-title v-text="item.title"></v-list-tile-title>
                    </v-list-tile-content>
                </v-list-tile>
            </v-list>
        </v-navigation-drawer>
    
        <v-toolbar app :clipped-left="true" color="primary" :dark="true" flat>
    
            <v-toolbar-side-icon v-if="showDrawer" @click.stop="drawer = !drawer">
            </v-toolbar-side-icon>

            <v-toolbar-side-icon v-if="!!back" @click="back">
                <v-icon>keyboard_backspace</v-icon>
            </v-toolbar-side-icon>
            
            <v-toolbar-title v-text="title" style="font-size: 1.4em"></v-toolbar-title>
            <v-spacer></v-spacer>
            <v-card-actions>
                <slot name="right"></slot>
            </v-card-actions>
    
        </v-toolbar>
        <v-snackbar
            :timeout="5000"
            :top="true"
            :multi-line="true"
            :vertical="true"
            v-model="snackbar.show"
            >
             snackbar.content 
            <v-btn flat color="white" @click.native="snackbar.show = false">Cerrar</v-btn>
        </v-snackbar>
    </div>
</template>

<script>
    export default 
        name: 'app-toolbar',
        props: ['title','showDrawer', 'back'],
        data() 
            return 
                drawer : false,
                items: [
                    icon: "shopping_cart",
                    title: "Carrito de Compras",
                    path: "/carrito-compras"
                , 
                    icon: "attach_money",
                    title: "Facturas",
                    path: "/documentos-tributarios"
                , 
                    icon: "account_balance_wallet",
                    title: "Presupuestos"
                , 
                    icon: "insert_chart",
                    title: "Informes"
                , 
                    icon: "local_offer",
                    title: "Productos"
                , 
                    icon: "person",
                    title: "Clientes"
                , 
                    icon: "layers",
                    title: "Cuenta"
                , 
                    icon: "comment",
                    title: "Comentarios"
                , 
                    icon: "settings",
                    title: "Ajustes"
                ]
            ;
        ,
        computed : 
            snackbar() 
                return this.$store.getters.snackbar;
            
        
    
</script>

使用是:

 <app-toolbar title="Carrito de Compras" :showDrawer="true">
    <template slot="right">
        <v-toolbar-side-icon @click="confirm">
            <v-icon>monetization_on</v-icon>
        </v-toolbar-side-icon>

    </template>
</app-toolbar>

【问题讨论】:

尝试在您的路线上使用meta。这样您就可以识别路由器所服务的每个组件。 另外,请向我们展示您的代码。谢谢。 @CENT1PEDE 我正在编辑,这是我的代码 【参考方案1】:

我在最近的一个项目中和你做了同样的事情,发现改变结构是解决此类问题的更简单方法。

我的结构如下:

app.vue: 只包含&lt;router-view&gt; 没有其他组件

router.js:父路由是一个布局组件,所有子路由都包含我的工具栏和其他布局组件,它自己的&lt;router-view&gt;接收子路由

例如:


  path: '/login',
  name: 'Login',
  component: load('login')
,

  path: '/',
  component: load('main-layout'),
  children: [
    
      path: '',
      name: 'Home Page',
      component: load('homePage')
    ,
    
      path: '/settings',
      name: 'Settings',
      component: load('settings'),
    
  ]

现在在你的主布局中:

computed: 
  showHomeButton () 
    if (this.$route.path === '/') 
      return true
    
    return false
    // Repeat for other routes, etc...
  ,

【讨论】:

@Brayan 你必须更具体,我不确定你在问什么。通常,您使用 props 将数据向下发送到其他组件,然后使用 emit 向上发送。【参考方案2】:

如果你使用的是Vuex,你可以使用vuex-router-sync,那么你可以 使用this.$state.route.path从任何组件访问路由。

如果不是,Scott 的回答可能是最好的方法。

【讨论】:

【参考方案3】:

我遇到了同样的问题,我的解决方案是从 vue 路由器的 de meta 管理左键操作,如下所示:

    
      path: '/feedstocks/:categoryId/:id',
      name: 'Feedstock',
      component: () =>
        import(
          /* webpackChunkName: "client-chunk-feedstock-details" */ '@/views/FeedstockDetails.vue'
        ),
      props: true,
      meta: 
        authNotRequired: true,
        backRoute: 'Material'
      
    

然后我可以在应用栏按钮操作中检查元数据:

<v-app-bar app color="primary" dark>
  <v-btn text icon color="white" @click="leftButtonAction">
    <v-icon> leftButtonIcon </v-icon>
  </v-btn>
  <v-toolbar-title>
     currentAppTitle 
  </v-toolbar-title>
  <v-spacer></v-spacer>
</v-app-bar>

leftButtonIcon() 
  if (this.$route.meta.backRoute) 
    return 'mdi-chevron-left'
  
  return 'mdi-menu'


leftButtonAction() 
  if (this.$route.meta.backRoute) 
    this.$router.push( name: this.$route.meta.backRoute )
   else 
    this.toggleDrawer()
  

【讨论】:

以上是关于使用 Vuetify 的导航栏中的动态按钮的主要内容,如果未能解决你的问题,请参考以下文章

如何在导航栏中添加多个栏按钮

导航栏中的下拉按钮会扭曲导航栏

带有 ionic-2-sidemenu 应用程序的顶部导航栏中的导航按钮

导航栏中的 Swift 自定义后退按钮

Bootstrap 3.0 导航栏中的多个折叠按钮

标签栏 UIViewController 中导航栏中的按钮未显示