Laravel单视图中如何展示数据列表与数据详情
解决列表与详情同页展示的问题
不用再次循环所有文章啦!你现在的问题是详情区的$post没有对应到用户点击的具体文章,咱们分几种方案来实现,选适合你的就行:
方案一:AJAX动态加载详情(适合文章数量多的场景)
这种方式初始只加载列表,点击时再请求对应文章的详情,能减少页面初始加载体积。
1. 修改列表项,添加文章标识
把列表里的<a>标签改成带文章ID的点击触发元素,避免页面跳转:
<a class="grid__item" href="javascript:void(0)" data-post-id="{{ $post->id }}"> <h2 class="title title--preview">{{$post->title}}</h2> <span class="category">{{$post->title}}</span> <div class="loader"></div> <div class="meta meta--preview"> <img class="meta__avatar" src="{{ Voyager::image( $post->image ) }}" alt="{{$post->title}}" /> <span class="meta__date"><i class="fa fa-calendar-o"></i>{{$post->created_at->format('m-d-Y')}}</span> <span class="meta__reading-time"><i class="fa fa-clock-o"></i>{{$post->created_at->format('H:i')}}</span> </div> </a>
2. 改造详情区域为动态模板
先留空或者默认显示第一篇文章的内容:
<section class="content" id="postContent"> <div class="scroll-wrap"> <article class="content__item" id="postDetail"> @if($posts->isNotEmpty()) <!-- 默认显示第一篇 --> <span class="category category--full">{{ $posts[0]->title }}</span> <h2 class="title title--full">{{ $posts[0]->title }}</h2> <div class="meta meta--full"> <img class="meta__avatar" src="{{ Voyager::image( $posts[0]->image ) }}" alt="{{ $posts[0]->title }}" /> <span class="meta__author">{{ $posts[0]->author ?? $posts[0]->title }}</span> <span class="meta__date"><i class="fa fa-calendar-o"></i>{{ $posts[0]->created_at->format('m/d/Y') }}</span> <span class="meta__reading-time"><i class="fa fa-clock-o"></i>{{ $posts[0]->created_at->format('H:i') }}</span> </div> <div class="post-content">{!! $posts[0]->content !!}</div> @endif </article> </div> <button class="close-button"><i class="fa fa-close"></i><span>Close</span></button> </section>
3. 写JS实现点击加载逻辑
用原生JS就能搞定,不需要额外依赖:
const postItems = document.querySelectorAll('.grid__item'); const postDetail = document.getElementById('postDetail'); const closeBtn = document.querySelector('.close-button'); const contentSection = document.getElementById('postContent'); // 给每个列表项绑定点击事件 postItems.forEach(item => { item.addEventListener('click', async () => { const postId = item.dataset.postId; // 发请求拿文章详情(需要后端对应接口) const res = await fetch(`/posts/${postId}`); const post = await res.json(); // 填充详情内容 postDetail.innerHTML = ` <span class="category category--full">${post.title}</span> <h2 class="title title--full">${post.title}</h2> <div class="meta meta--full"> <img class="meta__avatar" src="${post.image_url}" alt="${post.title}" /> <span class="meta__author">${post.author ?? post.title}</span> <span class="meta__date"><i class="fa fa-calendar-o"></i>${new Date(post.created_at).toLocaleDateString()}</span> <span class="meta__reading-time"><i class="fa fa-clock-o"></i>${new Date(post.created_at).toLocaleTimeString()}</span> </div> <div class="post-content">${post.content}</div> `; // 显示详情区 contentSection.style.display = 'block'; }); }); // 关闭按钮逻辑 closeBtn.addEventListener('click', () => { contentSection.style.display = 'none'; });
4. 后端准备接口(Laravel示例)
在PostController里加一个返回文章详情的方法:
public function show(Post $post) { // 处理Voyager图片路径 $post->image_url = Voyager::image($post->image); return response()->json($post); }
然后在路由文件(web.php或api.php)加一条路由:
Route::get('/posts/{post}', [PostController::class, 'show']);
方案二:提前渲染所有详情(适合文章数量少的场景)
这种方式一次性把所有文章详情都渲染到页面,通过CSS控制显示隐藏,不用发AJAX请求:
1. 渲染所有文章详情
把详情区改成循环渲染每个文章的内容,默认只显示第一篇:
<section class="content"> <div class="scroll-wrap"> @foreach($posts as $index => $post) <article class="content__item {{ $index === 0 ? 'active' : 'hidden' }}" id="post-{{ $post->id }}"> <span class="category category--full">{{ $post->title }}</span> <h2 class="title title--full">{{ $post->title }}</h2> <div class="meta meta--full"> <img class="meta__avatar" src="{{ Voyager::image( $post->image ) }}" alt="{{ $post->title }}" /> <span class="meta__author">{{ $post->author ?? $post->title }}</span> <span class="meta__date"><i class="fa fa-calendar-o"></i>{{ $post->created_at->format('m/d/Y') }}</span> <span class="meta__reading-time"><i class="fa fa-clock-o"></i>{{ $post->created_at->format('H:i') }}</span> </div> <div class="post-content">{!! $post->content !!}</div> </article> @endforeach </div> <button class="close-button"><i class="fa fa-close"></i><span>Close</span></button> </section>
2. 添加CSS控制显示隐藏
.content__item.hidden { display: none; } .content__item.active { display: block; }
3. 写JS切换显示
const postItems = document.querySelectorAll('.grid__item'); const closeBtn = document.querySelector('.close-button'); const contentSection = document.querySelector('.content'); postItems.forEach(item => { item.addEventListener('click', () => { const postId = item.dataset.postId; // 隐藏所有详情 document.querySelectorAll('.content__item').forEach(detail => { detail.classList.add('hidden'); detail.classList.remove('active'); }); // 显示对应文章的详情 document.getElementById(`post-${postId}`).classList.remove('hidden'); document.getElementById(`post-${postId}`).classList.add('active'); contentSection.style.display = 'block'; }); }); closeBtn.addEventListener('click', () => { contentSection.style.display = 'none'; });
两种方案各有优劣,根据你的文章数量和需求选就行~
内容的提问来源于stack exchange,提问作者madiluzi
相关产品推荐
相关产品推荐

