返回

Laravel Fortify Inertia Vue 注册页传递数据

vue.js

为 Laravel Fortify 注册视图传递属性给 Inertia Vue 页面

在使用 Laravel、Fortify、Inertia 和 Vue 构建应用程序时,经常遇到需要在注册页面中显示一些动态数据,比如从数据库获取的配置信息。然而,Fortify 默认提供的注册视图并没有直接的方法让我们传递额外的属性。 这就引出了如何在现有架构下有效解决该问题的思考。

问题剖析

Fortify 服务提供者预配置了注册路由和视图,但未预留传递额外属性的接口。这意味着你无法直接通过标准的 Laravel 控制器向 Inertia Vue 组件传递属性。 问题核心是 Fortify 负责注册页面逻辑, 而默认配置只渲染基础的 Inertia 注册组件, 缺少注入属性的机制。 这就需要我们考虑几种不同的解决方案。

解决方案

下面列出了几种常见处理方案及其各自的优势和劣势。

方案一:修改 Fortify 注册视图

可以创建一个自定义的服务提供者,重写 Fortify::registerView

  • 原理 :利用 Laravel 服务提供者,在框架启动时覆盖 Fortify 默认的注册视图。通过 Inertia::render 函数, 传入额外的属性数据。
  • 优点 :控制力强, 可以在 Inertia 组件渲染之前注入属性数据。
  • 缺点 :需要手动维护代码, 一定程度上破坏了框架的默认设置, 可能导致升级时需要特殊处理。

操作步骤:

  1. 创建一个新的服务提供者(比如:app/Providers/AppServiceProvider.php 或其他你习惯的命名空间), 可以使用以下命令:

    php artisan make:provider ExtendedFortifyServiceProvider
    
  2. 在新服务提供者的 register 方法中, 使用以下代码注册自定义注册视图:

    <?php
    
    namespace App\Providers;
    
    use Illuminate\Support\ServiceProvider;
    use Inertia\Inertia;
    use Laravel\Fortify\Fortify;
    
    class ExtendedFortifyServiceProvider extends ServiceProvider
    {
    	/**
         * Register any application services.
         */
        public function register(): void
        {
            //
        }
    
        /**
         * Bootstrap any application services.
         */
        public function boot(): void
        {
            Fortify::registerView(function () {
                return Inertia::render('Auth/Register', [
                  'some_data' => 'Example Property' , //  在此处添加额外属性
                ]);
             });
        }
    }
  1. 不要忘了将新创建的服务提供者添加到 config/app.php 中的 providers 数组里,
    添加在你 app/Providers/FortifyServiceProvider的后面。

    'providers' => [
        ...
    	App\Providers\FortifyServiceProvider::class,
        App\Providers\ExtendedFortifyServiceProvider::class,
        ...
    ],
    

通过以上步骤,注册页面会被新提供的服务所替换, 在渲染 Inertia 页面时, some_data 属性可以被注入并传递给 Vue 组件。

方案二:在 Vue 组件中发送额外请求

此方案保留后端原有的配置, 在前端页面组件加载后向后端请求额外的数据。

  • 原理 : Fortify 返回原生的 Register Vue 组件, 在组件内部,使用 axiosfetch 等工具发送一个请求,获取数据并在页面渲染时显示。
  • 优点 : 与 Fortify 默认行为兼容性强, 前后端职责分明,升级 Fortify 时不容易受到影响。
  • 缺点 : 多一次数据请求,可能增加页面加载时间。并且需要处理 loading 状态和潜在的请求错误。

操作步骤:

  1. 创建一个 API 路由和控制器来提供所需的数据。比如:routes/api.php中增加:

     Route::get('/register/data', [App\Http\Controllers\RegisterController::class, 'getData']);
    
  2. 创建控制器并处理请求:app/Http/Controllers/RegisterController.php:

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\JsonResponse;
    
    class RegisterController extends Controller
    {
         public function getData(): JsonResponse
    	{
         	//在这里添加你的业务逻辑
        	return response()->json([
    		    'config_value' => 'This is from Database' ,
    		]);
    	}
    }
    
  3. 在 Vue 组件(resources/js/Pages/Auth/Register.vue)中添加获取数据的代码。可以使用 axios, 代码大致如下:

     <template>
     	...
       <p>{{ someData }}</p>
     	...
     </template>
    
     <script setup>
     import { ref, onMounted } from 'vue'
     import axios from 'axios'
    
      const someData = ref(null)
    
     	onMounted(async() => {
       try {
         const response = await axios.get('/api/register/data')
           someData.value = response.data.config_value;
         }
         catch (error){
           console.error(error);
         }
       });
     </script>
    

组件加载后, 会发送 GET 请求到 /api/register/data 接口,并更新页面 someData的值。

方案三:使用 shared props

此方法利用 Inertia 的 shared 属性来全局共享数据。

  • 原理: 通过 HandleInertiaRequests 中共享 props 来传递一些页面通用信息, 这种方式可以在页面第一次渲染时同步加载配置信息,同时兼顾了性能与复用。
  • 优点 : 无需修改 Fortify 配置, 全局可访问, 提升页面加载速度,减少重复数据请求。
  • 缺点 : 数据作用域扩大, 不适合传递特定页面才会使用的信息,可能会污染全局空间。

操作步骤:

  1. app/Http/Middleware/HandleInertiaRequests.php 中配置 share 方法, 注入全局配置数据。

    <?php
    
    namespace App\Http\Middleware;
    
    use Illuminate\Http\Request;
    use Inertia\Middleware;
    
    class HandleInertiaRequests extends Middleware
    {
    
        public function share(Request $request): array
        {
             return array_merge(parent::share($request), [
                'my_global_config' =>  'My Config Data From middleware',
           ]);
         }
    }
    
  2. 在 Vue 组件中直接访问此属性:

      <template>
          ...
         <p>{{ $page.props.my_global_config }}</p>
         ...
      </template>
    
    <script setup>
    //无需要任何特别的处理代码。
    </script>
    

 由于该属性在 middleware 被共享了, Vue 组件可以直接使用 `$page.props.my_global_config` 来访问该属性。

### 安全提示

当传递数据库信息或其他敏感数据时,请确保采取合适的安全措施,例如使用授权和验证规则,并在服务端对数据进行适当的处理。 避免将机密数据直接暴露在客户端代码中。

### 结论

根据应用程序的特定需求和架构选择合适的方法。 权衡各种方案的优势和劣势。对于只需要传递少量信息,可以考虑修改视图或使用全局共享属性。 如果涉及复杂的数据和处理逻辑,或数据仅特定于一个组件使用时, 发送单独请求会是一个较好的选择。  没有一种解决方案可以适用于所有场景,理解这些方法并灵活应用至关重要。