Todo List: Xây dựng bố cục chung của ứng dụng với file Layout

875

Bài viết được sự cho phép của tác giả Kien Dang Chung

Video trong bài viết

Ứng dụng Todo List của chúng ta đã có hai trang, một trang danh sách các công việc và một trang chi tiết cho công việc cụ thể. Hai trang này tương ứng với hai view là index.blade.php và show.blade.php nằm trong thư mục resources/views/todos. (Bạn nào chưa có source thì tải về nhé, source của bài trước ở đây). Nếu các bạn để ý trong hai file view này có rất nhiều đoạn code giống nhau, vậy làm thế nào chúng ta mô đun hóa và sử dụng lại các đoạn code chung này?

  Các loại layout trong Android (RelativeLayout, LinearLayout)
  Hướng dẫn sử dụng Framelayout trong android

Tại sao cần xây dựng bố cục ứng dụng chung?

Các website hiện nay thường có rất nhiều trang và có một vài bố cục chung. Ví dụ, như trang All Laravel mà bạn đang xem, ở bất kỳ trang nào chúng ta cũng thấy có 2 phần chung:

  • Header bao gồm logo, menu, phần các bài viết phổ biến.
  • Sidebar: bao gồm công cụ tìm kiếm, các thẻ, bài viết phổ biến.
  • Footer: Thông tin liên hệ, đăng ký nhận tin bài.

Bố cục chung ứng dụng

Bố cục ứng dụng chung có những ưu điểm như sau:

  • Những phần chung này sẽ được mô đun hóa đưa ra một file riêng gọi là file layout (bố cục chung). Các file muốn có bố cục này chỉ cần “kế thừa” lại layout này.
  • Khi cần thay đổi nội dung chung, chúng ta không cần thay đổi tất cả các trang mà chỉ cần thay đổi trong phần bố cục chung. Ví dụ, khi thay đổi Logo mới chẳng hạn, chúng ta chỉ cần vào file layout thay đổi và nó sẽ áp dụng cho tất cả các trang kế thừa bố cục này.

Xây dựng bố cục với Laravel Blade

Laravel Blade cho phép xây dựng file layout và các view sẽ kế thừa lại layout này. Quay lại hai view index và show trong ứng dụng Todo List, chúng ta thấy có rất nhiều phần chung, chúng ta tạo file chứa bố cục này resources/views/layouts/app.blade.php (đặt tên thế nào cũng được miễn là tên diễn giải được ý nghĩa).

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
        <title>
            @yield('title')
        </title>
    </head>
    <body>
        <div class="container">
            @yield('content')
        </div>
    </body>
</html>

Trong file này chúng ta thấy có một số code trông khá lạ như sau:

  • yield(‘title’)
  • yield(‘content’)

Diễn giải code, chúng ta thấy có tiêu đề các trang khác nhau (phần title) và phần nội dung trang (phần content) khác nhau do vậy, yield(‘title’) và yield(‘content’) chính là nơi hiển thị các phần khác nhau đó.

Mẹo: Tất cả các phần có nội dung thay đổi được đưa vào một phần riêng với lệnh yield(‘ten_vung_chung’).

Khi đó ở các trang (view) cần “kế thừa” bố cục này, chúng ta sẽ sử dụng câu lệnh extends. Cấu trúc lại code resources/views/todos/index.blade.php:

@extends('layouts.app')

@section('title')
    Todos List
@endsection

@section('content')
    <h1 class="text-center my-5">TODOS PAGE</h1>
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card card-default">
                <div class="card-header">
                    Todos
                </div>

                <div class="card-body">
                    <ul class="list-group">
                        @foreach($todos as $todo)
                            <li class="list-group-item">
                                {{ $todo->name }}

                                <a href="/todos/{{ $todo->id }}" class="btn btn-primary btn-sm float-right mr-2">View</a>
                            </li>
                        @endforeach
                    </ul>
                </div>
            </div>
        </div>
    </div>
@endsection

Và với resources/views/todos/show.blade.php:

@extends('layouts.app')

@section('title')
    Single Todo: {{ $todo->name }}
@endsection

@section('content')
    <h1 class="text-center my-5">
        {{ $todo->name }}
    </h1>

    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card card-default">
                <div class="card-header">
                    Details
                </div>

                <div class="card-body">
                    {{ $todo->description }}
                </div>
            </div>
        </div>
    </div>
@endsection

Trong hai view này, để kế thừa bố cục chung ứng dụng chúng ta dùng câu lệnh extends(‘ten_bo_cuc’), chú ý là một ứng dụng có thể có nhiều bố cục chung khác nhau. Tên bố cục chứa cả đường dẫn đến file bố cục và phân cách bởi dấu chấm, ví dụ ở đây là layouts.app tức là file app.blade.php trong thư mục layouts với thư mục mặc định là resources/views.

Tiếp đến, các phần nội dung khác nhau được định nghĩa bằng câu lệnh yield ở trong layout sẽ được sử dụng trong view và nằm giữa @section(ten_vung_dinh_nghia_trong_yield) và @endsection.

Quay lại ứng dụng và kiểm tra các trang, bạn sẽ thấy ứng dụng khi thay đổi này không khác gì so với ứng dụng của bài học trước (bài số 9). Tại sao phải thực hiện những công việc ở trên?

Trở lại với câu hỏi ở phần trước, tại sao chúng ta lại đưa toàn bộ phần code chung ra file layouts/app.blade.php? Ứng dụng hoạt động trên các trang index và show đã rất ok, tuy nhiên chúng ta cần một menu chung cho toàn bộ ứng dụng để có thể chuyển hướng nhanh chóng đến một trang nào đó. Nếu như chưa có layouts/app.blade.php chúng ta sẽ phải đến từng trang (view) cụ thể và thêm menu vào, thật là mất nhiều công sức, chưa kể là mỗi khi cần thay đổi, chúng ta lại mất nhiều công sức hơn nữa và rất dễ bỏ sót những vị trí cần thay đổi.

Công việc dễ dàng hơn nhiều với file bố cục chung, chúng ta chỉ việc thêm menu vào file layouts/app.blade.php và các view kế thừa lại bố cục này sẽ tự động có thanh menu. Nội dung layouts/app.blade.php sẽ thay đổi như sau:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
        <title>
            @yield('title')
        </title>
    </head>
    <body>
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="/">Todos App</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 mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="/todos">todos <span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item active">
                        <a class="nav-link" href="/new-todos">Create todos <span class="sr-only">(current)</span></a>
                    </li>
                </ul>
            </div>
        </nav>
        <div class="container">
        @yield('content')
        </div>
    </body>
</html>

Không cần thay đổi gì hai index và show trong thư mục view resources/views/todos nhưng khi chạy ứng dụng bạn thấy đấy chúng ta đã có menu cho cả hai view này.

Thêm menu vào bố cục ứng dụng

Bài viết gốc được đăng tải tại allaravel.com

Có thể bạn quan tâm:

Xem thêm Việc làm IT hấp dẫn trên TopDev