支持Laravel.io的持续发展 →

Laravel中使用HTMX入门 - 概述

20 Sep, 2023 8 min read

在这篇文章中,我们将了解HTMX的工作原理,并在Laravel中使用HTMX构建一个非常基础的CRUD。

目录

什么是HTMX?

HTMX(HTML扩展)是一个易于使用的JavaScript库,它允许您直接在HTML中构建可反应的用户界面。

它通过引入超能力来扩展熟悉的HTML属性,允许您直接在标记中构建可反应的用户界面。

以下是整体工作流程:

  1. 用户在浏览器中触发事件(如点击或keyup)。
  2. 浏览器把此事件传递给HTMX。
  3. HTMX向服务器发出一个AJAX请求。
  4. 服务器响应HTML。
  5. HTMX使用新HTML更新DOM。
  6. 浏览器将更新后的页面显示给用户。

神奇的HTMX属性

HTMX通过引入一组新属性丰富了标准的HTML。这些属性赋予HTML元素发起HTTP请求、触发事件、指定目标和控制内容交换过程的能力。

一些关键的HTMX属性包括

  1. hx-{get, post, put, delete}:这些属性定义请求的HTTP谓词,允许元素发出GETPOSTPUTDELETE请求。

  2. hx-trigger:此属性定义启动请求的事件,例如基于mouseover或其他自定义交互。通常,HTMX会在按钮的clicks或表单的submissions等事件上自动触发请求。

  3. hx-target:此属性使我们能够指定将响应内容放置的元素。

  4. hx-swaphx-swap属性确定如何替换目标元素的内容。有不同类型的替换策略,如innerHTMLouterHTMLdelete更多

设置 Laravel 玩乐场

在我们可以开始使用 HTMX 之前,我们需要一个可以玩转的 Laravel 应用。

Laravel 是一个构建网页应用的优秀 PHP 框架,让我们用它来启动一个基本的 CRUD 示例。

首先,我们将使用 Laravel 的 artisan 命令创建一个 联系人 模型和控制器。

php artisan make:model Contact --controller --migration

这为我们提供了开始所需的模型、迁移和控制器。接下来,我们在 routes/web.php 中为 ContactController 添加了一个资源路由。

Route::resource('contacts', ContactController::class);

由于 CRUD 应用程序的概念很标准,我不会过多地婆说婆说细节。

现在我们的 Laravel 玩乐场已经设置好了,是时候进入有趣的部分——集成 HTMX 了!

让我们 HTMX 化 Laravel 应用程序

首先,我们需要安装 HTMX 并使其在 Laravel 项目中可用。安装 HTMX 有几个选项,但我们将使用 CDN 方法快速开始。

让我们在布局 app.blade.php 中包含 CDN 链接

<script src="https://unpkg.com/[email protected]"
 crossorigin="anonymous"></script> 

既然我们已经将 HTMX 添加到工具箱中,让我们开始使用它!

搜索联系人类

我们的联系人类表页有一个标准的由服务器渲染的表格。功能齐全,但有点枯燥。让我们使用 HTMX 的客户端魔法来让它变得更有趣。

计划

  • 将搜索输入连接到获取联系人类
  • 仅针对表格体进行刷新
  • 在控制器中检查 HTMX 请求
<x-app-layout>  
  
    <x-slot name="header">  
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">  
                Contacts  
        </h2>  
    </x-slot>  
  
    <div id="content">  
  
        <div class="flex justify-between p-3">  
	       
	       <!-- Removed -->
		   <form action="{{ route('contacts.index')  }}" class="flex gap-2">  
                <x-text-input name="q" 
	                class="px-2 py-1 block" :value="request('q')"/>  
                <x-secondary-button type="submit" class="px-4 py-2">  
                        Search  
                </x-secondary-button>  
           </form>  
           

		   <!-- Added -->
     	   <x-text-input name="q" class="px-2 py-1 block" :value="request('q')" 
  			  placeholder="Search contacts..."  
              hx-get="{{ route('contacts.index') }}"  
              hx-target="#contacts-table-body"  
              hx-trigger="keyup changed delay:500ms, search"/>
             
            <x-primary-link href="{{ route('contacts.create') }}">  
                    Create New Contact  
            </x-primary-link>  

        </div>  
  
        <table id="contacts-table" class="table-auto w-full">  
	    
			<thead>
	           <!-- Table header here. -->
	        </thead>
	        
	        <tbody id="contacts-table-body">
	            @include('contacts.partials.table-body')
            </tbody>
        
        </table>  
  
    </div>  
  
</x-app-layout>

然后在控制器中检查请求类型

class ContactController extends Controller  
{  
    public function index(Request $request)  
    {  
        $searchTerm = $request->input('q');  
  
        $contacts = Contact::where('name', 'LIKE', "%$searchTerm%")->get();  
        
        // Added
        if ($request->header('hx-request')) {  
            return view('contacts.partials.table-body', compact('contacts'));  
        }  
  
        return view('contacts.index', compact('contacts'));  
    }

    ...
    ...
}    
    

所以,仅仅通过几行代码,我们就已经实现了表格的响应式搜索

创建联系人类

让我们通过 HTMX 将创建新联系人类变得既顺滑又响应式。首先,在点击“新建联系人”时,我们将异步加载创建表单。

<x-app-layout>  
 
   <x-slot name="header">  
       <h2 class="font-semibold text-xl text-gray-800 leading-tight">  
           Contacts  
       </h2>  
   </x-slot>  
 
   <!-- Added --> 
   <div id="section">
           {{--   Placeholder for the views   --}}
   </div>

   <div id="content">  
 
       <div class="flex justify-between p-3">  
	        
    	   <x-text-input name="q" class="px-2 py-1 block" 
               :value="request('q')" placeholder="Search contacts..."  
               hx-get="{{ route('contacts.index') }}"  
               hx-target="#contacts-table-body"  
               hx-trigger="keyup changed delay:500ms, search"/>

           <!-- Removed --> 
           <x-primary-link href="{{ route('contacts.create') }}">  
                   Create New Contact  
           </x-primary-link>  

           <!-- Added --> 
           <x-primary-link hx-get="{{ route('contacts.create') }}"
                           hx-target="#section">  
                   Create New Contact  
           </x-primary-link> 

       </div>  
 
       <table id="contacts-table" class="table-auto w-full">  
	        ...
       </table>  
 
   </div>  
 
</x-app-layout>

然后我们将通过使用 hx-post 来提交表单,而无需重新加载。

<div id="partialCreate" class="p-5 border-b-8 border-b-gray-100">
   <form hx-post="{{ route('contacts.store') }}" 
         hx-target="#partialCreate" 
         hx-swap="delete">
       @csrf
       @include('contacts.partials.form')
   </form>
</div>

在成功后,我们希望刷新表格而无需重新加载页面。我们可以通过从服务器发送一个 HX-Trigger 标头来实现这一点,这将作为来自服务器端的发送给客户端以执行某些操作的事件。


class ContactController extends Controller
{
    ...

    public function create()
    {
        return view('contacts.create');
    }

    public function store(ContactRequest $request)
    {
        $contact = Contact::create($request->all());

        return response()->make($contact, 200, ['HX-Trigger' => 'loadContacts']);
    }

    ...
    ...
}

回到 index.blade.php,我们需要更新表格以监听来自服务器发送的 loadContacts 事件。这告诉 HTMX 向我们指定的路由发起请求以获取新的表格数据。我们添加 hx-gethx-trigger 属性

<x-app-layout>  
  
   ... 

   <div id="content">  
   
       ...

       <table id="contacts-table" class="table-auto w-full">  
	    
			<thead>
	           <!-- Table header here. -->
	        </thead>

	        <tbody id="contacts-table-body"
               hx-get="{{ route('contacts.index') }}" 
               hx-trigger="loadContacts from:body">
	            @include('contacts.partials.table-body')
           </tbody>
           
       </table>  
 
   </div>  
 
</x-app-layout>

所以流程是这样的

  • 服务器在创建联系人类时发送 "loadContacts" 事件
  • hx-trigger 检测到事件
  • 发起请求,加载最新的表格数据
  • 替换新数据,而无需重新加载

查看/编辑/删除联系人类

现在我们已经看到了 HTMX 在搜索和创建中的使用,让我们快速实现 CRUD 的其余部分。

table-row.blade.php 中,我们可以添加用于平滑查看、编辑和删除的 HTMX 属性

<tr id="contact-{{ $contact->id }}">
   <td class="px-4 py-2 border">{{ $contact->name }}</td>
   <td class="px-4 py-2 border">{{ $contact->email }}</td>
   <td class="px-4 py-2 border">{{ $contact->phone }}</td>
   <td class="px-4 py-2 border">{{ $contact->address }}</td>
   <td class="px-4 py-2 border"> 
       <a class="mr-1 uppercase hover:underline"
          hx-get="{{ route('contacts.show', $contact->id) }}"
          hx-target="#section">View</a>

       <a class="mr-1 uppercase hover:underline"
          hx-get="{{ route('contacts.edit', $contact->id) }}"
          hx-target="#section">Edit</a>

       <a class="mr-1 uppercase hover:underline"
          hx-delete="{{ route('contacts.destroy', $contact->id) }}"
          hx-confirm="Are you sure you want to delete this contact?"
          hx-headers='{"X-CSRF-TOKEN": "{{ csrf_token() }}"}'>Delete</a>
   </td>
</tr>

edit.blade.php 中,我们使用 HTMX 来异步提交编辑表单

  • hx-put 属性在表单提交时发送 PUT 请求
  • hx-target="#partialEdit" 设置目标以便交换
  • hx-swap="delete" 指定了交换策略。例如,在这里,在接受到服务器响应后,它将 delete 目标 #partialEdit
<div id="partialEdit" class="p-5 border-b-8 border-b-gray-100">
   <form hx-put="{{ route('contacts.update', $contact->id) }}" 
         hx-target="#partialEdit" 
         hx-swap="delete">
       @csrf
       @method('PUT')
       @include('contacts.partials.form')
   </form>
</div>

show.blade.php 中,我们添加 HTMX 来实现无全页刷新的导航

  • hx-get 用于异步获取页面
  • hx-target 用于更新内容区域
  • hx-swap 指定了交换策略。在这里,这意味着我们希望在服务器响应后删除目标 #partialShow
<div id="partialShow" class="p-5 border-b-8 border-b-gray-100">
    <h2 class="text-2xl font-bold">{{ $contact->name }}</h2>
    <p class="text-gray-600">Email: {{ $contact->email }}</p>
    <p class="text-gray-600">Phone: {{ $contact->phone }}</p>
    <p class="text-gray-600">Address: {{ $contact->address }}</p>
    <div class="flex items-center gap-2 mt-4">
        
        <x-primary-button hx-get="{{ route('contacts.edit', $contact->id) }}" 
                          hx-target="#section">Edit</x-primary-button>

        <x-secondary-button hx-get="{{ route('contacts.index') }}" 
                            hx-target="#partialShow" 
                            hx-swap="delete">Go Back</x-secondary-button>
    
    </div>
</div>

在结束之前,我想分享一下我们完整的 ContactController

class ContactController extends Controller
{
   public function index(Request $request)
   {
       $searchTerm = $request->input('q');

       $contacts = Contact::where('name', 'LIKE', "%$searchTerm%")->get();

       if ($request->header('hx-request')) {
           return view('contacts.partials.table-body', compact('contacts'));
       }

       return view('contacts.index', compact('contacts'));
   }

   public function create()
   {
       return view('contacts.create');
   }

   public function store(ContactRequest $request)
   {
       $contact = Contact::create($request->all());

       return response()->make($contact, 200, ['HX-Trigger' => 'loadContacts']);
   }

   public function show(Contact $contact)
   {
       return view('contacts.show', compact('contact'));
   }

   public function edit(Contact $contact)
   {
       return view('contacts.edit', compact('contact'));
   }

   public function update(ContactRequest $request, Contact $contact)
   {
       $contact->update($request->all());

       return response()->make($contact, 200, ['HX-Trigger' => 'loadContacts']);
   }

   public function destroy(Contact $contact)
   {
       $contact->delete();

       return response()->make($contact, 200, ['HX-Trigger' => 'loadContacts']);
   }
}

总结

这就是我们在 Laravel 中使用 HTMX 的介绍!正如我们所见,这只需要几行代码就能实现这种响应式功能。这有多酷啊?

虽然在这里我们介绍了基础知识,但我们可以使用HTMX在高级交换、动画、插件等方面做更多的事情。有关更多详细信息和技术案例,请查看HTMX文档

请关注我的Twitter,以便在我想发布更多内容时得到通知。

上次更新是在10个月前。

driesvints, massimoselvi, mshaf 喜欢了这篇文章

3
喜欢这篇文章?告诉作者并为他们鼓掌!

你可能喜欢以下文章

2024年3月11日

如何使用Larastan让您的Laravel应用程序从0到9

由于Larastan,在您的Laravel应用程序执行之前就可以找出错误...

阅读文章
2024年7月19日

在不使用特性(Traits)的情况下标准化API响应

我发现大多数用于API响应的库都是使用特性实现的...

阅读文章
2024年7月17日

通过Discord通知在您的Laravel项目中收集反馈

如何在Laravel项目中创建反馈模块,并在收到消息时从Discord收到通知...

阅读文章

我们感谢这些令人惊叹的公司 对我们的支持

您的标志在这里?

Laravel.io

解决 Laravel 问题的门户,知识共享和社区建设。

© 2024 Laravel.io - 版权所有。