定制 hamzi/catchy 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

hamzi/catchy

Composer 安装命令:

composer require hamzi/catchy

包简介

Convert standard Laravel applications into SPAs using Alpine.js and HTML-over-the-wire.

README 文档

README

A featherweight Single Page Application (SPA) adapter for Laravel 11, 12 & 13

Latest Version GitHub Tests Action Status Total Downloads PHP Version License

Laravel Catchy empowers you to convert standard Laravel applications into SPAs using Alpine.js and the @alpinejs/morph plugin.

No complex JavaScript builds. No routing overhead. 100% SEO-friendly. Zero external JavaScript dependencies.

Features

  • Featherweight footprint: Pure Alpine.js plugin and a thin Laravel middleware.
  • HTML-over-the-wire: Only transfers layout fragments over the network, dramatically saving bandwidth.
  • Form submission interception: Intercepts GET and POST forms natively (including CSRF tokens and Laravel _method spoofing).
  • Graceful degradation: Seamlessly falls back to regular page loads on server errors, external redirects, or slow connections.
  • Developer-friendly custom events: Hook into the navigation lifecycle (catchy:start, catchy:morphing, catchy:end, catchy:error) to integrate loading indicators like NProgress.
  • Native browser navigation: Full support for back/forward buttons (History API) and anchor scroll offsets.

Installation

Install the package via Composer (ensure your local repository path is configured or require it directly):

composer require hamzi/catchy

Note: In Laravel 11.x, 12.x, and 13.x, the package's service provider registers automatically.

Configuration

1. Register the Middleware

You need to apply the catchy middleware to the routes you want to behave as an SPA.

For Laravel 11.x/12.x/13.x, register the middleware globally or inside the web middleware group in bootstrap/app.php:

use Hamzi\Catchy\Http\Middleware\CatchySPAMiddleware;

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        CatchySPAMiddleware::class,
    ]);
})

Alternatively, you can apply it only to specific routes/groups using the catchy alias:

Route::middleware('catchy')->group(function () {
    Route::get('/', [HomeController::class, 'index']);
    Route::get('/about', [AboutController::class, 'show']);
});

2. Publish Configuration (Optional)

If you wish to change the default HTML container wrapper ID (catchy-app), publish the config file:

php artisan vendor:publish --tag=catchy-config

This will create config/catchy.php:

return [
    'container_id' => 'catchy-app',
];

Setup & Frontend Integration

Catchy can be loaded dynamically via Blade directives (CDN mode) or bundled locally using modern assets managers like Vite (NPM mode).

Method A: CDN/Blade Directive (Zero Configuration)

If you prefer not to compile assets via NPM, simply add the @catchyScripts Blade directive before the closing </body> tag in your layout. By default, it will automatically inject @alpinejs/morph from UNPKG CDN and initialize the plugin.

Ensure your layout has Alpine.js loaded:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

Method B: NPM/Vite Bundler (Recommended for Production)

If you want to bundle Catchy inside your JavaScript build:

  1. Turn off CDN morph auto-injection in config/catchy.php:
'include_morph' => false,
  1. Install Alpine.js, the morph plugin, and Catchy via NPM:
npm install alpinejs @alpinejs/morph
npm install hamzi-catchy
# (Or npm install ../catchy if using a local path during development)
  1. Import and register the plugins in your resources/js/app.js:
import Alpine from 'alpinejs';
import morph from '@alpinejs/morph';
import Catchy from 'hamzi-catchy';

Alpine.plugin(morph);
Alpine.plugin(Catchy);

window.Alpine = Alpine;
Alpine.start();

Step 2: Prepare Your Layout

Wrap the dynamic page-changing content inside the matching container element (e.g., <main id="catchy-app">) in your parent layout (e.g., layouts/app.blade.php), and add the @catchyScripts directive.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>{{ config('app.name') }}</title>
    
    <!-- Vite Assets -->
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body class="bg-gray-100 text-gray-900">

    <header class="bg-white shadow">
        <nav class="max-w-7xl mx-auto px-4 py-4 flex gap-4">
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/contact">Contact</a>
        </nav>
    </header>

    <!-- The Catchy App Wrapper -->
    <main id="catchy-app">
        @yield('content')
    </main>

    <!-- Inject the Catchy Alpine.js Plugin -->
    @catchyScripts
</body>
</html>

Usage Guide

Once registered, Catchy intercepts all same-origin link clicks and form submissions automatically.

Excluding Specific Links or Forms

To disable Catchy routing for a specific link or form (causing a full page reload instead), add the data-catchy-ignore attribute:

<!-- This link will trigger a standard browser page load -->
<a href="/logout" data-catchy-ignore>Log Out</a>

<!-- This form will post with a standard page reload -->
<form action="/upload" method="POST" enctype="multipart/form-data" data-catchy-ignore>
    ...
</form>

Programmatic Navigation

You can trigger programmatic SPA transitions using the global Alpine helper:

Alpine.catchy.visit('/some-path');

Reusable Blade UI Components

Catchy includes professionally styled, fully customizable Blade components for common UI patterns.

1. Spinner (<x-catchy-spinner />)

An animated SVG spinner for inline loaders or buttons:

<x-catchy-spinner />
<x-catchy-spinner size="sm" color="accent" />

Options: size (xs, sm, md, lg, xl) · color (primary, accent, white, gray)

2. Skeleton Loader (<x-catchy-skeleton />)

<x-catchy-skeleton type="title" />
<x-catchy-skeleton type="text" lines="3" />
<x-catchy-skeleton type="circle" />
<x-catchy-skeleton type="card" />

3. Fade-in Transition (<x-catchy-fade />)

<x-catchy-fade duration="350">
    <div class="card">Content fades in smoothly.</div>
</x-catchy-fade>

4. SPA Form (<x-catchy-form />)

Automates CSRF tokens, method spoofing, and lifecycle callbacks:

<x-catchy-form action="/profile" method="PUT"
    beforesend="loading = true"
    success="loading = false; alert('Saved!')"
    error="loading = false">
    <input type="text" name="name">
    <button type="submit">Save</button>
</x-catchy-form>

5. Modal Dialog (<x-catchy-modal />)

Responsive modal with backdrop blur, scale transitions, and keyboard closing:

<!-- Place once in your layout -->
<x-catchy-modal id="my-modal" size="lg" />

<!-- Trigger via SPA link -->
<a href="/users/1/edit" data-catchy-modal>Edit User</a>

Props: id, title, size (sm5xl, full), closeOnOutsideClick

6. Toast Notifications (<x-catchy-toast />)

Displays session flash messages and dynamic SPA notifications:

<!-- Place once in your layout -->
<x-catchy-toast position="top-right" duration="4000" />

Props: position (top-right, top-left, bottom-right, bottom-left), duration

Laravel session flash messages (success, error, warning, info, status) display automatically. During SPA navigation, flash messages are forwarded via the X-Catchy-Flash response header.

Advanced Features

@catchyForm Blade Directive

Apply lifecycle callbacks to any standard form:

<form action="/submit" method="POST" @catchyForm(['beforesend' => 'onBefore', 'success' => 'onSuccess', 'error' => 'onError'])>
    @csrf
    <!-- fields -->
</form>

Dynamic Container Targeting

Morph a different container instead of the default:

<a href="/sidebar-content" data-catchy-target="sidebar">Load in Sidebar</a>

Disable History Updates

<a href="/live-preview" data-catchy-history="false">Preview</a>

Modal Routing

<a href="/users/create" data-catchy-modal>New User</a>

Forms submitted inside the modal automatically close it and morph the main page container on success.

Form Callback Attributes

<form action="/submit" method="POST"
    data-catchy-beforesend="showLoading()"
    data-catchy-success="hideLoading()"
    data-catchy-error="handleError()">
    @csrf
</form>

Developer Experience (DX) & Custom Events

Event When Cancelable
catchy:start Navigation begins
catchy:morphing About to morph the DOM
catchy:end Navigation completed
catchy:error An error occurred
catchy:flash Flash messages received (on window)

Integrating NProgress

import NProgress from 'nprogress';
document.addEventListener('catchy:start', () => NProgress.start());
document.addEventListener('catchy:end', () => NProgress.done());
document.addEventListener('catchy:error', () => NProgress.done());

Cancel Navigation

document.addEventListener('catchy:start', (event) => {
    if (hasUnsavedChanges && !confirm('Abandon changes?')) {
        event.preventDefault();
    }
});

Publishing & Customization

# Publish config
php artisan vendor:publish --tag=catchy-config

# Publish views (to customize components)
php artisan vendor:publish --tag=catchy-views

License

The MIT License (MIT). Please see License File for more information.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-13

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固