Laravel6.x博客教程

LaravelPHP Web开发领域算得上是最优秀的框架之一,学习 Laravel 的人其实并不少,今天我想把以往自己学到的技术和经验,但我会以最高效的方式免费分享给正在学习这些技术的新人,帮助他们以最快的速度学习成长!

我决定推出一套Laravel开发系列教程。这套教程将从 0 基础开始,通过多个项目的实战,循序渐进地将现代化的 Web 开发技术分享给大家。帮助新手入门Laravel框架。

Laravel 开发之旅

Laravel is a web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small things.

开发环境说明

本教程写作时开发环境的系统平台为 Windows 7 (64 位),PHP 版本为 7.2.19Laravel 版本为 6.x

请确保你的服务器满足以下要求:

  • PHP >= 7.2.0
  • BCMath PHP 拓展
  • Ctype PHP 拓展
  • JSON PHP 拓展
  • Mbstring PHP 拓展
  • OpenSSL PHP 拓展
  • PDO PHP 拓展
  • Tokenizer PHP 拓展
  • XML PHP 拓展

Laravel集成环境

PHP集成环境有非常多,我就不一一介绍,这里我只推荐一个集成环境 Laragon(http://www.laragon.com.cn)。内置集成 Apache、MySQL、MariaDB、PHP、Nodejs、npm、phpMyAdmin、git、ssh、cmder、Memcached、Redis、composer、Debug、Sublime Text、ngrok、7z等工具!

Mac 环境推荐 Valet

安装 Laragon 非常简单,直接去官网下载然后选择安装目录(比如我放在 D:\laragon),然后一直下一步就OK。

安装 Laravel

我这里只推荐使用 Composer 安装 Laravel 安装器来创建 Laravel 项目,其他的方式我就不啰嗦。

在使用 Composer 之前,我们都知道 Composer 获取安装包的时候资源都在国外,导致很多时候安装失败或者进度缓慢,这里我推荐阿里云 Composer 全量镜像, 官方地址: 戳这里

打开 Laragon 的终端使用全局配置:

所有项目都会使用该镜像地址:

配置好 Composer 镜像之后,我们在 Laragon 的终端获取 Laravel 安装器:

composer global require laravel/installer

确保将 Composer's system-wide vendor 目录放置在你的系统环境变量 $PATH 中(如果你跟我一样是Windows那就不用管啦),以便系统可以找到 Laravel 的可执行文件。该目录根据你的操作系统存在不同的位置中;一些常见的配置包括 :

  • macOS and GNU / Linux 发行版: $HOME/.config/composer/vendor/bin
  • Windows: %USERPROFILE%\AppData\Roaming\Composer\vendor\bin

安装完成后, laravel new 命令会在你指定的目录创建一个全新的 Laravel 项目。例如, laravel new blog 将会创建一个名为 blog 的目录,并已安装好 Laravel 所有的依赖项:

laravel new blog

创建博客的数据库模型

设计博客的数据库表结构

博客最主要的功能就是展示我们写的文章,它需要从某个地方获取博客文章数据才能把文章展示出来,通常来说这个地方就是数据库。我们把写好的文章永久地保存在数据库里,当用户访问我们的博客时,Laravel 就去数据库里把这些数据取出来展现给用户。

博客的文章应该含有标题、正文、作者、发表时间等数据。一个更加现代化的博客文章还希望它有分类、标签、评论等。为了更好地存储这些数据,我们需要合理地组织数据库的表结构。

我们的博客初级版本主要包含博客文章,文章会有分类以及标签。一篇文章只能有一个分类,但可以有很多文章标签。

例如存储博客文章的数据库表长这个样子:

标题 正文 发表时间 分类 标签
1 标题1 正文 2019-10-11 Laravel Laravel教程、PHP
2 标题2 正文 2019-10-12 Vue 博客、vue
3 标题3 正文 2019-10-13 Python 爬虫

这 3 篇文章的分类和标签都是相同的,这会产生很多重复数据,当数据量很大时就浪费了存储空间。

不同的文章可能它们对应的分类或者标签是相同的,所以我们把分类和标签提取出来,做成单独的数据库表,再把文章和分类、标签关联起来。下面分别是分类和标签的数据库表:

分类 id 分类名
1 Laravel
2 Python
标签 id 标签名称
1 Laravel教程
2 Python爬虫

编写博客模型代码

以上是自然语言描述的表格,数据库也和编程语言一样,有它自己的一套规定的语法来生成上述的表结构,这样我们才能把数据存进去。一般来说这时候我们应该先去学习数据库创建表格的语法,再回来写我们的 Laravel 博客代码了。但是 Laravel 告诉我们不用这么麻烦,它已经帮我们做了一些事情。Laravel 把那一套数据库的语法转换成了 PHP 的语法形式,我们只要写 PHP 代码就可以了,Laravel 会把 PHP 代码翻译成对应的数据库操作。

这种操作数据库的行为在 Laravel 中我们称之为 数据库迁移,迁移就像是数据库的版本控制器,让你的团队更容易修改和共享程序的数据库结构。迁移通常配合 Laravel 的结构生成器,能更容易的生成应用程序的数据库结构。

例如我们使用 Artisan 命令来创建文章模型及数据库表:

php artisan make:model Model/Post -m

新创建的模型在 app/Model目录,-m 参数会创建 Post 模型对应的迁移文件,文件放在你的 database/migrations 目录。每个迁移的文件名都包含一个时间戳来让 Laravel 确认迁移的顺序。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id')->default(0)->comment('用户ID');
            $table->integer('category_id')->default(0)->comment('分类ID');
            $table->string('title')->default('')->comment('文章标题');
            $table->string('image')->default('')->comment('文章封面');
            $table->text('body')->comment('文章正文');
            $table->tinyInteger('status')->default(0)->comment('文章状态');
            $table->integer('view')->default(0)->comment('查看文章数');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

这样,Laravel 就可以把 CreatePostsTable 这个类翻译成数据库的操作语言,在数据库里创建一个名为 posts 的表格。可以看出从 Laravel 代码翻译成数据库语言时其规则就是一个迁移类对应一个数据库表格,类的属性对应着表格的列,属性名即列名。

我们需要 3 个表格:文章(Post)、分类(Category)以及标签(Tag),接下来创建分类和标签表格,同时完善数据库字段信息。

php artisan make:model Model/Category -m

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string("name")->default("")->comment("分类");
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}

php artisan make:model Model/Tag -m

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string("name")->default("")->comment("标签名称");
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tags');
    }
}

多对多关联关系

文章(Post)和标签(Tag)数据库表属于多对多关系,所以我们需要建立一张中间表(post_tags):

php artisan make:model Model/PostTag -m

添加字段:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostTagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post_tags', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('post_id')->unsigned()->index()->comment('文章ID');
            $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
            $table->bigInteger('tag_id')->unsigned()->index()->comment('标签ID');
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('post_tags');
    }
}

迁移、操作数据库

我们已经编写了博客数据库模型的代码,但那还只是 Laravel 代码而已,准确的说是 PHP 代码,Laravel 框架还没有把它翻译成数据库语言,因此实际上这些数据库表还没有真正的在数据库中创建。

数据库配置

数据库的配置文件放置在 config/database.php 文件中,你可以在此定义所有的数据库连接,并指定默认使用的连接。此文件内提供了大部分 Laravel 能支持的数据库配置示例。一般情况下我们只需要新建一个 blog 的数据库并修改 .env 文件:

...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog    # 数据库表名称
DB_USERNAME=root    # 数据库用户名
DB_PASSWORD=123     # 数据库密码
...

数据迁移

运行所有未完成的数据迁移使用 Artisan 命令:migrate:

php artisan migrate

打开数据库,就会发现多了一些数据表:

数据填充

我们已经完成数据库的连接和数据表的迁移,为了接下来更直观的展示博客视图首页,需要创建一些模拟数据。Laravel 包含一个填充类可以为你的数据库填充测试数据,所有的填充类都放在 database/seeds 目录下。

创建 factory

创建文章、分类及标签 factory

php artisan make:factory PostFactory
php artisan make:factory CategoryFactory
php artisan make:factory TagFactory

创建的3个factory类放在 database/factories 目录下

分别在三个类中定义 factory

  • PostFactroy
<?php
use App\Model\Post;
use Faker\Generator as Faker;

$factory->define(Post::class, function (Faker $faker) {
    return [
        'title' => $faker->words(rand(3,8), true),
        'body' => $faker->paragraphs(rand(3,8), true),
        'status' => 1,
        'view' => rand(10,100),
    ];
});
  • CategoryFactory
<?php
use App\Model\Category;
use Faker\Generator as Faker;

$factory->define(Category::class, function (Faker $faker) {
    return [
        'name' => $faker->word
    ];
});
  • TagFactory
<?php
use App\Model\Tag;
use Faker\Generator as Faker;

$factory->define(Tag::class, function (Faker $faker) {
    return [
        'name' => $faker->word
    ];
});

使用 factory

定义好了你的工厂文件,然后就可以使用 factory 这个辅助函数来向数据库中插入数据。

例如,创建1个用户及创建4个分类,并且每个分类下创建10篇文章,每篇文章下面创建2-4个标签:

  • database\seeds\DatabaseSeeder.php
<?php
use App\User;
use App\Model\Tag;
use App\Model\Post;
use App\Model\PostTag;
use App\Model\Category;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        // 创建一个用户
        $user = factory(User::class)->create([
            'name' => 'iwanli',
            'password' => bcrypt('123123')
        ]);
        // 创建四个分类
        factory(Category::class,4)->create()->each(function($category) use ($user){
            // 创建10片文章
            factory(Post::class, 10)->create([
                'user_id' => $user->id,
                'category_id' => $category->id,
            ])->each(function($post){
                // 随机创建2-4个标签
                factory(Tag::class, rand(2,4))->create()->each(function($tag) use ($post){
                    // 添加文章和标签的关系
                    PostTag::create([
                        'post_id' => $post->id,
                        'tag_id' => $tag->id,
                    ]);
                });
            });
        });
    }
}

DatabaseSeeder 类中,你可以使用 call 方法来运行其它的 seed 类。使用 call 方法可以将数据填充拆分成多个文件,这样就不会使单个 seeder 变得非常大。本教程涉及到的数据表不多,就没有拆分多个文件。

现在你可以使用 Artisan 命令 db:seed 来填充数据库了。默认情况下, db:seed 命令将运行 DatabaseSeeder 类,这个类可以用来调用其它 Seed 类。不过,你也可以使用 --class 选项来指定一个特定的 seeder 类:

php artisan db:seed

Laravel 接客之道

Web 应用的交互过程其实就是 HTTP 请求与响应的过程。无论是在 PC 端还是移动端,我们通常使用浏览器来上网,Laravel 处理流程大致来说是这样的:

我们按照 Laravel 的规定,就能开发出所需的功能。

创建控制器

php artisan make:controller Web/HomeController

创建一个 HomeController ,文件位于 app/Http/Controllers/Web 目录下。我们在 HomeController 中创建一个 index 方法:

  • app/Http/Controllers/Web/HomeController.php
...
namespace App\Http\Controllers\Web;
...
public function index()
{
    return 'Hello Laravel';
}
...

配置首页路由

所有的 Laravel 路由都在 routes 目录中的路由文件中定义,这些文件都由框架自动加载。routes/web.php 文件用于定义 web 界面的路由。这里面的路由都会被分配给 web 中间件组,它提供了会话状态和 CSRF 保护等功能。定义在 routes/api.php 中的路由都是无状态的,并且被分配了 api 中间件组。

  • routes/api.php
Route::namespace('Web')->group(function($router){
    $router->get('/', 'HomeController@index');
});

上面我们定义一个路由组,加上一个 Web 的命名空间前缀,首页指向的路由控制器是 HomeController 类下的 index 方法。接下来我们在浏览器中访问首页:

如果你不是用的Laragon,请先配置本地域名

绑定视图

从浏览器中访问博客首页,路由会调用 HomeController 类下的 index 方法,我们简单的返回了一个字符串,接下来我们将用到 Laravel 视图返回一个 HTML 页面。

resources/views 下新建一个 web 目录,该目录专门存放前端博客相关代码,在该目录下新建一个 index.blade.php:

<!-- resources/views/web/index.blade.php -->
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Laravel6.x Blog</title>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
    <link href="assets/css/material-kit.min.css" rel="stylesheet" />
</head>

<body class="index-page sidebar-collapse">
    <nav class="navbar navbar-transparent navbar-color-on-scroll fixed-top navbar-expand-lg" color-on-scroll="100"
        id="sectionsNav">
        <div class="container">
            <div class="navbar-translate">
                <a class="navbar-brand" href="/">
                    Laravel6.x Blog </a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" aria-expanded="false"
                    aria-label="Toggle navigation">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="navbar-toggler-icon"></span>
                    <span class="navbar-toggler-icon"></span>
                    <span class="navbar-toggler-icon"></span>
                </button>
            </div>
            <div class="collapse navbar-collapse">
                <ul class="navbar-nav ml-auto">
                    <li class="nav-item">
                        <a class="nav-link" href="/">
                            <i class="fa fa-home"></i> 首页
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="">
                            <i class="fa fa-tags"></i> 标签
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="">
                            <i class="fa fa-wechat"></i> 留言
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="">
                            <i class="fa fa-user-circle-o"></i> 关于我
                        </a>
                    </li>
                    <li class="nav-item">
                        <a href="" class="btn btn-rose btn-raised btn-round ">
                            登录
                            <div class="ripple-container"></div></a>
                    </li>
                    <li class="dropdown nav-item">
                        <a href="#pablo" class="dropdown-toggle nav-link" data-toggle="dropdown">
                            <i class="fa fa-user-circle"></i> iwanli
                            <b class="caret"></b>
                        </a>
                        <div class="dropdown-menu dropdown-menu-right">
                            <h6 class="dropdown-header">常用</h6>
                            <a href="" class="dropdown-item"><i class="fa fa-tasks"> 后台首页</i></a>
                            <a href="/post/create" class="dropdown-item"><i class="fa fa-pencil">
                                    添加文章</i></a>
                            <div class="dropdown-divider"></div>
                            <a href="/system" class="dropdown-item"><i class="fa fa-cogs">
                                    博客设置</i></a>
                            <div class="dropdown-divider"></div>
                            <a href="" class="dropdown-item"><i class="fa fa-tasks" onclick="event.preventDefault();
                                                    document.getElementById('logout-form').submit();"> 退出登录</i></a>
                            <form id="logout-form" action="" method="POST"
                                style="display: none;">
                                <input type="hidden" name="_token" value="j0NNz9PxL2bYCNP9wusu68qwMEndhdQVsEgtEXjd">
                            </form>
                        </div>
                    </li>
                    <li class="nav-item">
                        <a class="btn btn-just-icon btn-link text-danger" rel="tooltip" title="" data-placement="bottom"
                            href="https://github.com/lanceWan" target="_blank"
                            data-original-title="Follow us on github">
                            <i class="fa fa-github"></i>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="page-header header-filter" data-parallax="true"
        style="background-image: url('assets/img/bg.jpg')">
        <div class="container">
            <div class="row">
                <div class="col-md-8 ml-auto mr-auto">
                    <div class="brand text-center">
                        <h1 id="scoll">Laravel 6.x Blog</h1>
                        <h3 class="title text-center">假如我真的变成了鬼,将来,一定也会有,其他鬼杀队的成员,来砍断我的头颅。</h3>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="main main-raised">
        <div class="container">
            <div class="row">
                <div class="col-md-8 ml-auto mr-auto">
                    <h2 class="title text-center">Better for me</h2>
                    <h5 class="description">愿你放下执着,放下不甘心,从今以后,只负责精彩自己的人生。往事不回头,未来不将就,你若盛开,清风自来。</h5>
                </div>
            </div>
            <div class="container">
                <div class="row">
                    <div class="row col-md-9">
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/bg.jpg">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/bg.jpg'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">neque</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden" title="鬼灭之刃">鬼灭之刃</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 33 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 13:20:43</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/default.png">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/default.png'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">鬼魅之刃</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden"
                                            title="奥扎格雷1111">奥扎格雷1111</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 1 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 12:33:21</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/default.png">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/default.png'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">鬼魅之刃</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden"
                                            title="奥扎格雷1111">奥扎格雷1111</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 0 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 12:33:12</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/default.png">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/default.png'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">鬼魅之刃</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden"
                                            title="奥扎格雷1111">奥扎格雷1111</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 0 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 12:32:51</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/default.png">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/default.png'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">architecto</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden" title="奥扎格雷2">奥扎格雷2</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 0 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 12:31:42</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="col-md-6">
                            <div class="card card-blog card-animation">
                                <div class="card-header card-header-image">
                                    <a href="">
                                        <img class="img" style="height:196px"
                                            src="assets/img/default.png">
                                    </a>
                                    <div class="colored-shadow"
                                        style="background-image: url('assets/img/default.png'); opacity: 1;">
                                    </div>
                                </div>
                                <div class="card-body ">
                                    <h6 class="card-category text-danger">
                                        <i class="fa fa-send"> <a href="">architecto</a></i>
                                    </h6>

                                    <h4 class="card-title">
                                        <a href="" class="over-hidden" title="奥扎格雷2">奥扎格雷2</a>
                                    </h4>
                                </div>
                                <div class="card-footer ">
                                    <div class="author">
                                        <i class="fa fa-eye"> 1 ℃</i>
                                    </div>
                                    <div class="stats ml-auto">
                                        <i class="fa fa-clock-o">2019-10-23 12:31:28</i>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-3">
                        <hr>
                        <h4 class="title">交流学习</h4>
                        <ul class="list-unstyled">
                            <li>
                                <b>QQ 群</b> 312621686
                            </li>
                        </ul>
                        <hr>
                        <h4 class="title">最新福利</h4>
                        <p class="description">
                            <a href="https://jq.qq.com/?_wv=1027&amp;k=52vtZrB">
                                <img src="assets/img/default.png"
                                    class="img-raised rounded img-fluid">
                            </a>
                            <a href="https://jq.qq.com/?_wv=1027&amp;k=52vtZrB">点击链接加入群聊【Laravel PHP 技术交流】</a>
                        </p>
                        <hr>
                        <h4 class="title">友情链接</h4>
                        <ul class="list-unstyled">
                            <li>
                                <h4><a href="http://iwanli.me" target="_blank">晚黎</a></h4>
                            </li>
                        </ul>
                        <hr>

                    </div>
                </div>
                <div class="container">
                    <div class="row">
                        <div class="col-md-8 ml-auto mr-auto">
                            <nav>
                                <ul class="pagination">

                                    <li class="page-item disabled" aria-disabled="true" aria-label="&laquo; Previous">
                                        <span class="page-link" aria-hidden="true">&lsaquo;</span>
                                    </li>
                                    <li class="page-item active" aria-current="page"><span class="page-link">1</span>
                                    </li>
                                    <li class="page-item"><a class="page-link"
                                            href="">2</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">3</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">4</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">5</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">6</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">7</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">8</a></li>
                                    <li class="page-item"><a class="page-link"
                                            href="">9</a></li>
                                    <li class="page-item">
                                        <a class="page-link" href="" rel="next"
                                            aria-label="Next &raquo;">&rsaquo;</a>
                                    </li>
                                </ul>
                            </nav>

                        </div>
                    </div>
                </div>
            </div>

        </div>
        <br>
        <br>
    </div>
    <footer class="footer footer-white">
        <div class="container">
            <a class="footer-brand" href="/"> Laravel 6.x Blog</a>
            <div class="copyright pull-center">
                &copy;
                <script>
                    document.write(new Date().getFullYear())
                </script>, made with Laravel 6.x by
                <a href="http://iwanli.me" target="blank" class="text-primary">晚黎</a> for a better web.
            </div>
            <ul class="social-buttons float-right">
                <li>
                    <a href="https://github.com/lanceWan" target="_blank"
                        class="btn btn-just-icon btn-link text-danger">
                        <i class="fa fa-github"></i>
                    </a>
                </li>
            </ul>
        </div>
    </footer>
    <script src="assets/js/jquery.min.js" type="text/javascript"></script>
    <script src="assets/js/popper.min.js" type="text/javascript"></script>
    <script src="assets/js/bootstrap-material-design.min.js" type="text/javascript"></script>
    <script src="assets/js/material-kit.min.js" type="text/javascript"></script>
</body>

</html>

此博客静态页面模板可以加 Laravel技术交流吹水群:312621686

HomeController 中返回这个视图页面:

// app/Http/Controllers/Web/HomeController.php
public function index()
{
    return view('web.index');
}

刷新浏览器页面,发现是一堆杂乱的 HTML 页面,这是因为呈现的首页视图 CSSJS 文件没有加载成功,默认资源文件是放在 public 目录下,我们将博客模板的资源文件复制到 BLOG 项目中:

修改 index.blade.php 中代码如下:

...
<link href="{{asset("assets/web/css/material-kit.min.css")}}" rel="stylesheet" />
...
<script src="{{asset('assets/web/js/jquery.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/popper.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/bootstrap-material-design.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/material-kit.min.js')}}" type="text/javascript"></script>

asset() 函数指向的路径是 public 目录

重新刷新浏览器:

Blade 模板

BladeLaravel 提供的一个简单而又强大的模板引擎。和其他流行的 PHP 模板引擎不同,Blade 并不限制你在视图中使用原生 PHP 代码。所有 Blade 视图文件都将被编译成原生的 PHP 代码并缓存起来,除非它被修改,否则不会重新编译,这就意味着 Blade 基本上不会给你的应用增加任何负担。Blade 视图文件使用 .blade.php 作为文件扩展名,被存放在 resources/views 目录。

定义布局

Blade 的两个主要优点是模板继承和区块。这样能减少很多重复性的模块,例如一个网站的头部导航,底部信息等。

为了储存公共区块,我们在 resources/views/web 新建一个 layouts 目录,在改目录下新建三个文件并将 resources/views/web/index.blade.php 中部分代码修改。

公共底部代码:

<!-- resources/views/web/layouts/footer.blade.php -->
<footer class="footer footer-white">
    <div class="container">
        <a class="footer-brand" href="/"> Laravel 6.x Blog</a>
        <div class="copyright pull-center">
            &copy;
            <script>
                document.write(new Date().getFullYear())
            </script>, made with Laravel 6.x  by
            <a href="http://www.iwanli.me/" target="blank" class="text-primary">晚黎</a> for a better web.
        </div>
        <ul class="social-buttons float-right">
            <li>
                <a href="https://github.com/lanceWan" target="_blank"
                    class="btn btn-just-icon btn-link text-danger">
                    <i class="fa fa-github"></i>
                </a>
            </li>
        </ul>
    </div>
</footer>

公共导航代码:

<!-- resources/views/web/layouts/nav.blade.php -->
<nav class="navbar navbar-transparent navbar-color-on-scroll fixed-top navbar-expand-lg" color-on-scroll="100"
    id="sectionsNav">
    <div class="container">
        <div class="navbar-translate">
            <a class="navbar-brand" href="/">
                Laravel6.x Blog </a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="sr-only">Toggle navigation</span>
                <span class="navbar-toggler-icon"></span>
                <span class="navbar-toggler-icon"></span>
                <span class="navbar-toggler-icon"></span>
            </button>
        </div>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav ml-auto">
                <li class="nav-item">
                    <a class="nav-link" href="/">
                        <i class="fa fa-home"></i> 首页
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="">
                        <i class="fa fa-tags"></i> 标签
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="">
                        <i class="fa fa-wechat"></i> 留言
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="">
                        <i class="fa fa-user-circle-o"></i> 关于我
                    </a>
                </li>
                <li class="nav-item">
                    <a href="" class="btn btn-rose btn-raised btn-round ">
                        登录
                    </a>
                </li>
                <li class="nav-item">
                    <a class="btn btn-just-icon btn-link text-danger" rel="tooltip" title="" data-placement="bottom"
                        href="{{$settings['github'] ?? '/'}}" target="_blank"
                        data-original-title="Follow us on github">
                        <i class="fa fa-github"></i>
                    </a>
                </li>
            </ul>
        </div>
    </div>
</nav>

公共模板:

<!-- resources/views/web/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="en">
<head>
	<title>Laravel6.x Blog</title>
	<meta charset="utf-8">
	<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
	<link href="{{asset("assets/web/css/material-kit.min.css")}}" rel="stylesheet" />
</head>

<body class="index-page sidebar-collapse">
    @include('web.layouts.nav')
	<div class="page-header header-filter" data-parallax="true" style="background-image: url('{{asset('assets/web/img/bg.jpg')}}')">
		<div class="container">
			<div class="row">
				<div class="col-md-8 ml-auto mr-auto">
					<div class="brand text-center">
						<h1 id="scoll">My Laravel6.x Blog</h1>
						<h3 class="title text-center">假如我真的变成了鬼,将来,一定也会有,其他鬼杀队的成员,来砍断我的头颅。</h3>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div class="main main-raised">
		<div class="container">
			@section('sub')
				<div class="row">
					<div class="col-md-8 ml-auto mr-auto">
						<h2 class="title text-center">Better for me</h2>
						<h5 class="description">愿你放下执着,放下不甘心,从今以后,只负责精彩自己的人生。往事不回头,未来不将就,你若盛开,清风自来。</h5>
					</div>
				</div>
			@show
			@yield('content')
		</div>
		<br>
		<br>
    </div>
    @include('web.layouts.footer')
<script src="{{asset('assets/web/js/jquery.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/popper.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/bootstrap-material-design.min.js')}}" type="text/javascript"></script>
<script src="{{asset('assets/web/js/material-kit.min.js')}}" type="text/javascript"></script>
</body>
</html>

扩展首页视图

上面将公共模板布局代码完成后。我们将 resources/views/web/about.blade.php 代码修改如下:

<!-- resources/views/web/index.blade.php -->
@extends('web.layouts.app')

@section('content')
<div class="container">
    ......
</div>
@endsection

代码比较长,大家自行将静态页面代码复制进去

文章显示

前面教程讲填充了伪数据到数据库,现在将这些文章的数据显示在首页。

1. 文章分类关联关系

public function category()
{
    return $this->hasOne(Category::class, 'id', 'category_id');
}

2. 文章数据

改造 app/Http/Controllers/Web/HomeController.phpindex() 方法:

public function index()
{
    // 获取文章按照创建时间倒叙并分页,每页显示6条
    $posts = Post::with('category:id,name')->latest()->paginate(6);
    return view('web.index', compact('posts''));
}

3. 视图渲染数据

打开 resources/views/web/index.blade.php 留下一条文章样式,然后用 blade 命令渲染数据:

...
<div class="row col-md-9">
    @isset($posts)
    @foreach ($posts as $post)
    <div class="col-md-6">
        <div class="card card-blog card-animation">
            <div class="card-header card-header-image">
                <a href="{{url('post', [$post->id])}}">
                    <img class="img" style="height:196px" src="{{asset('assets/web/img/default.png')}}">
                </a>
                <div class="colored-shadow"
                    style="background-image: url('{{asset('assets/web/img/default.png')}}'); opacity: 1;">
                </div>
            </div>
            <div class="card-body ">
                <h6 class="card-category text-danger">
                    <i class="fa fa-send"> <a href="{{ url('category', $post->category->id) }}">{{$post->category->name}}</a></i>
                </h6>

                <h4 class="card-title">
                <a href="{{url('post', [$post->id])}}" class="over-hidden" title="{{$post->title}}">{{$post->title}}</a>
                </h4>
            </div>
            <div class="card-footer ">
                <div class="author">
                <i class="fa fa-eye"> {{$post->view}} ℃</i>
                </div>
                <div class="stats ml-auto">
                    <i class="fa fa-clock-o">{{$post->created_at}}</i>
                </div>
            </div>
        </div>
    </div>
    @endforeach
    @endisset
</div>
...

4. 分页显示

<div class="row">
     ...  
</div>
<div class="container">
    <div class="row">
        <div class="col-md-8 ml-auto mr-auto">
            {{ $posts->fragment('scoll')->links() }}
        </div>
    </div>
</div>

刷新页面就可以看到数据库中的数据被显示出来并分页,我们点击下一页的时候发现头部背景太大,浏览的时候希望直接看到博客文章,加上锚链接就能完美解决这个问题。 fragment('scoll') 其中 scoll 属性是我直接在 <h1 id="scoll">Laravel 6.x Blog</h1> 标签里面定义的 id 属性。大家可以根据自己的喜好去做调整。