You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多关键词多列按规则排序搜索及滚动加载实现求助

Laravel 多关键词搜索排序+滚动加载解决方案

一、查询排序核心实现

针对你要的匹配优先级(全3个关键词>前2个>仅第1个),可以通过权重计算+排序来实现,同时保证结果不重复:

1. 控制器查询代码

public function search()
{
    $word1 = request()->input('word1');
    $word2 = request()->input('word2');
    $word3 = request()->input('word3');

    // 构造带权重计算的查询
    $query = DB::table('your_table') // 替换成你的表名
        ->select('*', DB::raw("
            CASE
                // 匹配全部3个关键词,权重3
                WHEN (meta_name LIKE ? OR meta_description LIKE ?) 
                     AND (meta_name LIKE ? OR meta_description LIKE ?) 
                     AND (meta_name LIKE ? OR meta_description LIKE ?) THEN 3
                // 匹配前2个关键词,权重2
                WHEN (meta_name LIKE ? OR meta_description LIKE ?) 
                     AND (meta_name LIKE ? OR meta_description LIKE ?) THEN 2
                // 仅匹配第1个关键词,权重1
                WHEN (meta_name LIKE ? OR meta_description LIKE ?) THEN 1
                ELSE 0
            END AS match_weight
        ", [
            "%{$word1}%", "%{$word1}%",
            "%{$word2}%", "%{$word2}%",
            "%{$word3}%", "%{$word3}%",
            "%{$word1}%", "%{$word1}%",
            "%{$word2}%", "%{$word2}%",
            "%{$word1}%", "%{$word1}%"
        ]))
        // 过滤至少匹配第1个关键词的记录
        ->where(function ($q) use ($word1) {
            $q->where('meta_name', 'like', "%{$word1}%")
              ->orWhere('meta_description', 'like', "%{$word1}%");
        })
        // 只保留有权重的记录(排除完全不匹配的)
        ->having('match_weight', '>', 0)
        // 按权重降序排序,权重相同的可以再加主键排序保证稳定
        ->orderBy('match_weight', 'desc')
        ->orderBy('id', 'asc')
        // 去重(用主键groupBy比distinct更稳妥,避免同一条记录因多列匹配重复出现)
        ->groupBy('id');

    // 分页处理(用于滚动加载)
    $results = $query->paginate(10);

    // 区分AJAX请求和初始页面请求
    if (request()->wantsJson()) {
        return response()->json($results->items());
    }

    return view('search', compact('results'));
}

关键说明

  • 用CASE语句给不同匹配程度的记录分配权重,直接在数据库层面完成排序逻辑,效率更高
  • groupBy('id')确保同一条记录不会因为同时在meta_name和meta_description匹配关键词而重复出现
  • 外层where保证只返回至少包含第一个关键词的结果,避免无效数据

二、滚动加载实现

1. 前端视图(Blade)

<div id="search-results">
    @foreach($results as $item)
        <div class="result-card">
            <h3>{{ $item->meta_name }}</h3>
            <p>{{ $item->meta_description }}</p>
        </div>
    @endforeach
</div>

<div id="loading" style="display: none; text-align: center; padding: 1rem;">加载中...</div>
<div id="no-more" style="display: none; text-align: center; padding: 1rem; color: #999;">没有更多内容了</div>

2. 滚动监听JS代码

let currentPage = 2;
let isLoading = false;
let hasMore = true;

// 监听滚动事件
window.addEventListener('scroll', () => {
    if (isLoading || !hasMore) return;

    // 判断是否滚动到页面底部(留100px提前触发加载)
    if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 100) {
        loadMoreResults();
    }
});

function loadMoreResults() {
    isLoading = true;
    document.getElementById('loading').style.display = 'block';

    // 携带搜索关键词和当前页码请求数据
    fetch(`/search?word1={{ request()->word1 }}&word2={{ request()->word2 }}&word3={{ request()->word3 }}&page=${currentPage}`)
        .then(res => res.json())
        .then(data => {
            isLoading = false;
            document.getElementById('loading').style.display = 'none';

            if (data.length === 0) {
                hasMore = false;
                document.getElementById('no-more').style.display = 'block';
                return;
            }

            // 追加新数据到结果容器
            const container = document.getElementById('search-results');
            data.forEach(item => {
                const card = document.createElement('div');
                card.className = 'result-card';
                card.innerHTML = `
                    <h3>${item.meta_name}</h3>
                    <p>${item.meta_description}</p>
                `;
                container.appendChild(card);
            });

            currentPage++;
        })
        .catch(err => {
            isLoading = false;
            document.getElementById('loading').style.display = 'none';
            console.error('加载失败:', err);
        });
}

3. 路由配置

Route::get('/search', [SearchController::class, 'search']);

内容的提问来源于stack exchange,提问作者Istiaque Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 03:35:37