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

Symfony 3.3.6中基于jQuery自动补全实现双搜索栏功能求助

嘿,我来帮你一步步搞定这个需求!在Symfony 3.3.6里实现带自动补全的双搜索栏(工种+城市),还要展示对应工匠,其实分后端接口开发、前端交互实现、样式贴近参考网站这三块来做就清晰了,咱们一个个来拆解:

一、Symfony后端:提供自动补全与搜索接口

首先得确保你已经有对应的实体(比如Craftsman工匠、JobType工种、City城市),接下来创建控制器和Repository方法来处理AJAX请求:

1. 创建搜索控制器

// src/AppBundle/Controller/SearchController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use AppBundle\Entity\JobType;
use AppBundle\Entity\City;
use AppBundle\Entity\Craftsman;

class SearchController extends Controller
{
    // 工种自动补全接口
    public function jobTypeAutocompleteAction(Request $request)
    {
        $query = $request->query->get('term', '');
        $em = $this->getDoctrine()->getManager();
        
        // 调用Repository的模糊查询方法
        $jobTypes = $em->getRepository(JobType::class)->findByTerm($query);
        
        $results = [];
        foreach ($jobTypes as $jobType) {
            $results[] = [
                'id' => $jobType->getId(),
                'label' => $jobType->getName(),
                'value' => $jobType->getName()
            ];
        }
        
        return new JsonResponse($results);
    }
    
    // 城市自动补全接口
    public function cityAutocompleteAction(Request $request)
    {
        $query = $request->query->get('term', '');
        $em = $this->getDoctrine()->getManager();
        
        $cities = $em->getRepository(City::class)->findByTerm($query);
        
        $results = [];
        foreach ($cities as $city) {
            $results[] = [
                'id' => $city->getId(),
                'label' => $city->getName() . ' (' . $city->getZipCode() . ')',
                'value' => $city->getName()
            ];
        }
        
        return new JsonResponse($results);
    }
    
    // 根据工种+城市查询工匠列表
    public function searchCraftsmenAction(Request $request)
    {
        $jobTypeId = $request->query->get('job_type_id');
        $cityId = $request->query->get('city_id');
        
        $em = $this->getDoctrine()->getManager();
        $craftsmen = $em->getRepository(Craftsman::class)->findByJobTypeAndCity($jobTypeId, $cityId);
        
        return $this->render('search/craftsmen_list.html.twig', [
            'craftsmen' => $craftsmen
        ]);
    }
}

2. 给Repository添加查询方法

比如JobTypeRepository:

// src/AppBundle/Repository/JobTypeRepository.php
namespace AppBundle\Repository;

use AppBundle\Entity\JobType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;

class JobTypeRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, JobType::class);
    }
    
    public function findByTerm($term)
    {
        return $this->createQueryBuilder('j')
            ->where('j.name LIKE :term')
            ->setParameter('term', '%' . $term . '%')
            ->orderBy('j.name', 'ASC')
            ->setMaxResults(10) // 限制返回数量,避免太多结果
            ->getQuery()
            ->getResult();
    }
}

CityRepository的findByTerm方法和上面类似,CraftsmanRepository的findByJobTypeAndCity则根据实体关联关系编写查询(比如工匠关联工种和城市)。

3. 配置路由

在app/config/routing.yml中添加:

job_type_autocomplete:
    path: /search/job-type-autocomplete
    defaults: { _controller: AppBundle:Search:jobTypeAutocomplete }

city_autocomplete:
    path: /search/city-autocomplete
    defaults: { _controller: AppBundle:Search:cityAutocomplete }

search_craftsmen:
    path: /search/craftsmen
    defaults: { _controller: AppBundle:Search:searchCraftsmen }
二、前端:用jQuery UI Autocomplete实现交互

首先要引入jQuery和jQuery UI的资源(可以用CDN或本地文件),然后编写页面模板和JS逻辑:

1. 搜索页面模板

创建search/index.html.twig:

{% extends 'base.html.twig' %}

{% block stylesheets %}
    {{ parent() }}
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <!-- 自定义样式放在下面,后面会讲怎么贴近参考网站 -->
{% endblock %}

{% block body %}
    <div class="search-container">
        <h1>Trouver un artisan</h1>
        <div class="search-fields">
            <div class="field-group">
                <label for="job-type">Métier</label>
                <input type="text" id="job-type" placeholder="Ex: Plombier, Électricien">
                <input type="hidden" id="job-type-id"> <!-- 存选中的工种ID -->
            </div>
            <div class="field-group">
                <label for="city">Ville</label>
                <input type="text" id="city" placeholder="Ex: Paris, Lyon">
                <input type="hidden" id="city-id"> <!-- 存选中的城市ID -->
            </div>
            <button id="search-btn">Rechercher</button>
        </div>
        <div id="craftsmen-results"></div>
    </div>
{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
    <script>
        $(document).ready(function() {
            // 工种自动补全
            $('#job-type').autocomplete({
                source: '{{ path('job_type_autocomplete') }}',
                minLength: 2, // 输入至少2个字符才触发
                select: function(event, ui) {
                    $('#job-type-id').val(ui.item.id); // 选中后把ID存到隐藏域
                }
            });

            // 城市自动补全
            $('#city').autocomplete({
                source: '{{ path('city_autocomplete') }}',
                minLength: 2,
                select: function(event, ui) {
                    $('#city-id').val(ui.item.id);
                }
            });

            // 搜索按钮点击事件
            $('#search-btn').click(function() {
                var jobTypeId = $('#job-type-id').val();
                var cityId = $('#city-id').val();

                if (!jobTypeId || !cityId) {
                    alert('Veuillez sélectionner un métier et une ville');
                    return;
                }

                // AJAX请求获取工匠列表
                $.ajax({
                    url: '{{ path('search_craftsmen') }}',
                    data: {
                        job_type_id: jobTypeId,
                        city_id: cityId
                    },
                    success: function(data) {
                        $('#craftsmen-results').html(data);
                    },
                    error: function() {
                        $('#craftsmen-results').html('<p>Erreur lors de la recherche</p>');
                    }
                });
            });

            // 可选:当两个字段都选好时自动触发搜索
            $('#job-type-id, #city-id').change(function() {
                var jobTypeId = $('#job-type-id').val();
                var cityId = $('#city-id').val();
                if (jobTypeId && cityId) {
                    $('#search-btn').click();
                }
            });
        });
    </script>
{% endblock %}

2. 工匠列表模板

创建search/craftsmen_list.html.twig:

{% if craftsmen|length > 0 %}
    <h2>Résultats de la recherche</h2>
    {% for craftsman in craftsmen %}
        <div class="craftsman-card">
            <h3>{{ craftsman.getName() }}</h3>
            <div class="craftsman-info">
                <p>{{ craftsman.getAddress() }}</p>
                <p>{{ craftsman.getPhone() }}</p>
                <p>Métier: {{ craftsman.getJobType().getName() }}</p>
            </div>
        </div>
    {% endfor %}
{% else %}
    <p>Aucun artisan trouvé pour ce métier et cette ville.</p>
{% endif %}
三、样式调整:贴近参考网站风格

参考目标网站的设计,给页面添加自定义样式,把下面的代码放到search/index.html.twig的{% block stylesheets %}里:

<style>
    .search-container {
        max-width: 900px;
        margin: 3rem auto;
        padding: 0 1.5rem;
    }
    .search-fields {
        display: flex;
        gap: 1.2rem;
        margin: 2.5rem 0;
        flex-wrap: wrap;
        align-items: flex-end;
    }
    .field-group {
        flex: 1;
        min-width: 220px;
    }
    .field-group label {
        display: block;
        margin-bottom: 0.6rem;
        font-weight: 600;
        color: #333;
    }
    .field-group input[type="text"] {
        width: 100%;
        padding: 1rem;
        border: 2px solid #e0e0e0;
        border-radius: 4px;
        font-size: 1.1rem;
        transition: border-color 0.2s;
    }
    .field-group input[type="text"]:focus {
        border-color: #ff6600;
        outline: none;
    }
    #search-btn {
        padding: 1rem 2.5rem;
        background-color: #ff6600;
        color: white;
        border: none;
        border-radius: 4px;
        font-size: 1.1rem;
        font-weight: 600;
        cursor: pointer;
        transition: background-color 0.2s;
    }
    #search-btn:hover {
        background-color: #e55a00;
    }
    .craftsman-card {
        border: 1px solid #eee;
        border-radius: 8px;
        padding: 1.8rem;
        margin-bottom: 1.2rem;
        background-color: white;
        box-shadow: 0 2px 6px rgba(0,0,0,0.05);
        transition: box-shadow 0.2s;
    }
    .craftsman-card:hover {
        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    }
    .craftsman-card h3 {
        margin-top: 0;
        color: #ff6600;
        font-size: 1.3rem;
    }
    .craftsman-info {
        display: flex;
        gap: 1.5rem;
        margin-top: 0.8rem;
        flex-wrap: wrap;
        color: #555;
    }
    .craftsman-info p {
        margin: 0;
        display: flex;
        align-items: center;
        gap: 0.3rem;
    }
</style>

这样一套下来,就能实现你想要的功能啦!如果还有细节需要调整,比如自动补全的样式、工匠卡片的内容,都可以根据需求再修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:28:32