tightenco/ziggy

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

安装次数: 19,758,102

依赖者: 212

建议者: 2

安全: 0

星标: 3,866

关注者: 41

分支: 247

开放问题: 9

语言:JavaScript


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 的默认路由参数值(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 命令,可以生成额外的类型定义,以实现路由名称和参数的自动补全。

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

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 中添加以下内容,以从你的 vendor 目录加载 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() 函数

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

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

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

为了简化导入 route() 函数,你可以在 vendor 路径创建一个别名。

// 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);

如果你使用 TypeScript,你可能在项目的 .d.ts 文件中添加以下声明,以避免在 Vue 组件模板中使用 route() 函数时的类型错误。

declare module 'vue' {
    interface ComponentCustomProperties {
        route: typeof routeFn;
    }
}

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 后端(即没有 Composer 或 vendor 目录)的 JavaScript 项目。你可以使用 npm install ziggy-js 安装此 NPM 包。

为了让此函数在前端可用,你可以运行 php artisan ziggy:generate 并将生成的配置文件添加到你的前端项目中,或者你可以从 Laravel API 的端点返回 Ziggy 的配置作为 JSON(参见下面的 从 API 端点检索 Ziggy 的配置 以了解如何设置此功能)。

过滤路由

Ziggy 支持过滤输出的路由列表,这对于你不想在 HTML 源代码中包含和显示的某些路由来说非常有用。

重要

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

包含/排除路由

要设置路由过滤,在你的 Laravel 应用中创建一个名为 config/ziggy.php 的配置文件,并添加一个包含路由名称模式数组的 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方案而不是https方案的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('ziggy', fn () => response()->json(new Ziggy));

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

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

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