zoukankan      html  css  js  c++  java
  • 二级菜单优化功能

    二级菜单的功能优化---渐入佳境

    功能1:点击其中之一的一级菜单展示其二级菜单,同时其他一级菜单的二级菜单都处于闭合状态

    思路:使用jsDOM操作进行实现

    HTML示例代码
    <div class="multi-menu">
        {% for menu in menu_list %}
            <div class="item">
                <div class="title"><i class="fa {{ menu.icon }}"></i>
                    {{ menu.name }}</div>
                <div class="body">
                    {% for child in menu.children %}
                        <a href="{{ child.url }}">{{ child.title }}</a>
                    {% endfor %}
                    
                </div>
            </div>
        {% endfor %}
    </div>

    js代码实现

    $('.item .title').click(function () {
        $(this).next().removeClass('hide').parent().siblings().find('.body').addClass('hide')
    })
    
    //1.先命中一级菜单title,触发点击事件
    //2.保证自己没有被隐藏
    //3.找到其他body使其隐藏,通过自己先找到父级parent,再找到所有的兄弟siblings的儿子,也就是body,命中后添加hide属性
    
    //如此便实现了这个只显示当前菜单下的二级菜单功能

    功能2:访问当前页面,默认选中对应页面展示菜单

    思路:在访问的二级菜单url对应a标签中添加 class='active'

    1.django中 templatetags文件下使用inclusion_tag进行自定义模板

    #从二级菜单的数据结构中获取到需要使用的url,title进行模板渲染
    """
    {
        1: {
            'name': '信息管理',
            'icon': 'fa-email',
            'children': [{
                'title': '客户管理',
                'url': '/customer/list/'
            }]
        },
    }
    """
    from django import template
    import re
    from permission import settings
    register = template.Library()
    #自定义模板
    @register.inclusion_tag('menu.html')
    def menu(request):
        menu_dic = request.session.get(settings.MENU_SESSION_KEY)
        url = request.path_info #获取访问的url
    
        #获取到url和title进行模板渲染
        for item in menu_dic.values(): #首先循环拿到item表示一级菜单id对应的所有内容
    
            for i in item['children']: #循环item['children'] 要拿到i 表示二级菜单内的所有内容
                if re.match("^{}$".format(i['url']),url): #将获取到url与session中的url进行正则匹配
                    i['class'] = 'active' #匹配成功后给二级菜单字典内添加一组键值对 class='active'
                    break
        return {'menu_list':menu_dic.values()}

    2.在对应的模板中直接渲染即可,参照功能1中的HTML代码

      <a class="{{ child.class }}" href="{{ child.url }}">{{ child.title }}</a>
    
    根据上面的HTML代码来看,在class=body 下的a标签中添加class='active'进行渲染即可.
    ***如此便实现了
    访问某个页面,默认选中对应页面的展示菜单***
    
    

    功能3:访问某个页面,页面对应菜单的二级菜单展示,其他菜单的二级菜单默认关闭

    思路:首先先隐藏所有的二级菜单,再根据访问的url展示对应的一级菜单下的二级菜单

    #示例代码
    from
    django import template import re from luffy_permission import settings register = template.Library() #自定义模板 @register.inclusion_tag('menu.html') def menu(request): menu_dic = request.session.get(settings.MENU_SESSION_KEY) url = request.path_info for item in menu_dic.values(): item['class'] = 'hide' #将所有的二级菜单隐藏 for i in item['children']: if re.match("^{}$".format(i['url']),url): i['class'] = 'active' item['class'] = '' #将匹配成功的二级菜单取消隐藏 break return {'menu_list':menu_dic.values()}
    <div class="multi-menu">
        {% for menu in menu_list %}
            <div class="item">
                <div class="title"><i class="fa {{ menu.icon }}"></i>
                    {{ menu.name }}</div>
                <div class="body {{ menu.class }}">    
                    {% for child in menu.children %}
                        <a class="{{ child.class }}" href="{{ child.url }}">{{ child.title }}</a>
                    {% endfor %}
                    
                </div>
            </div>
        {% endfor %}
    </div>

    注:先在body中添加class='hide'属性,令所有的二级菜单隐藏,当访问的url页面匹配与session中的url匹配成功后在将 class='' 从而取消隐藏

    功能4:固定菜单栏展示顺序,因为数据结构是字典(无序的)

    思路:将menu表结构改变,添加一个字段weight = model.IntegerField(default=1),导入有序字典(from collections import OrderedDict),根据数值大小进行排序即可

    models.py
    class
    Menu(models.Model): """ 一级菜单 """ name = models.CharField(max_length=30,verbose_name='一级菜单名称') icon = models.CharField(max_length=56, verbose_name='图标', blank=True, null=True) weight = models.IntegerField(default=1) def __str__(self): return self.name #添加一个字段weight
    rbac.py
    from django import template import re from permission import settings from collections import OrderedDict register = template.Library() #自定义模板 @register.inclusion_tag('menu.html') def menu(request): menu_dic = request.session.get(settings.MENU_SESSION_KEY)
       url = request.path_info order_dic
    = OrderedDict() #实例化一个有序字典 for key in sorted(menu_dic,key=lambda n:menu_dic[n]['weight'],reverse=True): order_dic[key] = item = menu_dic[key] #将根据weight字段排序后的menu_dic 赋值给order_dic item['class'] = 'hide' for i in item['children']: if re.match("^{}$".format(i['url']),url): i['class'] = 'active' item['class'] = '' break return {'menu_list':order_dic.values()} #再返回有序字典在模板上顺序渲染

    功能5:非菜单权限归属问题 (二级菜单内各种时操作 默认选中并处于显示对应二级菜单)

    思路:二级菜单下需要有操作的层级关系,也就是你伪三级菜单 ,更改表结构也就是 权限表(Permission)

     步骤1:表结构设计 models.py

    #参照上图所示
    class
    Permission(models.Model): """ 权限表 menu_id 有的话 表示当前的权限是二级菜单 父权限 没有 是一个普通权限 parent_id 有的话 表示当前就是子权限 没有的话就是一个父权限 """ url = models.CharField(max_length=255,verbose_name='地址') title = models.CharField(max_length=25,verbose_name='标题') menu = models.ForeignKey('Menu',blank=True,null=True) parent = models.ForeignKey('self') #自关联 获取到层级结构

     步骤2:查询和存放在session中的权限信息处理 service/permission.py

     1 from django.conf import settings
     2 
     3 
     4 def init_permission(request,obj):
     5     # 先查到需要的权限信息,
     6 
     7     permission_query = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
     8                                                                                      'permissions__title',
     9                                                                                      'permissions__menu__name',
    10                                                                                      'permissions__menu__icon',
    11                                                                                      'permissions__menu__id',
    12                                                                                      'permissions__menu__weight',
    13                                                                                      'permissions__id',
    14                                                                                      'permissions__parent_id',
    15                                                                                      ).distinct()
    16     # 存放权限信息列表
    17     permission_list = []
    18     # 存放菜单信息的字典
    19     menu_dic = {}
    20     for item in permission_query:
    21         # 将权限信息放到permission_list
    22         permission_list.append({'url': item['permissions__url'],
    23                                 'pid': item['permissions__parent_id'],
    24                                 'id': item['permissions__id'] })
    25 
    26         #放入菜单信息
    27         menu_id = item['permissions__menu__id']
    28         if not menu_id:
    29             continue
    30         if menu_id not in menu_dic:
    31             menu_dic[menu_id] = {
    32                 'name': item['permissions__menu__name'],
    33                 'icon': item['permissions__menu__icon'],
    34                 'weight': item['permissions__menu__weight'],
    35                 'children': [{
    36                     'title': item['permissions__title'],
    37                     'url': item['permissions__url'],
    38                     'id': item['permissions__id'],
    39                 }]
    40             }
    41         else:
    42             menu_dic[menu_id]['children'].append({
    43                 'title': item['permissions__title'],
    44                 'url': item['permissions__url'],
    45                 'id': item['permissions__id'],
    46             })
    47 
    48     request.session[settings.PERMISSION_SESSION_KEY] = permission_list
    49     request.session[settings.MENU_SESSION_KEY] = menu_dic
    权限信息查询和session中保存

    步骤3.中间件权限校验,处理访问url归属问题 middlewares/rbac.py

     1 from django.utils.deprecation import MiddlewareMixin
     2 import re
     3 from django.conf import settings
     4 from django.shortcuts import HttpResponse,redirect,reverse
     5 
     6 class RbacMiddleware(MiddlewareMixin):
     7 
     8     def process_request(self,request):
     9         #获取当前的url
    10         url = request.path_info
    11 
    12         #白名单
    13         for i in settings.WHITE_LIST:
    14             if re.match(i,url):
    15                 return
    16 
    17         #获取权限信息
    18         permission_list = request.session.get(settings.PERMISSION_SESSION_KEY)
    19         if not permission_list:
    20             return redirect(reverse('login'))
    21         #权限校验
    22 
    23         for item in permission_list:
    24             # i 里面有{url pid  id}
    25             if re.match("^{}$".format(item['url']),url):
    26                 #要显示的二级菜单的id
    27                 pid = item.get('pid')
    28                 id = item.get('id')
    29                 #此步操作就是表示不管是pid还是id都是显示的二级菜单的id
    30                 if pid:
    31                     #当前访问的是子权限,找父权限显示
    32                     request.current_menu_id = pid
    33                 else:
    34                     #当前访问的是父权限,也就是二级菜单,找自己显示
    35                     request.current_menu_id = id
    36                 return
    37         return HttpResponse('您没有访问的权限')
    中间件处理访问的权限url归属问题

    步骤4.自定义模板中二级菜单id和session中存的匹配成功

    from django import template
    import re
    from luffy_permission import settings
    from collections import OrderedDict
    
    register = template.Library()
    #自定义模板
    @register.inclusion_tag('menu.html')
    def menu(request):
        menu_dic = request.session.get(settings.MENU_SESSION_KEY)
        url = request.path_info  
        order_dic = OrderedDict()  
        for i in sorted(menu_dic,key=lambda n:menu_dic[n]['weight'],reverse=True):
            order_dic[i] = item = menu_dic[i] 
        # for item in order_dic.values(): 
            item['class'] = 'hide'  
            for i in item['children']: 
                if i['id'] == request.current_menu_id:#session中的id和访问的二级菜单id匹配
                    i['class'] = 'active' 
                    item['class'] = '' 
                    break
        return {'menu_list':order_dic.values()}
    自定义模板

     功能6:路径导航(breadcrumb)

    思路:先写个字典,字典中添加要显示的url和title,然后进行循环,具体逻辑代码展现

    步骤1:将存放在session的权限信息从列表修改为字典,同时在权限信息中再添加title字段,确保能够展示,

    permission_dic[item['permissions__id']] = ({'url': item['permissions__url'],
                                                        'pid': item['permissions__parent_id'],
                                                        'id': item['permissions__id'] ,
                                                        'title': item['permissions__title'],
                                                        })
    
    #确保url和title字段存在,能够访问跳转和显示

    步骤2:中间件中 middlewares/rbac.py

      2-1添加一个列表套字典的数据结构并添加到request中

    request.breadcrumb_list = [
                {'title':'首页','url':'/index/'}
            ]
     2-2 向breadcrumb_list中添加匹配到的pid/id对应的url和title主要是在访问的时候对应的将对二级菜单和三级菜单的url和标题展示
         for item in permission_dic.values():
                if re.match("^{}$".format(item['url']),url):
                    pid = item.get('pid')
                    id = item.get('id')
                    #此步操作就是表示不管是pid还是id都是显示的二级菜单的id
                    if pid:
                        #当前访问的是子权限,找父权限显示
                        request.current_menu_id = pid
                        #向路径导航列表中添加三级菜单的url和title
                        request.breadcrumb_list.append(
                            {'title': permission_dic[str(pid)]['title'],
                             'url': permission_dic[str(pid)]['url']
                             }
                        )
                        # 向路径导航列表中添加二级菜单的url和title
                        request.breadcrumb_list.append({'title': item['title'], 'url': item['url']})
    
                    else:
                        #当前访问的是父权限,也就是二级菜单,找自己显示
                        request.current_menu_id = id
                        request.breadcrumb_list.append({'title':item['title'],'url':item['url']})

    步骤3 templatetags/inclusion_tag进行自定义模板rabc.py

    @register.inclusion_tag('breadcrumb.html')
    def breadcrumb(request):
        return {'breadcrumb_list':request.breadcrumb_list}
    
    
    #将获取到的request.breadcrumb_list 交给'breadcrumb.html'渲染

    步骤4:HTML模板渲染

    <div>
        <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">
            {% for breadcrumb in breadcrumb_list %}
                {% if forloop.last %}
                    <li>{{ breadcrumb.title }}</li>
                {% else %}
                    <li><a href="{{ breadcrumb.url }}">{{ breadcrumb.title }}</a></li>
                {% endif %}
    
            {% endfor %}
        </ol>
    </div>

    #继承母版,单独写一个breadcrumb.html文件 #小小技术点:循环展示的时候,如果是最后一个无法访问,通过bootstrap 路径导航给li标签添加class='active'实现

    功能7:权限控制到按钮级别

    思路:根据用户是否有权限通过url反向解析的名称进行判断,有就通过过滤器显示,否则隐藏

    步骤1:修改表结构,针对权限表(Permission)添加一个urlname字段,并将urls.py中url反向解析名称进行保存 例如:  name='customer_list'

    #更新的表结构models.py
    添加以下字段
    urlname = models.CharField(max_length=32,verbose_name='url别名')

    步骤2:获取到需要的权限信息 service/permission.py权限初始化

    permission_query = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                         'permissions__title',
                                                                                         'permissions__urlname',#取到权限表的url别名
                                                                                         'permissions__menu__name',
                                                                                         'permissions__menu__icon',
                                                                                         'permissions__menu__id',
                                                                                         'permissions__menu__weight',
                                                                                         'permissions__id',
                                                                                         'permissions__parent_id',
                                                                                         'permissions__parent__urlname', #取到父权限和自己的别名两个
                                                                                         ).distinct()
        # 存放权限信息列表
        permission_dic = {}
        # 存放菜单信息的字典
        menu_dic = {}
        for item in permission_query:
            # 将权限信息放到permission_list
            permission_dic[item['permissions__urlname']] = ({'url': item['permissions__url'],
                                                        'pid': item['permissions__parent_id'],
                                                        'pname': item['permissions__parent__urlname'],
                                                        'id': item['permissions__id'] ,
                                                        'urlname': item['permissions__urlname'] ,
                                                        'title': item['permissions__title'],
                                                        })

    步骤3.中间件中进行权限校验,使用权限表中的id和自关联的parent_id字段,匹配出对应的url和title

            for item in permission_dic.values():
                if re.match("^{}$".format(item['url']),url):
                    pid = item.get('pid')
                    pname = item.get('pname')
                    id = item.get('id')
                    if pid:
                        request.current_menu_id = pid
                        #向路径导航列表中添加二级菜单也就是父权限的url和title
                        request.breadcrumb_list.append(
                            {'title': permission_dic[pname]['title'],
                             'url': permission_dic[pname]['url']
                             }
                        )
                        # 向路径导航列表中添加三级菜单的url和title
                        request.breadcrumb_list.append({'title': item['title'], 'url': item['url']})
    
                    else:
                        #当前访问的是父权限,也就是二级菜单,找自己显示
                        request.current_menu_id = id
                        request.breadcrumb_list.append({'title':item['title'],'url':item['url']})#向路径导航中添加二级菜单
                    return

    步骤4.在templatetags/rbac.py中配置过滤器预备模板渲染data

    @register.filter()
    def has_permission(request,urlname):
    
        if urlname in request.session.get(settings.PERMISSION_SESSION_KEY):
            return True
    
    #通过url反向解析的名称有无进行判断,从而在展示模板中进行显示

    步骤5.HTML模板渲染出权限对应的操作信息

    权限对应的操作
  • 相关阅读:
    解决GIT可视化工具Sourcetree拉取失败问题
    记录常用Git命令
    vue开发移动端使用rem的适配方案
    使用HBuilderX实现打包vue项目成app
    使用vue+webpack从零搭建项目
    整理最近面试问道的问题
    模块化之seaJs学习和使用
    理解Object.defineProperty的作用
    vue生命周期
    使用gulp编译sass
  • 原文地址:https://www.cnblogs.com/CrazySheldon1/p/10447685.html
Copyright © 2011-2022 走看看