视图
简介
直接从路由和控制器里返回整段 HTML 字符串显然不现实。视图就解决了这个问题——把所有 HTML 放在单独的文件里,干干净净。
视图把控制器/应用逻辑和展示逻辑分开,放在 resources/views 目录下。Laravel 的视图模板通常用 Blade 模板引擎来写。一个简单的视图长这样:
<!-- 视图存放在 resources/views/greeting.blade.php -->
<html>
<body>
<h1>Hello, {{ $name }}</h1>
</body>
</html>
因为这个视图存放在 resources/views/greeting.blade.php,你可以用全局 view() 辅助函数返回它:
Route::get('/', function () {
return view('greeting', ['name' => 'James']);
});
信息
想了解更多 Blade 模板的写法?看看完整的 Blade 文档入门。
用 React / Svelte / Vue 写视图
很多开发者不再用 PHP 通过 Blade 写前端模板,而是更喜欢用 React、Svelte 或 Vue。Laravel 通过 Inertia 让这一切变得很轻松——Inertia 是一个库,能把你的 React / Svelte / Vue 前端和 Laravel 后端绑在一起,不用经历构建 SPA 的那些复杂操作。
我们的 React、Svelte 和 Vue 应用起步套件给你提供了一个很好的起点,基于 Inertia 搭建你的下一个 Laravel 应用。
创建和渲染视图
在 resources/views 目录下放一个 .blade.php 扩展名的文件,或者用 make:view Artisan 命令,就能创建一个视图:
php artisan make:view greeting
.blade.php 扩展名告诉框架这个文件包含 Blade 模板。Blade 模板里既有 HTML,也有 Blade 指令——可以轻松输出值、写 if 语句、遍历数据等等。
创建好视图之后,你可以用全局 view() 辅助函数从路由或控制器返回它:
Route::get('/', function () {
return view('greeting', ['name' => 'James']);
});
也可以用 View 门面返回:
use Illuminate\Support\Facades\View;
return View::make('greeting', ['name' => 'James']);
如你所见,view() 辅助函数的第一个参数对应 resources/views 目录下的视图文件名。第二个参数是要传给视图的数据数组。这里我们传了 name 变量,在视图里用 Blade 语法显示。
嵌套视图目录
视图也可以放在 resources/views 目录的子目录里。引用嵌套视图时用点号(.)分隔。比如你的视图存放在 resources/views/admin/profile.blade.php,你可以这样返回它:
return view('admin.profile', $data);
注意
视图目录名不要包含 . 字符。
创建第一个存在的视图
用 View 门面的 first() 方法,你可以在一组视图里返回第一个存在的那个。这在你的应用或包允许视图被自定义或覆盖时很有用:
use Illuminate\Support\Facades\View;
return View::first(['custom.admin', 'admin'], $data);
判断视图是否存在
用 View 门面的 exists() 方法可以判断视图是否存在,返回 true 表示存在:
use Illuminate\Support\Facades\View;
if (View::exists('admin.profile')) {
// ...
}
往视图传数据
前面例子已经展示了,你可以传一个数据数组给视图,让数据在视图里可用:
return view('greetings', ['name' => 'Victoria']);
用这种方式传数据时,数据应该是一个键值对数组。提供数据后,你可以在视图里用对应的键来访问值,比如 <?php echo $name; ?>。
除了传整个数组给 view() 辅助函数,你也可以用 with() 方法逐个添加数据。with() 方法返回视图对象实例,所以你可以继续链式调用:
return view('greeting')
->with('name', 'Victoria')
->with('occupation', 'Astronaut');
给所有视图共享数据
有时候你可能需要给应用渲染的所有视图共享同一份数据。用 View 门面的 share() 方法就行。通常你应该在服务提供者的 boot() 方法里调用 share()。你可以放在 App\Providers\AppServiceProvider 里,也可以单独生成一个服务提供者来放:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* 注册应用服务。
*/
public function register(): void
{
// ...
}
/**
* 启动应用服务。
*/
public function boot(): void
{
View::share('key', 'value');
}
}
视图 Composer
视图 Composer 是视图渲染时执行的回调或类方法。如果你有一份数据需要在每次渲染某个视图时都绑定上去,视图 Composer 可以帮你把这些逻辑集中到一个地方。当同一个视图被多个路由或控制器返回、而且总是需要某份数据时,视图 Composer 特别有用。
通常视图 Composer 会在应用的某个服务提供者里注册。下面的例子假设放在 App\Providers\AppServiceProvider 里。
我们用 View 门面的 composer() 方法注册视图 Composer。Laravel 没有为基于类的视图 Composer 提供默认目录,你可以按自己喜欢的方式组织。比如可以建一个 app/View/Composers 目录来放所有的视图 Composer:
<?php
namespace App\Providers;
use App\View\Composers\ProfileComposer;
use Illuminate\Support\Facades;
use Illuminate\Support\ServiceProvider;
use Illuminate\View\View;
class AppServiceProvider extends ServiceProvider
{
/**
* 注册应用服务。
*/
public function register(): void
{
// ...
}
/**
* 启动应用服务。
*/
public function boot(): void
{
// 基于类的 Composer...
Facades\View::composer('profile', ProfileComposer::class);
// 基于闭包的 Composer...
Facades\View::composer('welcome', function (View $view) {
// ...
});
Facades\View::composer('dashboard', function (View $view) {
// ...
});
}
}
注册好 Composer 之后,每次渲染 profile 视图时,App\View\Composers\ProfileComposer 类的 compose() 方法就会被执行。来看看这个 Composer 类的例子:
<?php
namespace App\View\Composers;
use App\Repositories\UserRepository;
use Illuminate\View\View;
class ProfileComposer
{
/**
* 创建一个新的 Profile Composer。
*/
public function __construct(
protected UserRepository $users,
) {}
/**
* 绑定数据到视图。
*/
public function compose(View $view): void
{
$view->with('count', $this->users->count());
}
}
可以看到,所有视图 Composer 都通过服务容器解析,所以你可以在 Composer 的构造函数里类型提示需要的依赖。
给多个视图附加 Composer
你可以一次给多个视图附加同一个 Composer,把视图名数组作为第一个参数传给 composer() 方法:
use App\Views\Composers\MultiComposer;
use Illuminate\Support\Facades\View;
View::composer(
['profile', 'dashboard'],
MultiComposer::class
);
composer() 方法还接受 * 通配符,可以把 Composer 附加到所有视图:
use Illuminate\Support\Facades;
use Illuminate\View\View;
Facades\View::composer('*', function (View $view) {
// ...
});
视图 Creator
视图 "Creator" 和视图 Composer 很像,区别在于执行时机:Creator 在视图实例化之后立即执行,不用等到视图即将渲染。注册视图 Creator 用 creator() 方法:
use App\View\Creators\ProfileCreator;
use Illuminate\Support\Facades\View;
View::creator('profile', ProfileCreator::class);
优化视图
默认情况下,Blade 模板视图是按需编译的。当执行渲染视图的请求时,Laravel 会先判断编译后的视图是否存在。如果存在,再判断未编译的视图是否比编译后的更新。如果编译后的视图不存在,或者未编译的视图被修改过,Laravel 就重新编译。
在请求过程中编译视图可能对性能有一点负面影响,所以 Laravel 提供了 view:cache Artisan 命令来预编译应用用到的所有视图。为了提升性能,你可以在部署流程中加上这一步:
php artisan view:cache
用 view:clear 命令可以清除视图缓存:
php artisan view:clear