Featured image of post 记一次跳不出思维解决 admin pjax 自定义刷新页面问题

记一次跳不出思维解决 admin pjax 自定义刷新页面问题

来一次脑筋急转弯

  • 项目里使用laravel-admin搭建后台, 然后做了一个小功能, 右上角增加一个消息通知

  • 如上图, 右上角有一个小铃铛, 点击之后清空消息, 并刷新当前页面. 使用的是laravel-adminaction去操作
<?php

namespace App\Admin\Actions\Custom;

use Encore\Admin\Actions\Action;
use Illuminate\Http\Request;

class MarkNotificationRead extends Action
{
    protected $selector = '.mark-notification-read';

    public function handle(Request $request)
    {        
        // forget notifications
        return $this->response()->success("已读所有消息")->refresh();
    }


    public function html()
    {
        // get notifications
        $count = 1;
        $countText = "<span class=\"label label-danger\">{$count}</span>";

        return "<li title='点击标记为已读'>
    <a href=\"#\" class='mark-notification-read'>
      <i data-count='{$count}' id='notification' class=\"fa fa-bell fa-rotate-0\"></i>
      {$countText}
    </a>
</li>";
    }
}
  • 如上伪代码实现了一个通知, 当用户点击按钮的时候会触发handle方法,然后刷新当前页面

  • 但是由于laravel-admin采用pjax导致无法刷新整个页面, 只会刷新下方的内容页面, 所以即使点击了也无法使小铃铛的1变成``

  • 看了文档, 在handle方法使用 \Admin::disablePjax(); 禁用pjax, 不生效(应该在页面级别加,而不是处理的方法)

  • 之后查看了一下MarkNotificationRead继承的Action有一个方法

    • 之前思维一直卡在pjax了, 一直没想到在Action处理
    • 总是想着应该在页面级别处理pjax
  • 父类中的handleActionPromise是处理ajax请求之后的handle, 随后重写父类的方法handleActionPromise

    public function handleActionPromise()
    {
        $resolve = <<<'SCRIPT'
var actionResolver = function (data) {

            var response = data[0];
            var target   = data[1];
            console.log(data);

            if (typeof response !== 'object') {
                return $.admin.swal({type: 'error', title: 'Oops!'});
            }

            var then = function (then) {
                if (then.action == 'refresh') {
                    // 增加这一行代码
                    window.location.reload();
                    return;
                }

                if (then.action == 'download') {
                    window.open(then.value, '_blank');
                }

                if (then.action == 'redirect') {
                    $.admin.redirect(then.value);
                }

                if (then.action == 'location') {
                    window.location = then.value;
                }

                if (then.action == 'open') {
                    window.open(then.value, '_blank');
                }
            };

            if (typeof response.html === 'string') {
                target.html(response.html);
            }

            if (typeof response.swal === 'object') {
                $.admin.swal(response.swal);
            }

            if (typeof response.toastr === 'object' && response.toastr.type) {
                $.admin.toastr[response.toastr.type](response.toastr.content, '', response.toastr.options);
            }

            if (response.then) {
              then(response.then);
            }
        };

        var actionCatcher = function (request) {
            if (request && typeof request.responseJSON === 'object') {
                $.admin.toastr.error(request.responseJSON.message, '', {positionClass:"toast-bottom-center", timeOut: 10000}).css("width","500px")
            }
        };
SCRIPT;

        \Encore\Admin\Admin::script($resolve);

        return <<<'SCRIPT'
process.then(actionResolver).catch(actionCatcher);
SCRIPT;
    }

  • handle增加了一个window.location.reload();, 处理起来比较复杂
  • 相比之下Dcat Admin在这方面做得很多,直接在Action类重写父类方法
    /**
     * 设置动作发起请求前的回调函数,返回false可以中断请求.
     *
     * @return string
     */
    protected function actionScript()
    {
        // 发起请求之前回调,返回false可以中断请求
        return <<<'JS'
function (data, target, action) { }
JS;
    }

    /**
     * 设置请求成功回调,返回false可以中断默认的成功处理逻辑.
     *
     * @return string
     */
    protected function resolverScript()
    {
        // 请求成功回调,返回false可以中断默认的成功处理逻辑
        return <<<'JS'
function (target, results) {}
JS;
    }

    /**
     * 处理接口返回的HTML代码.
     *
     * @return string
     */
    protected function handleHtmlResponse()
    {
        return <<<'JS'
function (target, html, data) {
    target.html(html);
}
JS;
    }

    /**
     * 设置请求出错回调,返回false可以中断默认的错误处理逻辑.
     *
     * @return string
     */
    protected function rejectScript()
    {
        return <<<'JS'
function (target, results) {}
JS;
    }

总结

  • 处理问题而不要直接凭感官觉得是某部分出问题(当然后时候也应该这样子)
    • 一开始总觉得是PJAX的问题, 就一直绕进去了.
  • 当用这个方式无法解决问题的时候, 是继续深究还是换一个思路
    • 这个没办法得出结论, 可能深究之后也有答案, 换个方式也有答案
    • 可能就是一个度的问题