Dcat Admin 后台进入表单页面,左侧菜单栏失去选中状态,怎么解决?

图片一:此为表格页面正确的选中状态

Dcat Admin 使用$form->hasMany() /$form->array() 编辑是如何将数据回显在编辑页面

图片二:此为表单页面,左侧菜单栏失去了选中状态。

Dcat Admin 使用$form->hasMany() /$form->array() 编辑是如何将数据回显在编辑页面

问题: 求助如何设置,进入表单页面左侧菜单栏,也通样是选中状态?

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
DogLoML
最佳答案

我这里试了下是这样的:从列表页点新增跳到创建不会丢失选中,直接输链接回车去创建页会丢失选中。
打开菜单的blade模板menu.blade.php可以看到

@if(empty($item['children']))
        <li class="nav-item">
            <a @if(mb_strpos($item['uri'], '://') !== false) target="_blank" @endif
               href="{{ $builder->getUrl($item['uri']) }}"
               class="nav-link {!! $builder->isActive($item) ? 'active' : '' !!}">
                {!! str_repeat('&nbsp;', $depth) !!}<i class="fa fa-fw {{ $item['icon'] ?: $defaultIcon }}"></i>
                <p>
                    {{ $builder->translate($item['title']) }}
                </p>
            </a>
        </li>
    @else

判断是否选中的按钮是$builder->isActive($item) 这个方法,我们在去src/Layout/Menu.php找方法具体是如何判断的。

    public function isActive($item, ?string $path = null)
    {


        if (empty($path)) {
            $path = request()->path();
        }

        if (empty($item['children'])) {
            if (empty($item['uri'])) {
                return false;
            }
            return trim($this->getPath($item['uri']), '/') == $path;
        }

        foreach ($item['children'] as $v) {
            Log::info($path.'---'.trim($this->getPath($v['uri']), '/'));
            if ($path == trim($this->getPath($v['uri']), '/')) {
                return true;
            }
            if (! empty($v['children'])) {
                if ($this->isActive($v, $path)) {
                    return true;
                }
            }
        }

        return false;
    }

这里我把信息记录到日志里方便查看

[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/auth/users  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/ranks  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/jobs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/outs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/separations  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/holiday-rules  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/outs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/separations  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/holiday-rules  

可以看到uri其实就是菜单对应的链接uri,path就是当前地址,由于没有单独判断create、edit等情况,所以无法保持选中。那为啥从列表点进去是选中的呢?因为用了pjax局部加载,左边其实还是原来的。

解决办法:通过查看源码可以发现src/AdminServiceProvider.php中,$this->app->singleton(‘admin.menu’, Menu::class);这行将Menu注入到了单例容器里,因此只要新建一个子类Menu,然后继承dcat自带的Menu,接着重写isActive方法,对特殊路由判断处理。完事之后,到admin/bootstrap把容器里面的Menu替换成我们修改之后的就ok了。

app()->singleton('admin.menu', \App\Admin\Rewrites\Menu::class);

我把判断逻辑改为从$path里面找uri,如果是以uri开头就返回真。

<?php
namespace App\Admin\Rewrites;



class Menu extends \Dcat\Admin\Layout\Menu
{
    /**
     * 判断是否选中.
     *
     * @param  array  $item
     * @param  null|string  $path
     * @return bool
     */
    public function isActive($item, ?string $path = null)
    {


        if (empty($path)) {
            $path = request()->path();
        }

        if (empty($item['children'])) {
            if (empty($item['uri'])) {
                return false;
            }
            // 原先是直接比较path和uri是否相等,现在改成path是否以uri开头,临时写的,有更好的方法判断的话可以交流下。
            //return trim($this->getPath($item['uri']), '/') == $path;
            return strpos( $path, trim($this->getPath($item['uri']), '/'))===0;
        }

        foreach ($item['children'] as $v) {
            //if ($path == trim($this->getPath($v['uri']), '/')) {
            if (strpos( $path, trim($this->getPath($v['uri']), '/'))===0) {
                return true;
            }
            if (! empty($v['children'])) {
                if ($this->isActive($v, $path)) {
                    return true;
                }
            }
        }

        return false;
    }

}
2年前 评论
你是我的眼 (楼主) 2年前
讨论数量: 5

版本号是多少?升级下试试

2年前 评论
你是我的眼 (楼主) 2年前
Su (作者) 2年前
DogLoML

我这里试了下是这样的:从列表页点新增跳到创建不会丢失选中,直接输链接回车去创建页会丢失选中。
打开菜单的blade模板menu.blade.php可以看到

@if(empty($item['children']))
        <li class="nav-item">
            <a @if(mb_strpos($item['uri'], '://') !== false) target="_blank" @endif
               href="{{ $builder->getUrl($item['uri']) }}"
               class="nav-link {!! $builder->isActive($item) ? 'active' : '' !!}">
                {!! str_repeat('&nbsp;', $depth) !!}<i class="fa fa-fw {{ $item['icon'] ?: $defaultIcon }}"></i>
                <p>
                    {{ $builder->translate($item['title']) }}
                </p>
            </a>
        </li>
    @else

判断是否选中的按钮是$builder->isActive($item) 这个方法,我们在去src/Layout/Menu.php找方法具体是如何判断的。

    public function isActive($item, ?string $path = null)
    {


        if (empty($path)) {
            $path = request()->path();
        }

        if (empty($item['children'])) {
            if (empty($item['uri'])) {
                return false;
            }
            return trim($this->getPath($item['uri']), '/') == $path;
        }

        foreach ($item['children'] as $v) {
            Log::info($path.'---'.trim($this->getPath($v['uri']), '/'));
            if ($path == trim($this->getPath($v['uri']), '/')) {
                return true;
            }
            if (! empty($v['children'])) {
                if ($this->isActive($v, $path)) {
                    return true;
                }
            }
        }

        return false;
    }

这里我把信息记录到日志里方便查看

[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/auth/users  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/ranks  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/jobs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/outs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/separations  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/holiday-rules  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/outs  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/separations  
[2021-11-26 10:15:25] local.INFO: admin/jobs/create---admin/holiday-rules  

可以看到uri其实就是菜单对应的链接uri,path就是当前地址,由于没有单独判断create、edit等情况,所以无法保持选中。那为啥从列表点进去是选中的呢?因为用了pjax局部加载,左边其实还是原来的。

解决办法:通过查看源码可以发现src/AdminServiceProvider.php中,$this->app->singleton(‘admin.menu’, Menu::class);这行将Menu注入到了单例容器里,因此只要新建一个子类Menu,然后继承dcat自带的Menu,接着重写isActive方法,对特殊路由判断处理。完事之后,到admin/bootstrap把容器里面的Menu替换成我们修改之后的就ok了。

app()->singleton('admin.menu', \App\Admin\Rewrites\Menu::class);

我把判断逻辑改为从$path里面找uri,如果是以uri开头就返回真。

<?php
namespace App\Admin\Rewrites;



class Menu extends \Dcat\Admin\Layout\Menu
{
    /**
     * 判断是否选中.
     *
     * @param  array  $item
     * @param  null|string  $path
     * @return bool
     */
    public function isActive($item, ?string $path = null)
    {


        if (empty($path)) {
            $path = request()->path();
        }

        if (empty($item['children'])) {
            if (empty($item['uri'])) {
                return false;
            }
            // 原先是直接比较path和uri是否相等,现在改成path是否以uri开头,临时写的,有更好的方法判断的话可以交流下。
            //return trim($this->getPath($item['uri']), '/') == $path;
            return strpos( $path, trim($this->getPath($item['uri']), '/'))===0;
        }

        foreach ($item['children'] as $v) {
            //if ($path == trim($this->getPath($v['uri']), '/')) {
            if (strpos( $path, trim($this->getPath($v['uri']), '/'))===0) {
                return true;
            }
            if (! empty($v['children'])) {
                if ($this->isActive($v, $path)) {
                    return true;
                }
            }
        }

        return false;
    }

}
2年前 评论
你是我的眼 (楼主) 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!