首页 > 解决方案 > Vue.js - 带有动态 v-if 的动态按钮

问题描述

我正在动态生成一些菜单按钮(不确定这是否是最佳做法)

脚本

items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/' },
{ title: 'Register', icon: 'mdi-image', route: '/register' },
{ title: 'Login', icon: 'mdi-help-box', route: '/login' },
],

html

<v-list-item v-for="(item, i) in items" :key="i" link :to="{path: item.route}">

但我想要做的是隐藏仪表板按钮,直到他们登录。用户登录值保存在商店中。

$store.state.user.signedIn // true/false

如何根据登录值以编程方式隐藏按钮?我试图这样做

{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', reqAuth: true }

但不知道如何让它在 html 中顺利运行。我还想稍后在登录/注册按钮上执行相反的操作,如果用户已登录,那么这些应该隐藏并且注销按钮将发挥作用。

标签: javascriptvue.jsvuejs2vue-componentvuetify.js

解决方案


你有两个选择:

  • A)具有单独的菜单数组并基于isLoggedIn. 如果您在这两种情况下都显示了任何项目,则需要将它们放在第三个数组中,并将前两个数组中的一个与第三个数组连接起来
  • B)在每个菜单项上都有一个布尔属性,说明它是否应该在何时显示isLoggedIn。如果您在两者上都显示了菜单项,则每个项目都需要两个道具(showWhenLoggedIn, showWhenLoggedOut- 如果太长,请更改它们),或者,您可以创建show一个布尔数组:show: [true, false]- 第一个布尔值控制是否在登录时显示出,第二次登录时)。

解决方案A)示例(单独的数组):

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    loggedInMenuItems: [
      { title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
    ],
    loggedOutMenuItems: [
      { title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
      { title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
    ],
    permanentMenuItems: [
      { title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
    ],
    isLoggedIn: false
  }),
  computed: {
    menuItems() {
      return (this.isLoggedIn
        ? this.loggedInMenuItems
        : this.loggedOutMenuItems
      ).concat(this.permanentMenuItems)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
  <pre v-html="menuItems.map(m => m.title)"></pre>
</div>

解决方案B)示例:

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    items: [
      { title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
      { title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
      { title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
      { title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
    ],
    isLoggedIn: false
  }),
  computed: {
    menuItems() {
      return this.items.filter(item => item.show[Number(!!this.isLoggedIn)])
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
  <pre v-html="menuItems.map(m => m.title)"></pre>
</div>

为简洁起见,我个人更喜欢第二个。我也觉得它更优雅一点。

但是,在大型团队或需要将代码复杂性保持在最低限度并最大限度地提高代码可读性的项目中,通常首选第一个解决方案。

最后,第二个解决方案为菜单项的顺序提供了更大的灵活性,尽管这不是一个真正的问题(order为每个项目实现一个属性将是微不足道的)。


注意:显然,isLoggedIn应该来自状态,而不是来自组件数据 fn。我把它放进去,data这样你就可以在这里轻松地测试它。


推荐阅读