Laravel中如何筛选与指定标签关联的所有文章?
实现Laravel博客按标签筛选文章功能
看起来你已经搭好了基础的表结构,接下来咱们一步步实现点击标签筛选文章的功能:
1. 补全关联表迁移
你提供的关联表代码没写完,这里补全完整的article_tag表迁移(注意要添加外键约束和联合主键,避免重复关联):
public function up() { Schema::create('article_tag', function (Blueprint $table) { $table->unsignedInteger('article_id'); $table->unsignedInteger('tag_id'); // 外键约束,删除文章/标签时自动删除关联记录 $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade'); $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); // 设置联合主键,确保同一文章和标签不会重复关联 $table->primary(['article_id', 'tag_id']); }); }
2. 定义模型多对多关联
Laravel的多对多关联需要在两个模型中分别定义关联方法:
Tag模型(app/Models/Tag.php)
namespace App\Models; use Illuminate\Database\Eloquent\Model; class Tag extends Model { // 允许批量赋值的字段 protected $fillable = ['tags']; // 关联文章:一个标签对应多篇文章 public function articles() { return $this->belongsToMany(Article::class); } }
Article模型(app/Models/Article.php)
namespace App\Models; use Illuminate\Database\Eloquent\Model; class Article extends Model { // 替换成你实际的文章字段 protected $fillable = ['title', 'content', 'published_at']; // 关联标签:一篇文章对应多个标签 public function tags() { return $this->belongsToMany(Tag::class); } }
3. 添加路由
在routes/web.php中添加处理标签筛选的路由:
use App\Http\Controllers\TagController; // 路由名称方便视图中生成链接 Route::get('/tags/{tag}', [TagController::class, 'show'])->name('tags.show');
4. 编写控制器逻辑
创建TagController并实现show方法,用于获取指定标签下的所有文章:
namespace App\Http\Controllers; use App\Models\Tag; class TagController extends Controller { public function show(Tag $tag) { // 预加载文章数据,避免N+1查询问题 $tag->load('articles'); // 如果需要分页,改用下面的代码: // $articles = $tag->articles()->paginate(10); return view('tags.show', compact('tag')); } }
5. 视图层实现
给标签添加跳转链接
在文章列表或详情页中,给每个标签加上跳转链接(比如articles/show.blade.php或articles/index.blade.php):
{{-- 遍历文章的所有标签 --}} @foreach($article->tags as $tag) <a href="{{ route('tags.show', $tag) }}" class="inline-block px-3 py-1 bg-gray-100 rounded-full text-sm mr-2"> {{ $tag->tags }} </a> @endforeach
标签文章列表视图
创建resources/views/tags/show.blade.php,展示该标签下的所有文章:
<div class="container mx-auto px-4 py-8"> <h1 class="text-2xl font-bold mb-6">标签: {{ $tag->tags }}</h1> <div class="space-y-6"> @foreach($tag->articles as $article) <div class="border p-4 rounded-lg"> <h2 class="text-xl font-semibold mb-2"> <a href="{{ route('articles.show', $article) }}" class="hover:text-blue-600"> {{ $article->title }} </a> </h2> <p class="text-gray-700 mb-3">{{ Str::limit($article->content, 150) }}</p> <p class="text-sm text-gray-500">发布于 {{ $article->created_at->format('Y-m-d H:i') }}</p> </div> @endforeach {{-- 如果用分页,添加分页导航 --}} {{-- {{ $articles->links() }} --}} </div> </div>
小建议
你的标签表字段名是tags,语义上有点奇怪,建议改成name更符合常规。如果已经建表,可以通过迁移修改:
public function up() { Schema::table('tags', function (Blueprint $table) { $table->renameColumn('tags', 'name'); }); }
修改后记得更新模型的$fillable和视图中的字段引用(把$tag->tags改成$tag->name)。
内容的提问来源于stack exchange,提问作者Brij Sharma
相关产品推荐
相关产品推荐

