【问题标题】:Array manipulation with multiple conditions – Vue.js / JavaScript具有多个条件的数组操作 – Vue.js / JavaScript
【发布时间】:2020-12-24 13:35:20
【问题描述】:

在我的 Vue.js 应用程序中,我使用导航抽屉来显示用户可以访问的不同页面。页面也只有在管理员激活了相关模块时才可见。因此,为每个页面和子页面设置了唯一的moduleID。该列表由filteredPages[] 填充。该数组是仅显示用户有权访问的页面的结果。所有可用页面都存储在我的原始数据源pages[]

总结一下:只有当两个这两个条件都为true时才会显示一个页面:

  1. activatedModules[] 包含页面子页面的moduleID
  2. userPermissions[] 包含子代的 permissions 值(如果没有子代,则为页面)。

我的代码:

export default {
    data: () => ({
        pages: [
            {
                text: 'Team', moduleID: 'm1',
                children: [
                { text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' },
                ],
            },
            {
                text: 'Planner', moduleID: 'm2',
                children: [
                { text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
                { text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
                ],
            },
            {
                text: 'HR', moduleID: 'm3',
                children: [
                { text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
                { text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
                ],
            },
            {
                text: 'Admin', moduleID: 'm4',
                children: [
                { text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
                { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
                ],
            },
            { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' },
        ],
        activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2' 'm4', 'm4-1', 'm4-2', 'm5'],
        userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50'],
        // This is the source for my navigation drawer:
        filteredPages: []
    }),
    computed: {
        filterArray() {
            // I tried to use filter() but how can I solve the rest?
            this.filteredPages = this.pages.filter(function(item) {
              for (var this.activatedModules in filter) {
                if /* I would assume that I have to write the condition here */
                return false;
              }
              return true;
            })
        }
    }
}

对于上面的代码,这应该是输出:

filteredPages: [
                {
                    text: 'Team', moduleID: 'm1',
                    children: [
                        { text: 'Dashboard', route:'team/dashboard', permissions: 'p', moduleID: 'm1-1' },
                    ],
                },
                // Notice that 'm2' is missing here because it is not in activatedModules[]
                {
                    text: 'HR', moduleID: 'm3',
                    children: [
                        { text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
                        { text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
                    ],
                },
                {
                    text: 'Admin', moduleID: 'm4',
                    children: [
                        // 'm4-1' is in activatedModules[] but the user doesn't have the permission 'p401' to view this
                        { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
                    ],
                },
                { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' },
            ]

用户的权限存储在 Firebase Cloud Firestore 中,如下所示:

你能帮忙过滤一下数组吗?

【问题讨论】:

  • 你能补充一下filterArray() 在这个具体案例中应该返回的内容吗?
  • @trincot 我在这种情况下用输出更新了问题。
  • @tao 我的 Vue.js 应用程序非常复杂,现在几乎完成了。因此,我可能拥有某种知识,至少可以将项目推进到这个阶段。这些页面是在没有权限的情况下编码的。我之前用filter() 操作过数组,但是没有这种复杂性,也没有在网上找到能以正确方式帮助我解决这个问题的资源。
  • 你的例子有问题。 p301 在权限中,但您在输出中评论它不是。而对于p401,情况正好相反。哪里有错别字?
  • 其实我才意识到这个错误,而且比我想象的要傻得多:你错误地写了created而不是computed。我将删除我以前的 cmets。

标签: javascript arrays vue.js


【解决方案1】:

应该这样做:

computed: {
  filteredPages() {
    return this.pages.map(page => ({
      ...page, 
      children: page.children
        // when children is truthy
        ? page.children.filter(
          // filter out those not in `userPermissions`
          child => this.userPermissions.includes(child.permissions)
          // and those not in `activatedModules`
            && this.activatedModules.includes(child.moduleID)
        )
        : page.children
    })).filter(
      // only keep page if in `activatedModules` and...
      page => (this.activatedModules.includes(page.moduleID)) &&
        // if children is truthy and has length or...
        (page.children?.length || (
          // if children is falsy and page.permissions in userPermissions
          !page.children && this.userPermissions.includes(page.permissions)
        ))
    );
  }
}

看看它的工作原理:

Vue.config.devtools = false;
Vue.config.productionTip = false;

new Vue({
  el: '#app',
  data: () => ({
    pages: [
      {
        text: 'Team',
        moduleID: 'm1',
        children: [
          { text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' }
        ],
      }, {
        text: 'Planner',
        moduleID: 'm2',
        children: [
          { text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
          { text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
        ],
      }, {
        text: 'HR',
        moduleID: 'm3',
        children: [
          { text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
          { text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
        ],
      }, {
        text: 'Admin',
        moduleID: 'm4',
        children: [
          { text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
          { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
        ],
      },
      { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' }
    ],
    activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
    userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50']
  }),
  computed: {
    filteredPages() {
      return this.pages.map(page => ({
        ...page, 
        children: page.children
          ? page.children.filter(
            child => this.userPermissions.includes(child.permissions)
              && this.activatedModules.includes(child.moduleID)
          )
          : page.children
      })).filter(
        page => (this.activatedModules.includes(page.moduleID))
          && (page.children?.length || (
            !page.children && this.userPermissions.includes(page.permissions)
          ))
      );
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <pre v-html="filteredPages" />
</div>

【讨论】:

  • 谢谢,我真的很喜欢这种方法。但是,当permissions 完全为空时,似乎也存在问题。用户仍然可以看到顶级页面(没有子页面),因为代码只输出顶级页面。
  • 就是这样。谢谢:)
【解决方案2】:

在下面的代码 sn-p 中,我首先使用过滤器通过activatedModules 过滤,然后使用forEach 通过userPermissions 过滤每个对象children 属性,我认为您可以在您的 vue 组件中实现这一点或了解如何解决问题(希望对您有所帮助):

const pages = [{
    text: 'Team',
    moduleID: 'm1',
    children: [{
      text: 'Dashboard',
      route: 'team/dashboard',
      permissions: 'p1382',
      moduleID: 'm1-1'
    }, ],
  },
  {
    text: 'Planner',
    moduleID: 'm2',
    children: [{
        text: 'Events',
        route: '/planner/events',
        permissions: 'p47289',
        moduleID: 'm2-1'
      },
      {
        text: 'Calendar',
        route: '/planner/calendar',
        permissions: 'p283',
        moduleID: 'm2-2'
      },
    ],
  },
  {
    text: 'HR',
    moduleID: 'm3',
    children: [{
        text: 'Staff',
        route: '/hr/staff',
        permissions: 'p34729',
        moduleID: 'm3-1'
      },
      {
        text: 'Config',
        route: '/hr/config',
        permissions: 'p382',
        moduleID: 'm3-2'
      },
    ],
  },
  {
    text: 'Admin',
    moduleID: 'm4',
    children: [{
        text: 'Users',
        route: '/admin/users',
        permissions: 'p3z4',
        moduleID: 'm4-1'
      },
      {
        text: 'Security',
        route: '/admin/security',
        permissions: 'p2u3',
        moduleID: 'm4-2'
      },
    ],
  },
  {
    text: 'Support',
    route: '/support',
    permissions: 'p332j',
    moduleID: 'm5'
  },
];
const activatedModules = ['m1', 'm3', 'm4', 'm5'];
const userPermissions = ['m1-1', 'm3-1', 'm3-2', 'm4-2'];
// This is the source for my navigation drawer:
let filteredPages = null;

filteredPages = pages.filter(x => activatedModules.includes(x.moduleID));
filteredPages.forEach(x => {
 if (x.children)
  x.children = x.children.filter(y => userPermissions.includes(y.moduleID));
});

console.log(filteredPages);

【讨论】:

  • 与tao的回答相同的问题:,permissions完全为空时似乎存在问题。用户仍然可以看到顶级页面(没有子页面),因为代码只输出顶级页面。
【解决方案3】:

一些备注:

  • 您不应该将function 用于回调,就像您开始为filter 做的那样,因为这会使您失去正确的this 值。使用箭头函数。
  • filter 不能自己完成这项工作,因为您还需要生成可能有更少子级的新对象。所以你应该先map 来做那些缩小的对象,然后filter

不使用 Vue,您可以运行以下 sn-p,它只是将调用硬编码为 filterArray

let app = {
    computed: {
        filterArray() {
            this.filteredPages = this.pages.map(item => {
                let children = (item.children || []).filter(child => 
                    this.activatedModules.includes(child.moduleID) &&
                    this.userPermissions.includes(child.permissions)
                );
                return (children.length || !item.children) 
                    && this.activatedModules.includes(item.moduleID)
                    && {...item, children};
            }).filter(Boolean);
        }
    },
    data: () => ({
        pages: [
            {
                text: 'Team', moduleID: 'm1',
                children: [
                { text: 'Dashboard', route:'team/dashboard', permissions: 'p101', moduleID: 'm1-1' },
                ],
            },
            {
                text: 'Planner', moduleID: 'm2',
                children: [
                { text: 'Events', route:'/planner/events', permissions: 'p201', moduleID: 'm2-1' },
                { text: 'Calendar', route:'/planner/calendar', permissions: 'p202', moduleID: 'm2-2' },
                ],
            },
            {
                text: 'HR', moduleID: 'm3',
                children: [
                { text: 'Staff', route:'/hr/staff', permissions: 'p301', moduleID: 'm3-1' },
                { text: 'Config', route:'/hr/config', permissions: 'p302', moduleID: 'm3-2' },
                ],
            },
            {
                text: 'Admin', moduleID: 'm4',
                children: [
                { text: 'Users', route:'/admin/users', permissions: 'p401', moduleID: 'm4-1' },
                { text: 'Security', route:'/admin/security', permissions: 'p402', moduleID: 'm4-2' },
                ],
            },
            { text: 'Support', route:'/support', permissions: 'p50', moduleID: 'm5' },
        ],
        activatedModules: ['m1', 'm1-1', 'm3', 'm3-1', 'm3-2', 'm4', 'm4-1', 'm4-2', 'm5'],
        userPermissions: ['p101', 'p301', 'p302', 'p402', 'p50'],
        filteredPages: []
    }),
};

// Demo, simulate Vue's call to computed.filterArray
let data = app.data();
app.computed.filterArray.call(data);
// Verify output:
console.log(data.filteredPages);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-02
    • 2020-08-24
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    相关资源
    最近更新 更多