大家晚安。当我想显示多对多关系数据时遇到问题,即基于带有 livewire 标签的邮政数据。之前我试过在laravel中可以出现。
现在我想用 livewire 按标签显示帖子数据,但仍然不能。
以下是我编写的代码。
web.php
Route::get('tag/{tag:slug}',[FrontController::class, 'tag'])->name('tag');
FrontController.php
public function tag(Tag $tag)
{
$categories = Category::all();
$general = General::find(1);
$locale = App::currentLocale();
$search = request("search");
$posts = $tag->posts()->where([
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate(12);
if ($this->search !== null) {
$posts = $tag->posts()->where([
['title','like', '%' . $search . '%'],
['lang',$locale],
['status','PUBLISH'],
])->latest()->paginate(12);
}
// dd($posts);
$tags = Tag::all();
$top = Post::where('status','PUBLISH')->orderBy('views','desc')->limit(5)->get();
return view ('front.tag',compact('categories','general','locale','posts','tags','top'));
}
tag.blade.php
@extends('layouts.front')
@section('content')
<main id="main">
<section class="post-category">
<div class="container-fluid">
<div class="row mt-3">
<div class="col-lg-3 col-md-12 col-sm-12 d-none d-lg-block">
<div class="sticky-top" style="top: 90px;">
<div class="card mb-3 rounded-3">
<div class="card-body">
<a href="#" target="_blank" rel="noreferrer">
<img src="{{ asset('front/img/ads.png') }}" alt="..." height="300" width="279" class="card-img-top" />
</a>
</div>
</div>
<div class="d-flex flex-column mb-3 bg-light shadow bg-body rounded">
<div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
{{ __('sentence.category') }}
</div>
<ul class="list-group list-group-flush">
@foreach ($categories as $category)
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{{ route('category', $category->slug) }}">{{ $category->name }}</a>
</li>
@endforeach
</ul>
</div>
<div class="d-flex flex-column bg-light bg-body shadow-lg rounded-3">
<div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
Tags
</div>
<div class="p-3 overflow-auto" style="max-height: 42vh">
<div class="nav tag-cloud">
@foreach ($tags as $tag)
<a href="{{ route('tag', $tag->slug) }}">{{ $tag->name }}</a>
@endforeach
</div>
</div>
</div>
</div>
</div>
<livewire:tag-index>
<div class="col-lg-3 col-md-12 col-sm-12">
<div class="sticky-top" style="top: 90px;">
<div class="card rounded-3 shadow-lg mb-3">
<div class="card-body">
<img src="{{ asset('front/img/ads1.png') }}" height="117" width="279" class="card-img-top" alt="...">
</div>
</div>
<div class="bg-light shadow bg-body rounded-3 mb-3">
<div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
{{ __('sentence.top_article') }}
</div>
<ul class="list-group list-group-flush mb-2">
@foreach ($top as $top)
<li class="list-group-item">
<a href="{{ route('blogShow', $top->slug) }}">{{ $top->title }}</a>
<div class="d-flex justify-content-between mt-3">
<small class="text-muted">{{ Carbon\Carbon::parse($top->created_at)->format("d F, Y") }}</small>
<small class="text-muted">{{ $top->views }} views </small>
</div>
</li>
@endforeach
</ul>
</div>
<div class="d-flex flex-column mb-3 bg-light shadow bg-body rounded d-lg-none d-xl-none">
<div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
{{ __('sentence.category') }}
</div>
<ul class="list-group list-group-flush">
@foreach ($categories as $category)
<li class="list-group-item d-flex justify-content-between align-items-center">
<a href="{{ route('category', $category->slug) }}">{{ $category->name }}</a>
</li>
@endforeach
</ul>
</div>
<div class="d-flex flex-column bg-light bg-body shadow-lg rounded-3 d-lg-none d-xl-none">
<div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
{{ __('sentence.tag') }}
</div>
<div class="p-3 overflow-auto" style="max-height: 42vh">
<div class="nav tag-cloud">
@foreach ($tags as $tag)
<a href="{{ route('tag', $tag->slug) }}">{{ $tag->name }}</a>
@endforeach
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
@endsection
@push('scripts')
@livewireScripts
<script type="text/javascript">
window.onscroll = function (ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
window.livewire.emit('tag-index');
}
};
</script>
<script>
document.getElementById('load-more').onclick = function() {
window.livewire.emit('tag-index');
};
</script>
@endpush
livewire\TagIndex.php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\{Tag, Post};
use Illuminate\Support\Facades\App;
class TagIndex extends Component
{
public $limitPerPage = 10;
public $search;
protected $listeners = [
'tag-index' => 'TagIndex'
];
protected $updatesQueryString = [
['search' => ['except' => '']],
];
public function TagIndex()
{
$this->limitPerPage = $this->limitPerPage + 6;
}
public function render(Tag $tag)
{
$locale = App::currentLocale();
$posts = $tag->posts()->where([
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate($this->limitPerPage);
if ($this->search !== null) {
$posts = $tag->posts()->where([
['title','like', '%' . $this->search . '%'],
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate($this->limitPerPage);
}
$this->emit('postStore');
return view('livewire.tag-index', ['posts' => $posts]);
}
}
livewire\tag-index.blade.php
<div class="col-lg-6 col-md-12 col-sm-12">
<div id="section-title" class="section-title p-1 pt-3">
<h2 class="text-center fw-bold">{{ trans('sentence.recent_posts')}}</h2>
</div>
<div class="form-group has-search mb-3">
<span class="bi bi-search form-control-feedback"></span>
<input type="text" wire:model="search" class="form-control" placeholder="{{ __('sentence.search_form') }}">
</div>
@foreach ($posts as $data)
<div class="card bg-light shadow bg-body rounded-3 mb-2">
<div class="card-header bg-primary text-white d-flex justify-content-between">
<small>by {{$data->admin->name}}</small>
<small>{{ Carbon\Carbon::parse($data->created_at)->format("d F, Y") }}</small>
</div>
<div class="card-body">
<h2 class="card-title">
<a href="{{ route('blogShow', $data->slug) }}">{{ $data->title }}</a>
</h2>
<div class="card-footer bg-body d-flex justify-content-between align-items-center pb-0 px-0">
<div class="d-flex my-1">
@foreach ($data->tags as $tag)
<a href="{{ route('tag', $tag->slug) }}" class="badge {{ $tag->bg }} me-1 shadow-sm text-white">{{ $tag->name }}</a>
@endforeach
</div>
</div>
</div>
</div>
@endforeach
@if ($posts->count() == 0)
<div class="alert alert-danger" role="alert">
Data not found!
</div>
@endif
@if($posts->count() >= 10)
<div class="text-center d-md-none d-lg-none d-xl-none">
<button id="load-more" class="btn btn-primary my-3">
Load More
</button>
</div>
@endif
</div>
使用 livewire 显示多对多关系数据的正确方法或代码是什么?在这种情况下,我想按标签显示发布数据。谢谢
答案 0 :(得分:1)
您的问题中有很多额外的 stuff
,因此我为您整理了一个简化的示例。您需要完成剩余的工作才能将其纳入您的项目。
我不知道您是如何显示 tag
标签或其他任何东西的,所以我选择了 checkboxes
,因为它看起来最合理。可以将这些样式设置为隐藏,以便它们更类似于 SO 上的 tag
标签,但同样,我会将 bike shedding
留给您。
我创建了一个名为 Tags
的 Livewire component
,并带有关联的 blade
视图。
tags.blade.php
<div>
{{-- loop over each of the tags --}}
@foreach ($this->tags as $tag)
{{-- wire:key is important here as Livewire requires it for effective DOM diffing! --}}
<div wire:key="tag-{{ $tag->id }}" class="block px-4 py-2">
{{--
this is where we bind the checkboxes
to a property on the Livewire component
--}}
<input wire:model="selectedTags" type="checkbox" id="tag-{{ $tag->id }}" name="{{ $tag->title }}" value="{{ $tag->id }}">
<label for="{{ $tag->title }}">{{ $tag->title }}</label>
</div>
@endforeach
{{-- loop over each of the posts --}}
@foreach ($this->posts as $post)
{{-- again, don't overlook wire:key! --}}
<div wire:key="post-{{ $post->id }}" class="block px-4 py-2">
<h4 class="text-sm">{{ $post->title }}</h4>
</div>
@endforeach
</div>
以上应该大部分是不言自明的,唯一可能不是的位是 wire:model="selectedTags"
。 selectedTags
组件上定义了一个名为 Tags
的公共属性(稍后您将看到),它的作用是允许我们在选中某个复选框时管理该数组中的元素。因此,例如,当有人使用 tag
的 id
选中 12
的复选框时,selectedTags
数组添加了一个元素,其中的 value
为 {{1} }.
Tags.php
12
同样,上面应该是不言自明的,因为没有任何不寻常的事情发生。
class Tags extends Component
{
// array of selected tags (checked checkboxes)
public $selectedTags = [];
// get just the id and title of each tag
public function getTagsProperty()
{
return Tag::select('id', 'title')->get();
}
public function getPostsProperty()
{
$tags = array_filter($this->selectedTags);
// if no tags are selected, return all posts
// you might decide to return nothing, up to you
if (!$tags) {
return Post::all();
}
// if there are some selected tags
// query the database for posts with the selectedTags
// this is an `OR` operation on tags
// if you want `AND` you'll need to change it
return Post::whereHas('tags', function ($query) use ($tags) {
$query->whereIn('tags.id', $tags);
})->get();
}
public function render()
{
return view('livewire.tags');
}
}
和 getPostsProperty()
函数定义了 computed properties
,它们是可选的,如果您愿意,可以使用普通属性。但是,如果您在组件视图中多次引用 getTagsProperty()
和 $tags
,计算属性的性能会更高,因为它不会每次都调用后端组件。
答案 1 :(得分:0)
已解决
感谢@Peppermintology 帮助我解决了两个问题,现在此问题已通过以下代码解决。
FrontController.php
public function tag(Tag $tag)
{
$categories = Category::all();
$general = General::find(1);
$locale = App::currentLocale();
$tag_id = $tag->id;
$search = request("search");
$posts = $tag->posts()->where([
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate(12);
if ($this->search !== null) {
$posts = $tag->posts()->where([
['title','like', '%' . $search . '%'],
['lang',$locale],
['status','PUBLISH'],
])->latest()->paginate(12);
}
$tags = Tag::all();
$top = Post::where('status','PUBLISH')->orderBy('views','desc')->limit(5)->get();
return view ('front.tag',compact('categories','general','locale','posts','tags','tag_id','top'));
}
livewire\TagIndex.php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\{Tag, Post};
use Illuminate\Support\Facades\App;
class TagIndex extends Component
{
public $limitPerPage = 10;
public $search, $tagId;
protected $listeners = [
'tag-index' => 'TagIndex'
];
protected $updatesQueryString = [
['search' => ['except' => '']],
];
public function TagIndex()
{
$this->limitPerPage = $this->limitPerPage + 6;
}
public function render()
{
$locale = App::currentLocale();
$tag_id = $this->tagId;
$tag = Tag::find($tag_id);
$posts = $tag->posts()->where([
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate($this->limitPerPage);
if ($this->search !== null) {
$posts = $tag->posts()->where([
['title','like', '%' . $this->search . '%'],
['status','PUBLISH'],
['lang',$locale],
])->latest()->paginate($this->limitPerPage);
}
$this->emit('postStore');
// dd($posts);
return view('livewire.tag-index', ['posts' => $posts, 'tag' => $tag]);
}
}