在 2017 年 8 月 10 日,Bootstrap 終於迎來了久違的 4.0.0-beta
版。
相較於 alpha 版本,beta 版少了很多地雷。同時,較 v3.3.x 版本也增進了排版的方便程度與簡化開發的難度。
本篇文章不針對 Bootstrap v4 做多教學,有興趣的可參閱官方檔案或由六角學院翻譯的繁體中文手冊
範例 Repository BS4Starter
範例圖
Step 1. 準備一個乾淨的 Laravel 5.5 環境 0467e66
$ laravel new BS4Starter
或
$ composer create-project laravel/laravel --prefer-dist BS4Starter "5.5.*"
Step 2. 移除所有預設的前端套件 0170d8f
$ php artisan preset none
Step 3. 移除所有 npm packages 並新增所需要的 package 3fb4985
$ yarn remove axios cross-env laravel-mix lodash
$ yarn add axios cross-env laravel-mix lodash jquery popper.js bootstrap@4.0.0-beta
註:這邊移除
axios
、cross-env
、laravel-mix
跟lodash
後又重新安裝的理由有兩個:
- 為了確定安裝的套件為最新版本(若使用
laravel new BS4Starter
指令建立 Laravel Project,其 package 版本可能為舊版)- 在 Laravel 預設中認為,
axios
、cross-env
、laravel-mix
跟lodash
是在開發時期才需要被引入的,而在釋出出版本之前就應該將public/css
與public/js
編譯為 production 模式再釋出,我認為這樣的開發方法不夠妥當(我不認為編譯後的 css 與 js 應該被放入 git 中)註2:除了 jquery 之外,bootstrap v4 需要 popper.js 去達成 dropdown 的功能,所以記得引入。
不要引入 popper,popper 跟 popper.js 是兩個完全不同的專案,除非你有需要,否則不要引入。
Step 4. 修改預設的 js 與 sass e2e0fab
在 resource/assets/js/bootstrap.js
:
// 省略…
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
} catch (e) {}
// 省略…
改為
// 省略…
import 'bootstrap';
// 省略…
在 resources/assets/sass/app.scss
中加入以下內容
// Bootstrap
@import "node_modules/bootstrap/scss/bootstrap.scss";
然後修改 webpack.mix.js
,修改範例如下所示:
let mix = require('laravel-mix');
let webpack = require('webpack');
mix.webpackConfig({
plugins: [new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
})]
});
mix.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
最後安裝套件並編譯
$ yarn install
$ yarn run dev
Step 5. 建立基礎認證樣板(Authentication Template)e599559
$ php artisan make:auth
Step 6. 修改認證樣板 73b1902
這個工程比較浩大一些,不過有一些基本的邏輯可循
- 沒有 panel,用 card 取而代之
- 沒有 offset 系列
以 home.blade.php
為例
- 將所有的
panel
取代為card
(PHPStorm 中用⌘+R
叫出 Replace) - 移除
card-default
- 將
card-heading
重新命名為card-header
- 移除
col-md-offset-2
- 在
<div class="row">
中加入justify-content-md-center
使其成為<div class="row justify-content-md-center">
修改前
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Dashboard</div>
<div class="panel-body">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
@endsection
修改後
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>
<div class="card-body">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
@endsection
對於有表單的內容,如 login.blade.php
、register.blade.php
等
一步步講有點複雜,直接比對一下修改前後吧
修改前
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Login</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('login') }}">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
<label for="email" class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email'))
<span class="help-block">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
<label for="password" class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control" name="password" required>
@if ($errors->has('password'))
<span class="help-block">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-8 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="{{ route('password.request') }}">
Forgot Your Password?
</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
修改後
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Login</div>
<div class="card-body">
<form method="POST" action="{{ route('login') }}">
{{ csrf_field() }}
<div class="form-group">
<label for="email">E-Mail Address</label>
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required autofocus>
@if ($errors->has('email'))
<div class="invalid-feedback">
<strong>{{ $errors->first('email') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<label for="password">Password</label>
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password'))
<div class="invalid-feedback">
<strong>{{ $errors->first('password') }}</strong>
</div>
@endif
</div>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Remember Me
</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">
Login
</button>
<a class="btn btn-link" href="{{ route('password.request') }}">
Forgot Your Password?
</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Step 7. 重寫主模板(resoureces/views/layouts/app.blade.php
) 11cd394
因為 Bootstrap v4 對於 nav 大幅度修改,所以主模板基本上是要全部重寫
這邊直接放上我的版本
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<header class="mb-sm-3">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">{{ config('app.name', 'Laravel') }}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ml-auto">
@if (auth()->guest())
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">Register</a>
</li>
@else
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
Logout
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
{{ csrf_field() }}
</form>
</div>
</li>
@endif
</ul>
</div>
</div>
</nav>
</header>
<main>
@yield('content')
</main>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
至此,基本上是將所有的 Laravel Authentication Template 全部改為 Bootstrap v4。
認真來說,BSv4 的風格較 v3 來得大方許多,而且在預設顏色的表現上也相當具有突顯性。
我認為 BSv4 寫起來更加舒適。