به عنوان توسعهدهندگان، ما همیشه به دنبال ابزارها، کتابخانهها و فریمورک هایی هستیم که کار را برایمان آسانتر کنند. برای توسعه دهندگان لاراول تفاوتی ندارد. به همین دلیل است که ما این فریمورک را در ابتدا دوست داریم، زیرا همه چیز برای ما آسان شده است.به ما این امکان را می دهد که به جای درگیر شدن با نحوه پیاده سازی، روی ساخت برنامه های عالی تمرکز کنیم. در این مقاله، ما Livewire را به صورت عمیق بررسی خواهیم کرد و خواهیم دید که چگونه می توان آن را در برنامه های کاربردی دنیای واقعی استفاده کرد.
Livewire چیست؟
Livewire کتابخانه ای است که به ما اجازه می دهد با استفاده از Blade و کمی جاوا اسکریپت رابط های واکنشی و پویا بسازیم.و یک فریمورک full-stack می باشد. در گذشته برای ساخت اپلیکیشن با لاراول ، باید:
- قالب های Blade را بنویسید و برنامه خود را در سمت سرور رندر می کردیم.
- بک اند خود را بهعنوان APIهایی بنویسید که میپذیرند و با JSON پاسخ میدهند، و سپس یک فریم ورک فرانتاند مانند Vue، React یا Angular برای مصرف APIها و پیادهسازی UI داشته باشید.
اما اکنون، گزینه سومی داریم: Livewire.
میتوانید از Livewire برای اجرای عملکرد های زیر، بدون بارگذاری مجدد صفحه استفاده کنید:
- صفحه بندی
- اعتبار سنجی فرم
- اطلاعیه
- پیش نمایش آپلود فایل
توجه داشته باشید که Livewire به عملکردهای بالا محدود نمی شود. شما می توانید آن را برای خیلی جاهای بیشتر دیگر استفاده کنید. ویژگیهای بالا فقط رایجترین ویژگیهایی هستند که ممکن است بخواهید در برنامههای خود پیادهسازی کنید.
Livewire در مقابل Vue
Vue همیشه فریم ورک فرانتاند ترجیحی برای توسعهدهندگان لاراول بوده است تا یک تعاملی را به برنامههای خود اضافه کنند. اگر در حال حاضر از Vue برای تقویت برنامه های خود استفاده می کنید، Livewire برای یادگیری شما اختیاری است. اما اگر نسبتاً تازه کار هستید که در لاراول Front end انجام می دهید و به دنبال Livewire به عنوان جایگزین Vue هستید، بله، می توانید از Livewire به عنوان جایگزین Vue استفاده کنید. منحنی یادگیری Livewire به اندازه یادگیری Vue شیب دار نخواهد بود، زیرا بیشتر از Blade برای نوشتن فایل های قالب خود استفاده می کنید.
قبل از اینکه با هم دیگر یک پروژه را بسازیم، ابتدا با یک سری مفاهیم اصلی در Livewire بپردازیم و سپس طبق این مفاهیم سراغ اپلیکیشن خود برویم.
Livewire چگونه کار می کند؟
قبل از شروع، خوب است ایده ای داشته باشیم که Livewire چگونه کار خود را انجام می دهد. به طور خلاصه:
Livewire خروجی کامپوننت اولیه را به صفحه نمایش می دهد - بله، مانند قالب معمولی Blade که توسط سرور رندر شده است.هنگامی که یک تعامل اتفاق می افتد، Livewire یک درخواست AJAX را با داده های به روز شده به سرور ارسال می کند،سرور کامپوننت را دوباره ارائه می کند و با HTML به روز شده پاسخ می دهد، سپس Livewire به طور هوشمند DOM را با توجه به آنچه تغییر کرده است جهش می دهد.
همانطور که می بینید، مانند این است که فرانت اند و بک اند خود را در یک مکان قرار می دهید، بدون نیاز به تکرار.
مفاهیم کلیدی در Livewire
فعال کردن Livewire در یک صفحه
برای اینکه Livewire روی یک صفحه کار کند، باید استایل ها و اسکریپتهای Livewire را در هر صفحهای که به آنها نیاز دارد، اضافه کنید. معمولاً اینها وارد قالب پایه شما می شوند. این کار را با استفاده از livewireStyles@
و livewireScripts@
انجام می دهید:
//app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>@yield('title')</title>
@livewireStyles
</head>
<body>
@yield('content')
@livewireScripts
</body>
</html>
کامپوننت های Livewire
Livewire تمام خوبی های خود را در مورد کامپوننت های خود انجام می دهد. کامپوننت های Livewire کاملاً شبیه کامپوننت معمولی کلاس مبتنی بر Laravel Blade هستند. بیایید نگاهی گذرا به این دو بیندازیم.
ایجاد کامپوننت لاراول Blade
با اجرای دستور زیر یک کامپوننت Laravel Blade ایجاد می کنید:
php artisan make:component Alert
با این کار یک فایل کلاس Alert.php جدید ایجاد می کنیم و آن را در پوشه App\Views\Components
قرار می دهیم. سپس، یک نمای قالب مربوطه ایجاد می شود و در resources/views/components
ها قرار می گیرد. برای نمایش کامپوننت، می توانید از این دستور Blade استفاده کنید: <x-alert/>
.
می توانید کامپوننت Laravel Blade را در مستندات بیشتر بررسی کنید.
ایجاد کامپوننت Livewire
برای ایجاد یک کامپوننت Livewire، دستور زیر را اجرا کنید:
php artisan make:livewire Alert
این دستور همچنین دو فایل جدید ایجاد می کند: app\Http\Livewire\Alert.php
و یک resources/views/livewire/alert.php
.
میتوانید یک کامپوننت Livewire را با استفاده از <livewire:alert/>
یا livewire ('alert')@
رندر کنید.
همانطور که می بینید، دستورات کاملا مشابه هستند. تنها تفاوت عمده این است که با کامپوننت های Livewire، یک همگامسازی بلادرنگ (بدون نیاز به بهروزرسانی صفحه) بین کلاس کامپوننت و قالب view آن وجود دارد. ما به زودی خواهیم دید که چگونه این کار می کند.
Livewire properties
ویژگیهای عمومی در کلاسهای کامپوننت شما برای view قالب کامپوننت در دسترس است. به همین جا ختم نمی شود؛مقدار property در زمان واقعی با view سینک می شود، به طوری که وقتی مقدار property را در view به روز می کنید، به طور خودکار در کلاس کامپوننت به روز می شود.
//App\Http\Livewire\Alert.php
<?php
class Alert extends Component{
public $message = "Our alert message";
}
// livewire/alert.blade.php
<div>
<input wire:model="message">
<br/>
{{ $message }}
</div>
برای اتصال یک ویژگی کامپوننت به تگ input html، باید از دستور زیر استفاده کنید:
wire:model="property name"
با تایپ کردن در کادر input ، مقدار message$
به روز رسانی را در زمان واقعی مشاهده خواهید کرد. این بسیار شبیه مفهوم اتصال داده در فریمورک هایی مانند Vue.js، React و Angular است. در اینجا درباره ویژگی های Livewire بیشتر بدانید.
Livewire actions
همانطور که می توانید داده ها را در قالب view به ویژگی های عمومی کامپوننت ها متصل کنید، همچنین می توانید رویدادهای سمت کلاینت را به روش های موجود در کامپوننت های خود نگاشت کنید. به عنوان مثال، می توانید با استفاده از روش های تعریف شده در کلاس کامپوننت خود، به رویدادهای کلیک، رویدادهای keyup و keydow و غیره پاسخ دهید.
بیایید به یک مثال نگاه کنیم:
use Livewire\Component;
class PostAlert extends Component{
public $liked = true;
public function render(){
return view('livewire.post-alert');
}
public function toggleLike(){
$this->liked = !$this->liked;
}
}
// livewire/post-alert.blade.php
<div>
<h4>Seeing livewire action in action</h4>
<button class="btn btn-primary" wire:click="toggleLike()">
Like
</button>
@if ($liked)
<i class="fa fa-heart text-danger h4"></i>
@else
<i class="fa fa-heart text-secondary h4"></i>
@endif
</div>
در کلاس کامپوننت بالا، ما یک متد toggleLike
ایجاد کردیم که مقدار پروپرتی liked
را به مقدار بولی مخالف آن تغییر میدهد. در view قالب، یک دکمه و یک آیکون قلب داریم که بر اساس مقدار ویژگی liked
قرمز یا خاکستری است.
ما از سینتکس wire:click=[action name]
برای اتصال متد toggleLike
به رویداد کلیک استفاده کردیم.
بسیاری از موارد استفاده Livewire حول ویژگی ها و اکشن می چرخد، و به همین دلیل، درک آنها بسیار مهم است. این مفاهیم را می توان برای مواردی مانند ایجاد فرم، ویرایش فرم، حذف فرم، و غیره به کار برد.
اعتبار سنجی داده ها
Livewire اعتبار سنجی داده ها را یکپارچه می کند. برای اعتبارسنجی دادههایی که از view قالب فرم میآیند، باید یک ویژگی rules$
بنویسید که حاوی قوانین اعتبارسنجی شما است، درست مانند لاراول. پس از آن، ()this→validate$
را در متدی که اعتبارسنجی را انجام می دهد، فراخوانی می کنید.
بیایید به فرمی برای ایجاد یک پست وبلاگ نگاه کنیم:
...
class CreatePost extends Component
{
public $title, $body;
public $success;
protected $rules = [
'title' => 'required|string|max:220',
'body' => 'required'
];
public function render()
{
return view('livewire.create-post')
->extends('layouts.app')
->section('content');
}
public function create(){
$this->validate();
Post::create([
'title' => $this->title,
'slug' => Str::slug($this->title),
'body' => $this->body,
'author_id' => auth()->id()
]);
$this->success = true;
}
}
// livewire/create-post
<div class="container">
@if ($success)
<div class="alert alert-success">
Post has been created successfully
</div>
@endif
<form wire:submit.prevent="create">
<div class="form-group">
<label for="Post title">Post title</label>
<input wire:model="title" type="text" name="title" id="title" class="form-control" placeholder="Title of the post">
@error('title') <span class="error">{{ $message }}</span> @enderror
</div>
<div class="form-group">
<label for="Post body">Post Body</label>
<textarea name="body" id="body" placeholder="Body of post here..." wire:model="body" class="form-control"></textarea>
@error('body') <span class="error">{{ $message }}</span> @enderror
</div>
<div>
<button class="btn btn-primary" type="submit">Publish</button>
</div>
</form>
</div>
در کد فرم بالا، زمانی که کاربر پست را ارسال میکند، و آن را تایید نمیکند، خطاهای اعتبارسنجی نمایش داده میشوند، همه بدون بازخوانی صفحه.
درباره پروژه Livewire
ما قصد داریم یک برنامه زنده CRUD ایجاد کنیم. بنابراین اساساً یک برنامه CRUD بدون بارگیری مجدد صفحه است. Livewire تمام درخواست های AJAX مورد نیاز برای به روز رسانی UI را رسیدگی می کند. این شامل فیلتر کردن نتایج از طریق فیلد جستجو، مرتبسازی از طریق سربرگ ستون و صفحهبندی ساده (قبلی و بعدی) است.
شروع کار با Laravel Livewire
به اندازه کافی با Livewire آشنا شدیم و بریم سراغ پروژه و به صورت عملی موارد گفته شده را بررسی کنیم.
اکنون می توانید یک پروژه جدید لاراول ایجاد کنید:
composer create-project laravel/laravel newproject
داخل پوشه newproject
که ایجاد می کند بروید. این پوشه اصلی پروژه خواهد بود که در آن تمام دستورات را در طول این آموزش اجرا می کنید.
گام بعدی ایجاد یک دیتابیس MySQL با استفاده از ابزار مدیریت پایگاه داده انتخابی است. پایگاه داده را newproject
نامگذاری کنید.
وابستگی های back-end را نصب کنید
ما فقط یک وابستگی برای قسمت بک اند داریم و آن Livewire است. با دستور زیر آن را نصب کنید:
composer require livewire/livewire
راه اندازی دیتابیس
انتقال پیشفرض برای ایجاد جدول کاربران را بهروزرسانی کنید و فیلدهای سفارشی را که میخواهیم استفاده کنیم اضافه کنید:
// database/migrations/<timestamp>_create_users_table.php
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->enum('user_type', ['admin', 'user'])->default('user'); // add this
$table->tinyInteger('age'); // add this
$table->string('address')->nullable(); // add this
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
سپس دیتابیس factories/UserFactory/
را به روز کنید
فایل php.
و مقادیر را به فیلدهای سفارشی که اضافه کردهایم اضافه کنید:
// database/factories/UserFactory.php
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
// add these
'user_type' => 'user',
'age' => $this->faker->numberBetween(18, 60),
'address' => $this->faker->address,
];
}
در نهایت، فایل database/seeders/DatabaseSeeder.php
را باز کنید و برای ایجاد کاربران فیک :
// database/seeders/DatabaseSeeder.php
public function run()
{
\App\Models\User::factory(100)->create();
}
فراموش نکنید که فایل env.
خود را با دیتابیس آزمایشی که می خواهید استفاده کنید به روز کنید. در این مورد، من پایگاه داده را newproject
نامگذاری کرده ام. پس از انجام این کار، migrations
و seeder
را برای پر کردن دیتابیس اجرا کنید:
php artisan migrate
php artisan db:seed
کامپوننت Livewire را ایجاد کنید
می توانید از دستور make:livewire
برای ایجاد یک کامپوننت جدید Livewire استفاده کنید:
php artisan make:livewire LiveTable
با این کار فایل های زیر ایجاد می شود:
app/Http/Livewire/LiveTable.php
- کنترلر کامپوننتresources/views/livewire/live-table.blade.php
- فایل view کامپوننت
فایل source/views/livewire/live-table.blade.php
را باز کنید و موارد زیر را اضافه کنید:
<div>
<div class="row mb-4">
<div class="col-md-12">
<div class="float-right mt-5">
<input wire:model="search" class="form-control" type="text" placeholder="Search Users...">
</div>
</div>
</div>
<div class="row">
@if ($users->count())
<table class="table">
<thead>
<tr>
<th>
<a wire:click.prevent="sortBy('name')" role="button" href="#">
Name
@include('includes.sort-icon', ['field' => 'name'])
</a>
</th>
<th>
<a wire:click.prevent="sortBy('email')" role="button" href="#">
Email
@include('includes.sort-icon', ['field' => 'email'])
</a>
</th>
<th>
<a wire:click.prevent="sortBy('address')" role="button" href="#">
Address
@include('includes.sort-icon', ['field' => 'address'])
</a>
</th>
<th>
<a wire:click.prevent="sortBy('age')" role="button" href="#">
Age
@include('includes.sort-icon', ['field' => 'age'])
</a>
</th>
<th>
<a wire:click.prevent="sortBy('created_at')" role="button" href="#">
Created at
@include('includes.sort-icon', ['field' => 'created_at'])
</a>
</th>
<th>
Delete
</th>
<th>
Edit
</th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>{{ $user->address }}</td>
<td>{{ $user->age }}</td>
<td>{{ $user->created_at->format('m-d-Y') }}</td>
<td>
<button class="btn btn-sm btn-danger">
Delete
</button>
</td>
<td>
<button class="btn btn-sm btn-dark">
Edit
</button>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-warning">
Your query returned zero results.
</div>
@endif
</div>
<div class="row">
<div class="col">
{{ $users->links() }}
</div>
</div>
</div>
این تعداد زیادی کد است، بنابراین اجازه دهید آن را از بالا به پایین تجزیه کنیم. ابتدا فیلد جستجو برای جستجوی کاربران را داریم. ما می خواهیم کاربران بتوانند نتایج جستجوی خود را در حین تایپ ببینند. روشی که ما آن را پیاده سازی می کنیم با استفاده از wire:model
است. این به ما امکان می دهد نام متغیر را از کلاس کامپوننت (LiveTable) ارسال کنیم. هر آنچه کاربر در این فیلد تایپ کند با مقدار آن متغیر همگام سازی می شود. در این مورد، متغیر جستجو را متصل می کنیم:
<input wire:model="search" class="form-control" type="text" placeholder="Search Users...">
در کد کلاس کامپوننت LiveTable، متغیر محدود شده را مانند کد زیر مشاهده خواهید کرد. در Livewire به این property می گویند. اگر از Vue می آیید، پس این معادل state است. فقط ویژگی های public
را می توان مستقیماً از قسمت فرانت مشاهده کرد:
// app/Http/Livewire/LiveTable.php
<?php
class LiveTable extends Component
{
public $search = ''; // don't add this yet
}
بعد، سرفصل های جدول را داریم. در اینجا ما از wire:click.prevent
برای گوش دادن به رویدادهای کلیک در تگ لینک استفاده می کنیم. در Livewire به این اکشن (action) می گویند. آنها اساساً به شما امکان میدهند به رویدادهای مرورگر گوش دهید.استفاده از prevent.
از عملکرد پیش فرض مرورگر جلوگیری می کند. مقداری که به این میدهید، نام روشی است که میخواهید در کلاس کامپوننت اجرا کنید. در این مورد sortBy
است. سپس نام ستونی را که میخواهیم مرتب کنیم ارسال میکنیم:
<th>
<a wire:click.prevent="sortBy('name')" role="button" href="#">
Name
@include('includes.sort-icon', ['field' => 'name'])
</a>
</th>
در اینجا روش مربوطه در کلاس کامپوننت به نظر می رسد. ما کد این مورد را بعداً اضافه خواهیم کرد:
// app/Http/Livewire/LiveTable.php
public function sortBy($field)
{
//
}
در کد بالا، فایل view دیگری به نام sort-icon را قرار داده ایم. یک فایل source/views/includes/sort-icon.blade.php
ایجاد کنید و موارد زیر را اضافه کنید. با این کار icon مرتب سازی فعلی بر اساس مرتب سازی فعلی انتخاب شده توسط کاربر ارائه می شود:
@if ($sortField !== $field)
<i class="text-muted fas fa-sort"></i>
@elseif ($sortAsc)
<i class="fas fa-sort-up"></i>
@else
<i class="fas fa-sort-down"></i>
@endif
این تقریباً برای نشانه گذاری است. بقیه کدها اساساً مشابه قالب استاندارد Blade شما هستند. بنابراین ما همچنان از متد ()links
برای نشان دادن صفحه بندی و دستور if@
برای نمایش شروط چیزی استفاده می کنیم.
اکنون به کلاس کامپوننت می رویم. فایل app/Http/Livewire/LiveTable.php
را باز کنید و آن را بهروزرسانی کنید تا حاوی کد زیر باشد:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use Livewire\WithPagination;
use App\Models\User;
class LiveTable extends Component
{
use WithPagination;
public $sortField = 'name'; // default sorting field
public $sortAsc = true; // default sort direction
public $search = '';
public function sortBy($field)
{
if ($this->sortField === $field) {
$this->sortAsc = !$this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortField = $field;
}
public function render()
{
return view('livewire.live-table', [
'users' => User::search($this->search)
->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')
->simplePaginate(10),
]);
}
}
همانطور که قبلا ذکر شد، ما مقدار متغیر جستجو را از طریق wire:model
به یک فیلد متنی خاص در سمت کلاینت متصل کردهایم. بنابراین هر بار که کاربر چیزی را تایپ می کند، متغیر جستجو نیز به روز می شود. و هنگامی که به روز می شود، کامپوننت نیز دوباره رندر می شود. این به این دلیل است که در تابع ()render
برای fetch داده های کاربر به مقدار متغیر جستجو وابسته هستیم. بنابراین برای هر ضربه کلید، ما در واقع با ارائه کوئری کاربر و مرتب سازی انتخاب شده، داده ها را از دیتابیس fetch می کنیم.
User::search($this->search)
->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')
->simplePaginate(10)
متد ()sortBy
چیزی است که برای به روز رسانی فیلد برای مرتب سازی جدول کاربران استفاده می کنیم. هر فیلد را می توان به ترتیب صعودی یا نزولی مرتب کرد. به طور پیش فرض، با کلیک بر روی یک فیلد مرتب سازی، آن را به صورت صعودی مرتب می کنید. با کلیک مجدد روی آن به سادگی برعکس عمل می شود:
public function sortBy($field)
{
if ($this->sortField === $field) {
$this->sortAsc = !$this->sortAsc; // if field is already sorted, use the opposite instead
} else {
$this->sortAsc = true; // sort selected field by ascending by default
}
$this->sortField = $field;
}
هنگام فیلتر کردن جدول کاربران، از متد ()search
استفاده می کنیم. اما ما هنوز آن را اضافه نکرده ایم. فایل app/Models/User.php
را به روز کنید تا متد ()search
را نیز در بر گیرد. این جدول کاربر را فیلتر می کند تا فقط کاربرانی از نوع کاربر را برگرداند. سپس بقیه شرایط فیلدهایی هستند که می خواهیم برای فیلتر کردن قسمت جستجو استفاده کنیم:
protected $casts = [
//
];
public static function search($query)
{
return empty($query) ? static::query()->where('user_type', 'user')
: static::where('user_type', 'user')
->where(function($q) use ($query) {
$q
->where('name', 'LIKE', '%'. $query . '%')
->orWhere('email', 'LIKE', '%' . $query . '%')
->orWhere('address', 'LIKE ', '%' . $query . '%');
});
}
با استفاده از کامپوننت Livewire
وقتی این کار انجام شد، عملکرد جستجو و مرتبسازی باید خوب باشد. فایل routes/web.php
خود را باز کنید و روت موجود را با موارد زیر جایگزین کنید:
Route::get('/', function () {
return view('index');
});
سپس یک فایل source/views/index.blade.php
ایجاد کنید و موارد زیر را اضافه کنید. اینجاست که از کامپوننت Live Table که ایجاد کردیم استفاده می کنیم. ما میتوانیم آن را به همان روشی که با یک کامپوننت استاندارد انجام میدهید، در صفحه نمایش دهیم. تنها تفاوت این است که ما باید نام کامپوننت را با livewire پیشوند کنیم: و همچنین باید از livewireScripts@
برای رندر فایل جاوا اسکریپت Livewire استفاده کنیم:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ config('app.name') }}</title>
<link rel="stylesheet" type="text/css" href="{{ asset('css/app.css') }}">
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-9">
<livewire:live-table />
</div>
</div>
</div>
@livewireScripts
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
در این مرحله، اکنون می توانید اجرای برنامه را شروع کنید. ساده ترین راه ارائه پروژه با استفاده از Artisan است:
php artisan serve
سپس در مرورگر خود در /http://127.0.0.1:8000
به برنامه دسترسی پیدا کنید.
نتیجه
در این آموزش، اصول اولیه استفاده از Livewire را برای پویاتر کردن برنامه های Laravel خود بدون نوشتن یک سری جاوا اسکریپت برای fetch و ارسال داده ها به سرور آموختید.
به طور خاص، ما یک برنامه ساده CRUD ساختهایم که از Livewire برای رفع نیاز به پکیج های فرانتاند مانند Datatables برای پیادهسازی جستجو و مرتبسازی جدول استفاده میکند.