修改larave分页地址,不带分号,seo

2019-12-29 15:04:43

参考地址 Laravel 把传参的分页 url 改为 /page/11

laravel 实现页面伪静态增强 seo

Laravel 中通过自定义分页器分页方法实现伪静态分页链接以利于 SEO

我们知道,Laravel 自带的分页器方法包含 simplePaginate 和 paginate 方法,一个返回不带页码的分页链接,另一个返回带页码的分页链接,但是这两种分页链接页码都是以带问号的动态参数形式附加在查询字符串中,形如 https://laravelacademy.org?page=100,但是这种包含动态参数的 URL 格式对 SEO 不友好,我们最好将其转化为 https://laravelacademy.org/page/100 这种不带问号的伪静态分页链接格式,遗憾的是 Laravel 并没有提供对这种伪静态分页链接格式的自定义支持,只好自己动手了。

我们将基于 paginate 方法实现的分页进行扩展,只是修改其分页链接格式,该方法底层调用了 Illuminate\Pagination\LengthAwarePaginator 类实现分页,所以我们需要自定义一个继承自该分页器类的 app/Utils/AcademyPaginator.php,详细如下看:

任务把传参的分页 url 改为 /page/11

http://www.24test.com/news/zhongchao?page=...

把 url 改为 /page/11

找到了
news 路由 指向与

D:\web\work\trunk\24_project\project_test\sports-transfer\module\Article\Controller\Web\type()

type 指向了 topic 方法

topic 中的分页是 直接使用了

$this->paging()

paging 位于 ArticlePaging 的一个 trait

分页的页码是直接使用了参数来获取的

$request = app(Request::class);

解决方案

改动路由,把参数改为路由占位符传参
找到路由文件
D:\web\work\trunk\24_project\project_test\sports-transfer\module\Article\Provider\RouteProvider.php--68line

我们直接加上路由参数

    Route::get("/news/{type}/page/{pages}/", "ListController@type");// pagine 改为占位符

直接如下

修改分页样式

在 article.blade.php 中我们找到了引入了分页文件
位于:D:\web\work\trunk\24_project\project_test\sports-transfer\resources\views\pc\layout\block-pagination-style.blade.php

那我们在此处直接修改分页生产的 url

我们需要去找到类去修改 更为合适

直接修改分页类

D:\web\work\trunk\24_project\project_test\sports-transfer\vendor\laravel\framework\src\Illuminate\Pagination\AbstractPaginator.php--line 137

加上正则的判断

/**
     * Get the URL for a given page number.
     *
     * @param  int  $page
     * @return string
     */
    // public function url($page)
    // {
    //     if ($page <= 0) {
    //         $page = 1;
    //     }

    //     // If we have any extra query string key / value pairs that need to be added
    //     // onto the URL, we will put them in query string form and then attach it
    //     // to the URL. This allows for extra information like sortings storage.
    //     $parameters = [$this->pageName => $page];

    //     if (count($this->query) > 0) {
    //         $parameters = array_merge($this->query, $parameters);
    //     }

    //     return $this->path
    //                     .(Str::contains($this->path, '?') ? '&' : '?')
    //                     .http_build_query($parameters, '', '&')
    //                     .$this->buildFragment();
    // }

    /**
     * 重写页面 URL 实现代码,去掉分页中的问号,实现伪静态链接
     * @access public 
     * @param int $page
     * @since 1.1 
     * @return string
     */
    public function url($page)
    {
        if ($page <= 0) {
            $page = 1;
        }

        // 移除路径尾部的/
        $path = rtrim($this->path, '/');

        // 如果路径中包含分页信息则正则替换页码,否则将页码信息追加到路径末尾
        if (preg_match('/\/page\/\d+/', $path)) {
            $path = preg_replace('/\/page\/\d+/', '/page/' . $page, $path);
        } else {
            $path .= '/page/' . $page;
        }
        $this->path = $path;

        if ($this->query) {
            $url = $this->path . (Str::contains($this->path, '?') ? '&' : '?')
                . http_build_query($this->query, '', '&')
                . $this->buildFragment();
        } elseif ($this->fragment) {
            $url = $this->path . $this->buildFragment();
        } else {
            $url = $this->path;
        }

        return $url;
    }

它是在这里将分页信息作为查询参数的一部分放到分页链接中,所以我们需要在自定义的 AcademyPaginator 类中重写这个方法覆盖父类实现:

/**
 * 重写页面 URL 实现代码,去掉分页中的问号,实现伪静态链接
 * @param int $page
 * @return string
 */public function url($page){
    if ($page <= 0) {
        $page = 1;
    }

    // 移除路径尾部的/
    $path = rtrim($this->path, '/');

    // 如果路径中包含分页信息则正则替换页码,否则将页码信息追加到路径末尾
    if (preg_match('/\/page\/\d+/', $path)) {
        $path = preg_replace('/\/page\/\d+/', '/page/' . $page, $path);
    } else {
        $path .= '/page/' . $page;
    }
    $this->path = $path;

    if ($this->query) {
        $url = $this->path . (Str::contains($this->path, '?') ? '&' : '?')
            . http_build_query($this->query, '', '&')
            . $this->buildFragment();
    } elseif ($this->fragment) {
        $url = $this->path . $this->buildFragment();
    } else {
        $url = $this->path;
    }

    return $url;}

至此,我们自定义的分页器类已经编写好了,接下来还要将这个分页器注册到模型类的查询构建器中以便可以像 simplePaginate 和 paginate 方法那样在模型实例上调用,这里我们需要借助查询构建器 Illuminate\Database\Eloquent\Builder 提供的静态 macro 方法在运行时动态扩展其提供的方法,我们还是在 AcademyPaginator 中定义这个方法扩展实现:

/**
 * 将新增的分页方法注册到查询构建器中,以便在模型实例上使用
 * 注册方式:
 * 在 AppServiceProvider 的 boot 方法中注册:AcademyPaginator::rejectIntoBuilder();
 * 使用方式:
 * 将之前代码中在模型实例上调用 paginate 方法改为调用 seoPaginate 方法即可:
 * Article::where('status', 1)->seoPaginate(15, ['*'], 'page', page);
 */public static function injectIntoBuilder(){
    Builder::macro('seoPaginate', function ($perPage, $columns, $pageName, $page) {
        $perPage = $perPage ?: $this->model->getPerPage();

        $items = ($total = $this->toBase()->getCountForPagination())
            ? $this->forPage($page, $perPage)->get($columns)
            : $this->model->newCollection();

        $options = [
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ];

        return Container::getInstance()->makeWith(AcademyPaginator::class, compact(
            'items', 'total', 'perPage', 'page', 'options'
        ));
    });}

这样,在模型实例上调用 seoPaginate 方法,将通过 AcademyPaginator 进行分页,最后我们在 AppServiceProvider 的 boot 方法中全局调用这个注入:

// 为查询构建器注入自己实现的分页器方法AcademyPaginator::injectIntoBuilder();接下来,就可以在自己的代码中编写以下这种代码实现伪静态分页链接了:$articles = Article::with('author', 'category')->public()->orderBy('id', 'desc')->seoPaginate($pageSize, $this->listColumns, 'page', $page);

致谢

https://www.cnblogs.com/liangzia/p/6223129...

为啥子 只要使用 seoPaginate?

因为

// 为查询构建器注入自己实现的分页器方法
        // Builder 提供的静态macro 方法在运行时动态扩展 所以我们实现时候只要
        // 将之前代码中在模型实例上调用 paginate 方法改为调用 seoPaginate 方法即可:
        // @author bobo
        // @date 2019-11-01

解决问题记录

本人代码是自己写的实现分页方法 直接 new 到了 laravel 底层的类传入属性

那我们这里不可以调用属性 seoPaginate

解决方法:

直接 new AcademyPaginator 类传入属性即可

/**
     * @param $articles Collection
     * @param int $pn
     * @return LengthAwarePaginator
     */
    /** 
    * topic  
    * 分页 占位符方式传参
    * 此处方法为兼容版本 担心其他地方调用报错
    * @access public 
    * @param mixed $arg1 列表页数据类型 
    * @param int $arg2 分页条目数 默认为空 
    * @param int $arg3 页码 默认为空 
    * @date 2019-11-01
    * @author bobo<1576554465@qq.com>
    * @version     $1.1$ 
    * @since 1.0 
    * @return html 
    */ 
    public function paging($articles, $pn = 10,$page=null) {

        $request = app(Request::class);
        // dd($request);
        // 拿到页码  request有 
        if ($request->has('page')) {
            $pl = $request->input('page');
            $pl = $pl <= 0 ? 1 :$pl;
        } elseif(!empty($page)) {
            // 传递的页码不为空则直接赋值
            $pl = $page;
            $pl = $pl <= 0 ? 1 :$pl;
        } else {
            $pl = 1;
        }
        // $object = new LengthAwarePaginator($articles->slice(($pl-1)*$pn, $pn), $articles->count(), $pn, $pl,[
        // 使用新方法seoPaginate 
        $object = new AcademyPaginator($articles->slice(($pl-1)*$pn, $pn), $articles->count(), $pn, $pl,[
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => 'page',
        ]);
        $object->clazz = 'page';

        return $object;
    }

排查其他受影响的 url

基本不影响,因为我们是适配使用的,只要你使用的是 laravel 提供的分页类即可。
而且路由没有进行大改


  • 2021-02-03 16:58:39

    iOS静态库与动态库的区别与打包

    这篇主要是记录一下 iOS 下静态库与动态库的打包流程,以便以后用到时快速查阅,供自己也供大家学习记录。同时也简述了一下 动态库 与 静态库 的区别。

  • 2021-02-03 16:59:59

    iOS 静态库和动态库全分析

    库就是程序代码的集合,将 N 个文件组织起来,是共享程序代码的一种方式。从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。

  • 2021-02-03 17:01:30

    iOS库 .a与.framework区别

    静态库:连接时完整地拷贝至可执行文件中,被屡次使用就有多份冗余拷贝。 动态库:连接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

  • 2021-02-03 17:13:58

    iOS - 封装静态库

    静态库:链接时完整的拷贝至可执行文件中,被多次使用就有多份冗余拷贝,.a的静态库 .framework的静态库

  • 2021-02-03 17:16:07

    iOS 中的动态库、静态库和 framework

    首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。 什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。

  • 2021-02-03 17:17:53

    iOS 同一个工程下打包不同的app

    应用图标,启动画面,应用启动后的首页都不一样。 有些课程(例如公务员考试和高考)是有目标考试的概念,不同的目标考试大纲是不一样的。拿高考来举例,北京的高考和上海的高考,就有着完全不一样的考试大纲。高考的文科和理科,又有着完全不同的考试科目。 有些课程会有一些自定义的界面,例如高考的应用可以设置昵称,有些课程的真题练习中是有推荐真题模块的,而有些课程又没有。 有些课程有扫描答题卡功能,有些课程有考前冲刺功能,有些课程有大题专项查看功能,而有些课程又没有上述功能。另外还有一些微小细节,但是解决方法和类似,所以就不一一展开说明。

  • 2021-02-04 14:02:30

    window软件界面找不到了跑到屏幕外面去了

    一般可以这样操作,按Alt+空格,然后按M,然后用上下左右键把窗口移动到能看到的地方,再按回车。有些第三方的软件可能不能用,大部分都可以这样做。

  • 2021-02-04 14:08:13

    基于 Electron 的爬虫框架 Nightmare

    Electron 可以让你使用纯 JavaScript 调用 Chrome 丰富的原生的接口来创造桌面应用。你可以把它看作一个专注于桌面应用的 Node.js 的变体,而不是 Web 服务器。其基于浏览器的应用方式可以极方便的做各种响应式的交互,接下来介绍下关于 Electron 上衍生出的框架 Nightmare

  • 2021-02-04 20:13:02

    iOS framework制作及使用(包含xib和图片)

    静态库与动态库简介: 静态库:链接使用时完整地拷贝至可执行文件中 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次 本文制作framework对应xcode版本:10.1