0
0
Lập trình
Hưng Nguyễn Xuân 1
Hưng Nguyễn Xuân 1xuanhungptithcm

Sử Dụng GoRouter cho Ứng Dụng Web Flutter Thân Thiện URL

Đăng vào 7 tháng trước

• 9 phút đọc

Tại Sao Chọn GoRouter cho Ứng Dụng Web Flutter?

GoRouter, được phát triển bởi đội ngũ Flutter, được thiết kế để xử lý điều hướng theo cách dựa trên URL, điều này khiến nó trở nên lý tưởng cho các ứng dụng web. Dưới đây là lý do tại sao GoRouter lại nổi bật trong phát triển web Flutter:

  • Điều Hướng Dựa Trên URL: GoRouter hỗ trợ các URL sạch (ví dụ: /about, /product/123), phù hợp với cách người dùng mong đợi điều hướng trên web.
  • Tích Hợp Trình Duyệt: Nó xử lý các nút quay lại/tiến tới của trình duyệt và thay đổi URL một cách liền mạch.
  • Liên Kết Sâu: Người dùng có thể chia sẻ hoặc đánh dấu các trang cụ thể (ví dụ: /product/42) và đến trực tiếp trang đó.
  • Định Tuyến Tuyên Bố: Định nghĩa các tuyến đường một cách đơn giản, dễ mở rộng, giảm thiểu độ phức tạp trong điều hướng.

Trong hướng dẫn này, chúng ta sẽ xây dựng một ứng dụng web Flutter đơn giản với GoRouter, bao gồm một trang Chính, một trang Giới thiệu và một trang Sản phẩm với URL động. Chúng ta sẽ đảm bảo ứng dụng hỗ trợ điều hướng trình duyệt và liên kết sâu, trong khi giữ mã nguồn dễ tiếp cận cho người mới bắt đầu.

Thiết Lập Dự Án

Hãy cùng tạo một ứng dụng web Flutter với GoRouter từng bước.

Bước 1: Tạo Dự Án Flutter Mới

Nếu bạn chưa có dự án Flutter, hãy tạo một dự án mới bằng cách chạy:

Copy
flutter create go_router_web_app
cd go_router_web_app

Đảm bảo SDK Flutter của bạn được thiết lập cho phát triển web. Kiểm tra bằng cách:

Copy
flutter run -d chrome

Bước 2: Thêm Thư Viện GoRouter

Thêm gói go_router vào dự án của bạn. Mở pubspec.yaml và bao gồm:

Copy
dependencies:
  go_router: ^16.2.1

Chạy flutter pub get để cài đặt. (Kiểm tra pub.dev để biết phiên bản mới nhất.)

Bước 3: Tạo Các Màn Hình Ứng Dụng

Chúng ta sẽ tạo ba màn hình đơn giản: HomeScreen, AboutScreen, và ProductScreen. Tạo một thư mục lib/screens và thêm các tệp sau đây.

lib/screens/home_screen.dart:

Copy
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Trang Chính')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Chào mừng đến với Trang Chính!'),
            ElevatedButton(
              onPressed: () => context.go('/about'),
              child: const Text('Đi đến Giới thiệu'),
            ),
            ElevatedButton(
              onPressed: () => context.go('/product/123'),
              child: const Text('Xem Sản phẩm #123'),
            ),
          ],
        ),
      ),
    );
  }
}

lib/screens/about_screen.dart:

Copy
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class AboutScreen extends StatelessWidget {
  const AboutScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Giới thiệu')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Giới thiệu về Ứng dụng của Chúng tôi'),
            ElevatedButton(
              onPressed: () => context.go('/'),
              child: const Text('Quay lại Trang Chính'),
            ),
          ],
        ),
      ),
    );
  }
}

lib/screens/product_screen.dart:

Copy
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class ProductScreen extends StatelessWidget {
  final String productId;
  const ProductScreen({super.key, required this.productId});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Sản phẩm #$productId')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Chi tiết cho Sản phẩm #$productId'),
            ElevatedButton(
              onPressed: () => context.go('/'),
              child: const Text('Quay lại Trang Chính'),
            ),
          ],
        ),
      ),
    );
  }
}

Bước 4: Thiết Lập GoRouter

Bây giờ, hãy cấu hình GoRouter để xử lý điều hướng. Thay thế nội dung của lib/main.dart bằng mã sau:

Copy
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'screens/home_screen.dart';
import 'screens/about_screen.dart';
import 'screens/product_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // Định nghĩa cấu hình GoRouter
  final GoRouter _router = GoRouter(
    initialLocation: '/', // Bắt đầu tại trang chủ
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const HomeScreen(),
      ),
      GoRoute(
        path: '/about',
        builder: (context, state) => const AboutScreen(),
      ),
      GoRoute(
        path: '/product/:productId',
        builder: (context, state) {
          final productId = state.pathParameters['productId']!;
          return ProductScreen(productId: productId);
        },
      ),
    ],
    // Tùy chọn: Xử lý các lỗi giống như 404
    errorBuilder: (context, state) => Scaffold(
      appBar: AppBar(title: const Text('Trang Không Tìm Thấy')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Lỗi: ${state.error}'),
            ElevatedButton(
              onPressed: () => context.go('/'),
              child: const Text('Đi đến Trang Chính'),
            ),
          ],
        ),
      ),
    ),
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: 'Demo Flutter GoRouter Web',
      routerConfig: _router,
      theme: ThemeData(primarySwatch: Colors.blue),
    );
  }
}

Giải Thích Mã

  • Cài Đặt GoRouter: Chúng ta định nghĩa ba tuyến đường:
    • /: Liên kết với HomeScreen.
    • /about: Liên kết với AboutScreen.
    • /product/:productId: Liên kết với ProductScreen, với tham số động productId.
  • MaterialApp.router: Tích hợp GoRouter với hệ thống điều hướng của Flutter.
  • Xử Lý Lỗi: errorBuilder hiển thị trang 404 tùy chỉnh nếu người dùng điều hướng đến một tuyến đường không hợp lệ (ví dụ: /invalid).
  • Điều Hướng: Chúng ta sử dụng context.go() để điều hướng, điều này cập nhật URL của trình duyệt và hỗ trợ các nút quay lại/tiến tới.

Bước 5: Chạy Ứng Dụng Trên Web

Chạy ứng dụng trong trình duyệt với:

Copy
flutter run -d chrome

Bạn sẽ thấy:

  • Trang Chính với các nút để điều hướng đến Trang Giới thiệu hoặc Trang Sản phẩm.
  • URL trong trình duyệt thay đổi thành /, /about, hoặc /product/123 khi bạn điều hướng.
  • Các nút quay lại/tiến tới của trình duyệt hoạt động liền mạch.
  • Gõ một URL như http://localhost:port/product/456 trực tiếp trong trình duyệt sẽ đưa bạn đến Trang Sản phẩm với ID 456.

Các Tính Năng Chính Của GoRouter Cho Ứng Dụng Web

1. Điều Hướng Dựa Trên URL

GoRouter làm cho các URL trở thành cốt lõi của điều hướng. Ví dụ, điều hướng đến /product/123 với context.go('/product/123') cập nhật thanh địa chỉ của trình duyệt, làm cho URL có thể chia sẻ được.

2. Liên Kết Sâu

GoRouter hỗ trợ liên kết sâu ngay từ đầu. Nếu người dùng truy cập http://yourapp.com/product/123, GoRouter phân tích productId và tải màn hình chính xác. Điều này rất tuyệt vời cho việc chia sẻ liên kết hoặc tích hợp với các hệ thống bên ngoài như thông báo.

3. Tích Hợp Lịch Sử Trình Duyệt

GoRouter đồng bộ với lịch sử của trình duyệt. Nhấn nút quay lại sẽ quay lại tuyến đường trước đó (ví dụ: từ /about đến /), và tiến về phía trước. Điều này xảy ra tự động, không cần mã bổ sung.

4. Các Tuyến Đường Động

Cú pháp :productId cho phép các tuyến đường động. Bạn có thể truy cập tham số trong phần builder với state.pathParameters['productId']. Ví dụ:

Copy
GoRoute(
  path: '/product/:productId',
  builder: (context, state) => ProductScreen(productId: state.pathParameters['productId']!),
)

5. Tham Số Truy Vấn

GoRouter cũng hỗ trợ các tham số truy vấn (ví dụ: /search?query=flutter). Truy cập chúng với state.uri.queryParameters['query']. Ví dụ:

Copy
GoRoute(
  path: '/search',
  builder: (context, state) {
    final query = state.uri.queryParameters['query'] ?? 'Không có truy vấn';
    return SearchScreen(query: query);
  },
)

6. Chuyển Hướng Cho Xác Thực

Đối với các ứng dụng web, bạn có thể muốn chuyển hướng người dùng đến trang đăng nhập nếu họ chưa xác thực. Thêm một chuyển hướng vào cấu hình GoRouter:

Copy
final GoRouter _router = GoRouter(
  routes: [/* ... */],
  redirect: (context, state) {
    bool isLoggedIn = false; // Thay thế bằng logic xác thực của bạn
    if (!isLoggedIn && state.uri.path != '/login') {
      return '/login';
    }
    return null; // Không chuyển hướng
  },
);

Mẹo Xây Dựng Ứng Dụng Web Flutter Thân Thiện URL

  • Kiểm Tra URL Trực Tiếp: Thử gõ các URL như /product/999 trong trình duyệt để đảm bảo liên kết sâu hoạt động.
  • Sử Dụng Đường Dẫn Mô Tả: Giữ các tuyến đường như /about hoặc /product trực quan cho người dùng.
  • Xử Lý Lỗi Một Cách Nhẹ Nhàng: Sử dụng errorBuilder để hiển thị các trang 404 thân thiện với người dùng.
  • Tối Ưu Hóa Cho SEO: Các URL sạch như /product/123 tốt hơn cho các công cụ tìm kiếm và việc chia sẻ.
  • Kiểm Tra Điều Hướng Trình Duyệt: Đảm bảo các nút quay lại/tiến tới hoạt động như mong đợi.

Triển Khai Ứng Dụng Web

Để triển khai ứng dụng web Flutter của bạn:

  1. Xây dựng nó bằng:
Copy
   flutter build web
  1. Lưu trữ nội dung của thư mục build/web trên một máy chủ web (ví dụ: Firebase Hosting, Netlify, hoặc GitHub Pages).
  2. Đảm bảo máy chủ của bạn hỗ trợ routing cho ứng dụng đơn, chuyển hướng tất cả các tuyến đường đến index.html để GoRouter có thể xử lý.
Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào