Hello! 欢迎来到小浪资源网!



使用 Laravel、Inertiajs v 和 Vue 3 实现无限滚动


使用 Laravel、Inertiajs v 和 Vue 3 实现无限滚动

在这篇综合指南中,我们将探索如何使用 inertia.JS v2.0 和 vue 3 在 laravel 应用程序中实现无限滚动。我们将介绍前端和后端实现,特别注意处理整页刷新并保持滚动位置。

目录

  • 了解组件
  • 前端实现
  • 后端实现
  • 现实示例:带有类别的博客文章
  • 最佳实践和注意事项

了解组件

无限滚动的实现依赖于三个主要组件:

  1. inertia.js v2.0 的 whenvisible 组件:该组件处理交叉观察者逻辑以检测何时需要加载更多内容。
  2. laravel 的分页:处理服务器端分页逻辑。
  3. vue 3 的 composition api:管理我们的前端状态和反应性。

前端实施

让我们从一个为博客文章列表实现无限滚动的 vue 组件开始:

<script setup> import { computed } from 'vue' import { usepage, whenvisible } from '@inertiajs/vue3' import loadingspinner from '@/components/loadingspinner.vue' import blogpostcard from '@/components/blogpostcard.vue'  const page = usepage()  const hasfeaturepost = computed(() => !!page.props.featuredpost) const categoryname = computed(() => page.props.category?.name) </script>  <template>     <div class="bg-gray-50">         <!-- featured post section -->         <div             v-if="hasfeaturepost"             class="container"         >             <div class="py-8 text-center">                 <h2 class="mb-4 text-3xl font-bold">                     featured post: {{ page.props.featuredpost.title }}                 </h2>             </div>         </div>          <!-- posts grid -->         <div class="max-w-7xl px-4 py-8 mx-auto sm:px-6 lg:px-8">             <h1 class="text-2xl font-bold mb-6">                 {{ categoryname ? `posts in ${categoryname}` : 'all posts' }}             </h1>              <div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">                 <div                     v-for="post in page.props.posts"                     :key="post.id"                     class="relative flex flex-col"                 >                     <blog-post-card :post="post" />                 </div>                  <!-- infinite scroll handler -->                 <whenvisible                     :always="page.props.postspagination?.current_page < page.props.postspagination?.last_page"                     :params="{                         data: {                             page: page.props.postspagination.current_page + 1,                         },                         only: ['posts', 'postspagination'],                     }"                 >                     <div                         v-if="page.props.postspagination?.current_page >= page.props.postspagination?.last_page"                         class="text-center py-6 text-gray-600 col-span-1 md:col-span-2 lg:col-span-3"                     >                         you've reached the end!                     </div>                     <div                         v-else                         class="col-span-1 md:col-span-2 lg:col-span-3"                     >                         <loading-spinner />                     </div>                 </whenvisible>             </div>         </div>     </div> </template> 

主要前端功能

  1. whenvisible 组件:当元素在视口中可见时,inertia.js v2.0 中的此组件会自动触发请求。

  2. 分页参数:

:params="{     data: {         page: page.props.postspagination.current_page + 1,     },     only: ['posts', 'postspagination'], }" 
  • data:指定要加载的下一页
  • only:通过仅获取所需数据来优化请求
  1. 加载状态:组件优雅地处理加载和内容结束状态。

后端实施

这是处理常规分页和整页加载场景的 laravel 控制器实现:

<?php  namespace apphttpcontrollers;  use appmodelspost; use appmodelscategory; use illuminatepaginationlengthawarepaginator; use inertiainertia;  class blogcontroller extends controller {     public function index(?category $category = null)     {         return inertia::render('blog/index', [             'category' => $category,             'featuredpost' => $this->getfeaturedpost(),             'posts' => $this->getpaginatedposts($category),             'postspagination' => $this->getpaginatedposts($category)?->toarray(),         ]);     }      protected function getpaginatedposts(?category $category): ?lengthawarepaginator     {         $currentpage = request()->input('page', 1);         $perpage = request()->input('per_page', 12);          $query = post::query()             ->with(['author', 'category'])             ->published();          if ($category) {             $query->where('category_id', $category->id);         }          // apply any additional filters         if (request()->has('sort')) {             $query->orderby(request()->input('sort'), request()->input('direction', 'desc'));         } else {             $query->latest();         }          // handle full page load vs. infinite scroll request         if (!request()->header('x-inertia')) {             // full page load - fetch all pages up to current             $allresults = collect();              for ($page = 1; $page <= $currentpage; $page++) {                 $pageresults = $query->paginate($perpage, ['*'], 'page', $page);                 $allresults = $allresults->concat($pageresults->items());             }              return new lengthawarepaginator(                 $allresults,                 post::query()                     ->published()                     ->when($category, fn($q) => $q->where('category_id', $category->id))                     ->count(),                 $perpage,                 $currentpage             );         }          return $query->paginate($perpage);     }      protected function getfeaturedpost()     {         return post::query()             ->with(['author', 'category'])             ->published()             ->featured()             ->latest()             ->first();     } } 

主要后端功能

  1. 分页处理
if (!request()->header('x-inertia')) {     // full page load logic } else {     // regular pagination for infinite scroll } 
  1. 整页加载:当用户刷新或直接访问页面时,我们会获取所有先前的页面以保持正确的滚动位置:
for ($page = 1; $page <= $currentpage; $page++) {     $pageresults = $query->paginate($perpage, ['*'], 'page', $page);     $allresults = $allresults->concat($pageresults->items()); } 
  1. 高效查询:实现包括关系预加载和范围查询:
$query = Post::query()     ->with(['author', 'category'])     ->published(); 

结论

使用 laravel 和 inertia.js v2.0 实现无限滚动可提供流畅的用户体验,同时保持良好的性能和 SEO 实践。 vue 3 的 composition api 和 inertia.js 的 whenvisible 组件的结合使其易于实现和维护。

立即学习前端免费学习笔记(深入)”;

记住:

  • 彻底测试实现,特别是对于边缘情况
  • 监控性能指标
  • 考虑为禁用 JavaScript 的用户实施后备
  • 实现无限滚动时请记住可访问性

此实现可以适用于博客文章之外的各种用例,例如产品列表、图片库或任何其他受益于无限滚动的内容。

其他资源

  • inertia.js 文档
  • laravel 文档
  • vue 3 文档
  • 无限滚动的网页可访问性指南

相关阅读