devcu/ziggy

在 JavaScript 中使用 Laravel 的命名路由。

安装: 4

依赖者: 0

建议者: 0

安全: 0

星星: 0

观察者: 0

分支: 247

语言:JavaScript

2.x-dev 2024-03-14 20:13 UTC

This package is auto-updated.

Last update: 2024-09-14 23:54:13 UTC


README

Ziggy - Use your Laravel routes in JavaScript

Ziggy – 在 JavaScript 中使用 Laravel 路由

GitHub Actions Status Latest Version on Packagist Downloads on Packagist Latest Version on NPM Downloads on NPM

Ziggy 提供了一个 JavaScript route() 函数,其工作方式与 Laravel 中的相似,使得在 JavaScript 中使用命名的 Laravel 路由变得非常简单。

安装

使用 Composer 在 Laravel 应用中安装 Ziggy

composer require tightenco/ziggy

@routes Blade 指令添加到您的主布局中(在您的应用程序 JavaScript 之前),然后 route() 辅助函数将全局可用!

默认情况下,@routes Blade 指令的输出包括所有应用程序路由及其参数的列表。此路由列表包含在页面 HTML 中,可以被最终用户查看。要配置哪些路由包含在此列表中,或在不同页面上显示和隐藏不同的路由,请参阅 过滤路由

用法

route() 函数

Ziggy 的 route() 函数的工作方式与 Laravel 的 route() 辅助函数 相似——您可以传递路由的名称和您想要传递给路由的参数,然后它将生成一个 URL。

基本用法

Route::get('posts', fn (Request $request) => /* ... */)->name('posts.index');
route('posts.index'); // 'https://ziggy.test/posts'

参数

Route::get('posts/{post}', fn (Post $post) => /* ... */)->name('posts.show');
route('posts.show', 1);           // 'https://ziggy.test/posts/1'
route('posts.show', [1]);         // 'https://ziggy.test/posts/1'
route('posts.show', { post: 1 }); // 'https://ziggy.test/posts/1'

多个参数

Route::get('venues/{venue}/events/{event}', fn (Venue $venue, Event $event) => /* ... */)
    ->name('venues.events.show');
route('venues.events.show', [1, 2]);                 // 'https://ziggy.test/venues/1/events/2'
route('venues.events.show', { venue: 1, event: 2 }); // 'https://ziggy.test/venues/1/events/2'

查询参数

Ziggy 将不匹配任何命名路由参数的参数添加为查询参数

Route::get('venues/{venue}/events/{event}', fn (Venue $venue, Event $event) => /* ... */)
    ->name('venues.events.show');
route('venues.events.show', {
    venue: 1,
    event: 2,
    page: 5,
    count: 10,
});
// 'https://ziggy.test/venues/1/events/2?page=5&count=10'

如果您需要传递与路由参数同名查询参数,请将其嵌套在特殊的 _query 键下

route('venues.events.show', {
    venue: 1,
    event: 2,
    _query: {
        event: 3,
        page: 5,
    },
});
// 'https://ziggy.test/venues/1/events/2?event=3&page=5'

与 Laravel 一样,Ziggy 会自动将布尔查询参数编码为查询字符串中的整数

route('venues.events.show', {
    venue: 1,
    event: 2,
    _query: {
        draft: false,
        overdue: true,
    },
});
// 'https://ziggy.test/venues/1/events/2?draft=0&overdue=1'

默认参数值

Ziggy 支持默认路由参数值(Laravel 文档)。

Route::get('{locale}/posts/{post}', fn (Post $post) => /* ... */)->name('posts.show');
// app/Http/Middleware/SetLocale.php

URL::defaults(['locale' => $request->user()->locale ?? 'de']);
route('posts.show', 1); // 'https://ziggy.test/de/posts/1'

示例

使用 axios 发送 HTTP 请求

const post = { id: 1, title: 'Ziggy Stardust' };

return axios.get(route('posts.show', post)).then((response) => response.data);

Router

使用无参数调用 Ziggy 的 route() 函数将返回其 JavaScript Router 类的一个实例,该类还具有其他一些有用的属性和方法。

检查当前路由:route().current()

// Laravel route called 'events.index' with URI '/events'
// Current window URL is https://ziggy.test/events

route().current();               // 'events.index'
route().current('events.index'); // true
route().current('events.*');     // true
route().current('events.show');  // false

route().current() 可选地接受参数作为其第二个参数,并将检查这些参数的值是否与当前 URL 中的值匹配

// Laravel route called 'venues.events.show' with URI '/venues/{venue}/events/{event}'
// Current window URL is https://myapp.com/venues/1/events/2?hosts=all

route().current('venues.events.show', { venue: 1 });           // true
route().current('venues.events.show', { venue: 1, event: 2 }); // true
route().current('venues.events.show', { hosts: 'all' });       // true
route().current('venues.events.show', { venue: 6 });           // false

检查是否存在路由:route().has()

// Laravel app has only one named route, 'home'

route().has('home');   // true
route().has('orders'); // false

检索当前路由参数:route().params

// Laravel route called 'venues.events.show' with URI '/venues/{venue}/events/{event}'
// Current window URL is https://myapp.com/venues/1/events/2?hosts=all

route().params; // { venue: '1', event: '2', hosts: 'all' }

注意:使用 route().params 获取的参数值始终以字符串形式返回。

路由模型绑定

Ziggy 支持 Laravel 的 路由模型绑定,甚至可以识别自定义路由键名。如果您将 JavaScript 对象作为路由参数传递给 route(),Ziggy 将使用为该路由注册的路由模型绑定键来在对象内部找到正确的参数值。如果未明确为参数注册路由模型绑定键,Ziggy 将使用对象的 id 键。

// app/Models/Post.php

class Post extends Model
{
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
Route::get('blog/{post}', function (Post $post) {
    return view('posts.show', ['post' => $post]);
})->name('posts.show');
const post = {
    id: 3,
    title: 'Introducing Ziggy v1',
    slug: 'introducing-ziggy-v1',
    date: '2020-10-23T20:59:24.359278Z',
};

// Ziggy knows that this route uses the 'slug' route-model binding key:

route('posts.show', post); // 'https://ziggy.test/blog/introducing-ziggy-v1'

Ziggy 还支持在路由定义中直接声明的范围绑定的 自定义键

Route::get('authors/{author}/photos/{photo:uuid}', fn (Author $author, Photo $photo) => /* ... */)
    ->name('authors.photos.show');
const photo = {
    uuid: '714b19e8-ac5e-4dab-99ba-34dc6fdd24a5',
    filename: 'sunset.jpg',
}

route('authors.photos.show', [{ id: 1, name: 'Ansel' }, photo]);
// 'https://ziggy.test/authors/1/photos/714b19e8-ac5e-4dab-99ba-34dc6fdd24a5'

TypeScript

Ziggy 包含 TypeScript 类型定义,以及一个 Artisan 命令,可以生成额外的类型定义,以启用路由名称和参数的自动补全。

要生成路由类型,运行带有 --types--types-only 选项的 ziggy:generate 命令

php artisan ziggy:generate --types

为了使您的 IDE 能够识别 Ziggy 的 route() 辅助函数是全局可用的,并正确地声明它,请将以下声明添加到项目中的某个 .d.ts 文件中

import { route as routeFn } from 'ziggy-js';

declare global {
    var route: typeof routeFn;
}

如果您尚未安装 Ziggy 的 NPM 包,请在 jsconfig.jsontsconfig.json 中添加以下内容,以从您的供应商目录加载 Ziggy 的类型

{
    "compilerOptions": {
        "paths": {
            "ziggy-js": ["./vendor/tightenco/ziggy"]
        }
    }
}

JavaScript 框架

注意

许多应用程序不需要此处描述的额外设置——@routes Blade 指令使 Ziggy 的 route() 函数和配置全局可用,包括在捆绑的 JavaScript 文件中。

如果您没有使用 @routes Blade 指令,可以直接将 Ziggy 的 route() 函数和配置导入到 JavaScript/TypeScript 文件中。

生成和导入 Ziggy 的配置

Ziggy 提供了一个 Artisan 命令,可以将其配置和路由输出到文件

php artisan ziggy:generate

默认情况下,此命令将配置放在 resources/js/ziggy.js 中,但您可以通过传递 Artisan 命令的参数或设置 ziggy.output.path 配置值来自定义此路径。

ziggy:generate 创建的文件看起来像这样

// resources/js/ziggy.js

const Ziggy = {
    url: 'https://ziggy.test',
    port: null,
    routes: {
        home: {
            uri: '/',
            methods: [ 'GET', 'HEAD'],
            domain: null,
        },
        login: {
            uri: 'login',
            methods: ['GET', 'HEAD'],
            domain: null,
        },
    },
};

export { Ziggy };

导入 route() 函数

您可以将 Ziggy 导入,就像导入任何其他 JavaScript 库一样。如果没有 @routes Blade 指令,Ziggy 的配置不是全局可用的,因此必须手动将其传递给 route() 函数

import { route } from '../../vendor/tightenco/ziggy';
import { Ziggy } from './ziggy.js';

route('home', undefined, undefined, Ziggy);

为了简化导入 route() 函数,您可以在供应商路径上创建一个别名

// vite.config.js

export default defineConfig({
    resolve: {
        alias: {
            'ziggy-js': path.resolve('vendor/tightenco/ziggy'),
        },
    },
});

现在,您的导入可以缩短为

import { route } from 'ziggy-js';

Vue

Ziggy 提供了一个 Vue 插件,以便在您的 Vue 应用程序中轻松使用 route() 辅助函数

import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';
import App from './App.vue';

createApp(App).use(ZiggyVue);

现在您可以在 Vue 组件和模板中的任何地方使用 route() 函数

<a class="nav-link" :href="route('home')">Home</a>

如果您没有使用 @routes Blade 指令,也要导入 Ziggy 的配置并将其传递给 .use()

import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';
import { Ziggy } from './ziggy.js';
import App from './App.vue';

createApp(App).use(ZiggyVue, Ziggy);

React

Ziggy 包括一个 useRoute() 钩子,以便在您的 React 应用程序中轻松使用 route() 辅助函数

import React from 'react';
import { useRoute } from 'ziggy-js';

export default function PostsLink() {
    const route = useRoute();

    return <a href={route('posts.index')}>Posts</a>;
}

如果您没有使用 @routes Blade 指令,也要导入 Ziggy 的配置并将其传递给 useRoute()

import React from 'react';
import { useRoute } from 'ziggy-js';
import { Ziggy } from './ziggy.js';

export default function PostsLink() {
    const route = useRoute(Ziggy);

    return <a href={route('posts.index')}>Posts</a>;
}

您还可以使 Ziggy 配置对象全局可用,这样您就可以在每次调用 useRoute() 时不必传递 Ziggy 的配置

// app.js
import { Ziggy } from './ziggy.js';
globalThis.Ziggy = Ziggy;

单页应用 (SPA) 或独立仓库

Ziggy 的 route() 函数作为 NPM 包提供,可用于管理其 Laravel 后端之外的 JavaScript 项目(即没有 Composer 或 vendor 目录)。您可以使用 npm install ziggy-js 安装 NPM 包。

要使路由可用于前端,以便该函数可以使用,您可以选择运行 php artisan ziggy:generate 并将生成的配置文件添加到您的前端项目中,或者您可以从 Laravel API 的端点返回 Ziggy 的配置作为 JSON(请参阅下面的 从 API 端点检索 Ziggy 的配置 以获取如何设置此的示例)。

过滤路由

Ziggy 支持过滤其输出的路由列表,这在您有一些不希望包含和显示在 HTML 源中的路由时非常有用。

重要

从 Ziggy 的输出中隐藏路由不能替代彻底的身份验证和授权。应该保护不应公开访问的路由,无论它们是否被过滤出 Ziggy 的输出。

包含/排除路由

要设置路由过滤,在 Laravel 应用程序中创建一个位于 config/ziggy.php 的配置文件,并添加包含包含路由名称模式的数组之一的 either onlyexcept 键。

注意:您必须选择其中一个。同时设置 onlyexcept 将完全禁用过滤并返回所有命名路由。

// config/ziggy.php

return [
    'only' => ['home', 'posts.index', 'posts.show'],
];

您可以在路由过滤器中使用星号作为通配符。在下面的示例中,admin.* 将排除名为 admin.loginadmin.register

// config/ziggy.php

return [
    'except' => ['_debugbar.*', 'horizon.*', 'admin.*'],
];

按组过滤

您还可以使用配置文件中的 groups 键来定义您希望在应用程序的不同位置提供的路由组。

// config/ziggy.php

return [
    'groups' => [
        'admin' => ['admin.*', 'users.*'],
        'author' => ['posts.*'],
    ],
];

然后,您可以通过将组名传递给 @routes Blade 指令来公开特定的组。

{{-- authors.blade.php --}}

@routes('author')

要公开多个组,您可以传递一个包含组名的数组。

{{-- admin.blade.php --}}

@routes(['admin', 'author'])

注意:将组名传递给 @routes 指令将始终优先于您的其他 onlyexcept 设置。

其他

TLS/SSL 终止和可信代理

如果您的应用程序正在使用 TLS/SSL 终止 或位于负载均衡器或代理后面,或者如果它托管在提供此类服务的平台上,Ziggy 可能会生成带有 http 方案的 URL,而不是您应用程序 URL 使用的 https。为了解决这个问题,请根据 配置可信代理 的文档设置您的 Laravel 应用程序的可信代理。

使用 @routes 与内容安全策略

内容安全策略 (CSP) 可能会阻止内联脚本,包括 Ziggy 的 @routes Blade 指令输出的脚本。如果您有一个 CSP 并使用 nonce 标记安全内联脚本,您可以将 nonce 传递给 @routes 指令,它将被添加到 Ziggy 的脚本标签中。

@routes(nonce: 'your-nonce-here')

禁用 route() 辅助函数

如果您只想使用 @routes 指令在 JavaScript 中提供 Ziggy 的配置,但不需要 route() 辅助函数,请将 ziggy.skip-route-function 配置设置为 true

从 API 端点检索 Ziggy 的配置

如果您需要通过网络从 Laravel 后端检索 Ziggy 的配置,您可以创建一个类似以下的路由:

// routes/api.php

use Tighten\Ziggy\Ziggy;

Route::get('api/ziggy', fn () => response()->json(new Ziggy));

当应用程序的路由更改时重新生成路由文件

如果您通过运行 php artisan ziggy:generate 将 Ziggy 配置作为文件生成,那么当应用程序的路由文件更改时,您可能需要重新运行该命令。下面的示例是一个 Laravel Mix 插件,但可以通过不使用 Mix 实现类似的功能。非常感谢 Nuno Rodrigues 提供了 想法和示例实现。有关 Vite 示例,请参阅 #655

Laravel Mix 插件示例

const mix = require('laravel-mix');
const { exec } = require('child_process');

mix.extend('ziggy', new class {
    register(config = {}) {
        this.watch = config.watch ?? ['routes/**/*.php'];
        this.path = config.path ?? '';
        this.enabled = config.enabled ?? !Mix.inProduction();
    }

    boot() {
        if (!this.enabled) return;

        const command = () => exec(
            `php artisan ziggy:generate ${this.path}`,
            (error, stdout, stderr) => console.log(stdout)
        );

        command();

        if (Mix.isWatching() && this.watch) {
            ((require('chokidar')).watch(this.watch))
                .on('change', (path) => {
                    console.log(`${path} changed...`);
                    command();
                });
        };
    }
}());

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [])
    .ziggy();

贡献

要开始为 Ziggy 做贡献,请查看 贡献指南

鸣谢

感谢 Caleb PorzioAdam WathanJeffrey Way 在巩固这个想法方面的帮助。

安全

请审查我们的 安全策略,了解如何报告安全漏洞。

许可

Ziggy 是在 MIT 许可下发布的开源软件。有关更多信息,请参阅 LICENSE