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

来源:undefined 2025-02-03 01:44:21 1028

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

目录

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

了解组件

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

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

前端实施

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

<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"

>

youve 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>

登录后复制

主要前端功能

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

分页参数

:

1

2

3

4

5

6

:params="{

data: {

page: page.props.postspagination.current_page + 1,

},

only: [posts, postspagination],

}"

登录后复制
data:指定要加载的下一页 only:通过仅获取所需数据来优化请求 加载状态:组件优雅地处理加载和内容结束状态。

后端实施

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

<?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

2

3

4

5

if (!request()->header(x-inertia)) {

// full page load logic

} else {

// regular pagination for infinite scroll

}

登录后复制
整页加载:当用户刷新或直接访问页面时,我们会获取所有先前的页面以保持正确的滚动位置:

1

2

3

4

for ($page = 1; $page <= $currentpage; $page++) {

$pageresults = $query->paginate($perpage, [*], page, $page);

$allresults = $allresults->concat($pageresults->items());

}

登录后复制
高效查询:实现包括关系预加载和范围查询:

1

2

3

$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 文档 无限滚动的网页可访问性指南

以上就是使用 Laravel、Inertiajs v 和 Vue 3 实现无限滚动的详细内容,更多请关注php中文网其它相关文章!

最新文章