我们如何在 Laravel 中对随机记录进行分页显示?例如:
$products = Product::all()->orderBy(DB::raw('RAND()'));
$products->paginate(4);
$products->setPath('products');
上述操作会导致重复记录,因为顺序是随机的。
我该如何持久化 $products 对象,以便在新的页面请求时,它可以通过相同/固定的随机记录集进行过滤?我们如何在 Laravel 中对随机记录进行分页显示?例如:
$products = Product::all()->orderBy(DB::raw('RAND()'));
$products->paginate(4);
$products->setPath('products');
上述操作会导致重复记录,因为顺序是随机的。
我该如何持久化 $products 对象,以便在新的页面请求时,它可以通过相同/固定的随机记录集进行过滤?当你深入阅读mysql的文档 并查找RAND()功能时,你会发现可以使用“种子”。
通过使用种子,您将始终获得随机化的相同结果。
示例:
$products = Product
::all()
->orderBy(DB::raw('RAND(1234)'))
->paginate(4);
你可以生成自己的种子并将其存储在会话或其他地方以记住它。
更新
Laravel查询构建器现在有一个完全相同的功能:$products = Product
::all()
->inRandomOrder('1234')
->paginate(4);
Laravel+Eloquent解决方案
在Eloquent查询之前,设置会话变量。我使用time()作为会话值,因此我可以在一定时间内保持相同的排序。例如,3600秒(1小时)。
if ($request->session()->has('session_rand')) {
if((time() - $request->session()->get('session_rand')) > 3600){
$request->session()->put('session_rand', time());
}
}else{
$request->session()->put('session_rand', time());
}
使用DB::raw()和我们上面设置的会话变量,将orderBy()添加到Eloquent查询中:
->orderBy(DB::raw('RAND('.$request->session()->get('session_rand').')'))
解决方案 Ajax + chunk + session + lazyload + paginate + eloquent + blade
获取所有产品,为每个块设置项目数量(类似于分页),并将其存储到会话中(我们将块存储到会话中,因此当 ajax 请求到来时,它不会再次调用 $products = Product::inRandomOrder()->get();
),第一个块将是第一个分页。
当 ajax 请求更多产品时,它将从会话中获取产品,并根据 ajax 请求的页面号获取正确的产品块。
如果没有更多块,则返回而不带任何产品。
if(!$request->ajax()){
$products = Product::inRandomOrder()->get();
$chunks = $products->chunk(4);
\Session::put('chunks',$chunks);
$products = $chunks[0];
}else{
$page = $request->all()['page'];
$chunks = \Session::get('chunks');
if(count($chunks)<$page){
\Session::forget('chunks');
return;
}else{
$products = $chunks[$page-1];
}
}
if ($request->ajax()) {
$view = view('product_lazyLoad',compact('products'))->render();
return response()->json(['html'=>$view]);
}
return view('products',compact('products'));
products.blade.php :主页面
@if($products)
<ul class="row" id="productLists">
@include('product_lazyLoad')
</ul>
@endif
<!-- load records -->
<div class="col-12 ajax-load text-center" style="display:none">
<p><img src="/images/loader.gif">Loading More Products</p>
</div>
product_lazyload.blade.php:显示产品
@foreach($products as $product)
<div>
<p>Display your products here</p>
</div>
@endforeach
//lazy load
var page = 1;
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() >= $(document).height())
{
page++;
loadMoreData(page);
}
});
function loadMoreData(page){
$.ajax({
url: '?page=' + page,
type: "get",
beforeSend: function(){
$('.ajax-load').show();
}
}).done(function(data){
if(!data.html){
$('.ajax-load').html("No more records found");
$('.ajax-load').show();
return;
}
$('.ajax-load').hide();
$("#productLists").append(data.html);
}).fail(function(jqXHR, ajaxOptions, thrownError){
//error handle
});
}