Laravel 视图共用组件共享变量
视图
定义方式:return view('以.分隔的视图模板路径');
视图是 MVC 模式中的 View 部分,大部分视图都应该是 HTML 格式文本,在 Laravel 中,支持三种格式的视图文件解析:CSS 文件,原生 PHP 和 Blade 模板。原生 PHP 文件后缀是 .php,通过 PHP 引擎解析,Blade 模板文件后缀是 .blade.php,通过 Blade 引擎解析(底层实现逻辑可参考 vendor/laravel/framework/src/Illuminate/View/ViewServiceProvider.php 中的 registerEngineResolver 方法)。
视图返回与参数传递
Laravel 提供了多个语法糖在路由中返回视图,如辅助函数 view 或 View::make 方法,还可以注入 IlluminateViewView Factory 类(最底层实现),通常我们使用辅助函数 view,因为最简洁。
如果要传递数据给视图,可以这么做(多个数据以数组方式传递),这样就可以将 tasks 数据变量传递到视图以便在视图中进行引用:return view('home')->with('tasks', Task::all());
还可以这么做:return view('home', ['tasks' => Task::all()]);
在视图间共享变量
有时候在不同视图间传递同一个数据变量很麻烦,是否可以做到一次定义,多处使用呢?答案是可以,通过视图对象提供的 share 方法即可实现,我们可以在某个服务提供者如 AppServiceProvider 的 boot 方法中定义共享的视图变量:
view()->share('siteName', 'Laravel学院');
view()->share('siteUrl', 'https://xueyuanjun.com');
然后就可以在各个视图中使用 $siteName 和 $siteUrl 这两个变量了(其它变量定义方式类似),而无需每次传递这个数据变量,比如我们在不修改路由定义的前提下修改上述 resources/views/page/show.blade.php 文件。
下面介绍很重要的一种方式 预设视图组件数据变量
我们的视图有很多公共部分,比如导航菜单、侧边栏、底部信息等,通常我们会以单独的视图组件来处理这些元素区块,但是如何从后端传递这些组件需要的数据变量是个问题,因为这些组件在多个页面中共用,从后端角度来看,会涉及到多个路由/控制器方法。在 Laravel 中,我们可以通过 View Composer 功能来实现上述需求,我们可以在后端通过 View Composer 将数据绑定到指定视图,从而避免在路由定义或控制器方法中重复获取以及显式传递这些视图组件所需的数据。
通常这个工作需要在某个服务提供者的 boot 方法中进行,现在我们将其定义到 app/Providers/AppServiceProvider.php 的 boot 方法:view()->share('posts', Post::recent());
如果不指定视图组件的话,上述代码的含义是在所有视图中共享 posts 变量(该用法在视图入门教程中已经提及),这当然是有点浪费了,不推荐这么做,我们通常会以闭包方式通过 View Composer 指定视图作用域来预设共享「变量」:
view()->composer('home.layouts.subnav', function ($view) {
$view->with('posts', Post::recent());
});
<?php
# Model
namespace AppModelsIndex;
use AppModelsBlogArticle;
use AppModelsBlogCategory;
use AppModelsBlogTag;
use IlluminateDatabaseEloquentModel;
use IlluminateSupportFacadesDB;
class Post extends Model
{
//导航数据预设
public static function recent(){
$categoryData = Category::select(['id','cate_name'])
->where('head_recommend', 1)
->limit(5)
->get();
return ['headNav' => $categoryData];
}
}
这样,我们就可以在 resources/views/partials/sidebar.blade.php 中使用 posts 变量,而不必在定义路由或实现控制器方法的时候显式传递它了。 你甚至还可以通过数组/通配符的方式指定多个视图作用域:
// 通过通配符指定多个视图组件
view()->composer('partials.*', function ($view) {
$view->with('posts', Post::recent());
});
通过自定义类实现更加灵活的数据预设
除了常见的闭包方式外,你还可以通过自定义类的方式为 View Composer 实现更加灵活的数据预设。
首先,我们在 app/Http/ViewComposers 目录下创建一个自定义 View Composer 类 RecentPostsComposer.php:
<?php
namespace AppHttpViewComposers;
use AppPost;
use IlluminateContractsViewView;
class RecentPostsComposer
{
private $posts;
public function __construct(Post $posts) {
$this->posts = $posts;
}
public function compose(View $view) {
$view->with('posts', $this->posts->recent());
}
}
我们在 RecentPostsComposer 类的构造函数中注入了一个 Post 模型类,该模型类会在实例化的时候自动注入,然后我们将变量预设逻辑定义在 compose 方法中。这样,当我们在 View Composer 中调用 RecentPostsComposer 类的时候,compose 方法会被自动调用从而完成变量预设:
view()->composer( 'partials.sidebar', AppHttpViewComposersRecentPostsComposer::class );