颤振如何与单页网页和不同的路由网址一起工作?

Posted

技术标签:

【中文标题】颤振如何与单页网页和不同的路由网址一起工作?【英文标题】:how flutter work with single page web and different route url? 【发布时间】:2021-06-08 05:26:56 【问题描述】:

我是 Flutter-web 的新手。

我正在使用flutter构建具有不同路由但不渲染整个页面的单页网站。

已经尝试过navigator.push & button导航栏,但是没用。

页面变更时如何构建不同url的单页网站?

抱歉英语不好!

【问题讨论】:

请通过发布一些代码来展示您已经尝试过的内容。 【参考方案1】:

找到解决方案:

import 'package:flutter/material.dart';

void main() 
  runApp(NestedRouterDemo());


class Book 
  final String title;
  final String author;

  Book(this.title, this.author);


class NestedRouterDemo extends StatefulWidget 
  @override
  _NestedRouterDemoState createState() => _NestedRouterDemoState();


class _NestedRouterDemoState extends State<NestedRouterDemo> 
  BookRouterDelegate _routerDelegate = BookRouterDelegate();
  BookRouteInformationParser _routeInformationParser =
      BookRouteInformationParser();

  @override
  Widget build(BuildContext context) 
    return MaterialApp.router(
      title: 'Books App',
      routerDelegate: _routerDelegate,
      routeInformationParser: _routeInformationParser,
    );
  


class BooksAppState extends ChangeNotifier 
  int _selectedIndex;

  Book _selectedBook;

  final List<Book> books = [
    Book('Stranger in a Strange Land', 'Robert A. Heinlein'),
    Book('Foundation', 'Isaac Asimov'),
    Book('Fahrenheit 451', 'Ray Bradbury'),
  ];

  BooksAppState() : _selectedIndex = 0;

  int get selectedIndex => _selectedIndex;

  set selectedIndex(int idx) 
    _selectedIndex = idx;
    notifyListeners();
  

  Book get selectedBook => _selectedBook;

  set selectedBook(Book book) 
    _selectedBook = book;
    notifyListeners();
  

  int getSelectedBookById() 
    if (!books.contains(_selectedBook)) return 0;
    return books.indexOf(_selectedBook);
  

  void setSelectedBookById(int id) 
    if (id < 0 || id > books.length - 1) 
      return;
    

    _selectedBook = books[id];
    notifyListeners();
  


class BookRouteInformationParser extends RouteInformationParser<BookRoutePath> 
  @override
  Future<BookRoutePath> parseRouteInformation(
      RouteInformation routeInformation) async 
    final uri = Uri.parse(routeInformation.location);

    if (uri.pathSegments.isNotEmpty && uri.pathSegments.first == 'settings') 
      return BooksSettingsPath();
     else 
      if (uri.pathSegments.length >= 2) 
        if (uri.pathSegments[0] == 'book') 
          return BooksDetailsPath(int.tryParse(uri.pathSegments[1]));
        
      
      return BooksListPath();
    
  

  @override
  RouteInformation restoreRouteInformation(BookRoutePath configuration) 
    if (configuration is BooksListPath) 
      return RouteInformation(location: '/home');
    
    if (configuration is BooksSettingsPath) 
      return RouteInformation(location: '/settings');
    
    if (configuration is BooksDetailsPath) 
      return RouteInformation(location: '/book/$configuration.id');
    
    return null;
  


class BookRouterDelegate extends RouterDelegate<BookRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<BookRoutePath> 
  final GlobalKey<NavigatorState> navigatorKey;

  BooksAppState appState = BooksAppState();

  BookRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() 
    appState.addListener(notifyListeners);
  

  @override
  BookRoutePath get currentConfiguration 
    if (appState.selectedIndex == 1) 
      return BooksSettingsPath();
     else 
      if (appState.selectedBook == null) 
        return BooksListPath();
       else 
        return BooksDetailsPath(appState.getSelectedBookById());
      
    
  

  @override
  Widget build(BuildContext context) 
    return Navigator(
      key: navigatorKey,
      pages: [
        MaterialPage(
          child: AppShell(appState: appState),
        ),
      ],
      onPopPage: (route, result) 
        if (!route.didPop(result)) 
          return false;
        

        if (appState.selectedBook != null) 
          appState.selectedBook = null;
        
        notifyListeners();
        return true;
      ,
    );
  

  @override
  Future<void> setNewRoutePath(BookRoutePath path) async 
    if (path is BooksListPath) 
      appState.selectedIndex = 0;
      appState.selectedBook = null;
     else if (path is BooksSettingsPath) 
      appState.selectedIndex = 1;
     else if (path is BooksDetailsPath) 
      appState.selectedIndex = 0;
      appState.setSelectedBookById(path.id);
    
  


// Routes
abstract class BookRoutePath 

class BooksListPath extends BookRoutePath 

class BooksSettingsPath extends BookRoutePath 

class BooksDetailsPath extends BookRoutePath 
  final int id;

  BooksDetailsPath(this.id);


// Widget that contains the AdaptiveNavigationScaffold
class AppShell extends StatefulWidget 
  final BooksAppState appState;

  AppShell(
    @required this.appState,
  );

  @override
  _AppShellState createState() => _AppShellState();


class _AppShellState extends State<AppShell> 
  InnerRouterDelegate _routerDelegate;
  ChildBackButtonDispatcher _backButtonDispatcher;

  void initState() 
    super.initState();
    _routerDelegate = InnerRouterDelegate(widget.appState);
  

  @override
  void didUpdateWidget(covariant AppShell oldWidget) 
    super.didUpdateWidget(oldWidget);
    _routerDelegate.appState = widget.appState;
  

  @override
  void didChangeDependencies() 
    super.didChangeDependencies();
    // Defer back button dispatching to the child router
    _backButtonDispatcher = Router.of(context)
        .backButtonDispatcher
        .createChildBackButtonDispatcher();
  

  @override
  Widget build(BuildContext context) 
    var appState = widget.appState;

    // Claim priority, If there are parallel sub router, you will need
    // to pick which one should take priority;
    _backButtonDispatcher.takePriority();

    return Scaffold(
      appBar: AppBar(),
      body: Router(
        routerDelegate: _routerDelegate,
        backButtonDispatcher: _backButtonDispatcher,
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(
              icon: Icon(Icons.settings), label: 'Settings'),
        ],
        currentIndex: appState.selectedIndex,
        onTap: (newIndex) 
          appState.selectedIndex = newIndex;
        ,
      ),
    );
  


class InnerRouterDelegate extends RouterDelegate<BookRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<BookRoutePath> 
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  BooksAppState get appState => _appState;
  BooksAppState _appState;
  set appState(BooksAppState value) 
    if (value == _appState) 
      return;
    
    _appState = value;
    notifyListeners();
  

  InnerRouterDelegate(this._appState);

  @override
  Widget build(BuildContext context) 
    return Navigator(
      key: navigatorKey,
      pages: [
        if (appState.selectedIndex == 0) ...[
          FadeAnimationPage(
            child: BooksListScreen(
              books: appState.books,
              onTapped: _handleBookTapped,
            ),
            key: ValueKey('BooksListPage'),
          ),
          if (appState.selectedBook != null)
            MaterialPage(
              key: ValueKey(appState.selectedBook),
              child: BookDetailsScreen(book: appState.selectedBook),
            ),
        ] else
          FadeAnimationPage(
            child: SettingsScreen(),
            key: ValueKey('SettingsPage'),
          ),
      ],
      onPopPage: (route, result) 
        appState.selectedBook = null;
        notifyListeners();
        return route.didPop(result);
      ,
    );
  

  @override
  Future<void> setNewRoutePath(BookRoutePath path) async 
    // This is not required for inner router delegate because it does not
    // parse route
    assert(false);
  

  void _handleBookTapped(Book book) 
    appState.selectedBook = book;
    notifyListeners();
  


class FadeAnimationPage extends Page 
  final Widget child;

  FadeAnimationPage(Key key, this.child) : super(key: key);

  Route createRoute(BuildContext context) 
    return PageRouteBuilder(
      settings: this,
      pageBuilder: (context, animation, animation2) 
        var curveTween = CurveTween(curve: Curves.easeIn);
        return FadeTransition(
          opacity: animation.drive(curveTween),
          child: child,
        );
      ,
    );
  


// Screens
class BooksListScreen extends StatelessWidget 
  final List<Book> books;
  final ValueChanged<Book> onTapped;

  BooksListScreen(
    @required this.books,
    @required this.onTapped,
  );

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ListView(
        children: [
          for (var book in books)
            ListTile(
              title: Text(book.title),
              subtitle: Text(book.author),
              onTap: () => onTapped(book),
            )
        ],
      ),
    );
  


class BookDetailsScreen extends StatelessWidget 
  final Book book;

  BookDetailsScreen(
    @required this.book,
  );

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            FlatButton(
              onPressed: () 
                Navigator.of(context).pop();
              ,
              child: Text('Back'),
            ),
            if (book != null) ...[
              Text(book.title, style: Theme.of(context).textTheme.headline6),
              Text(book.author, style: Theme.of(context).textTheme.subtitle1),
            ],
          ],
        ),
      ),
    );
  


class SettingsScreen extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Center(
        child: Text('Settings screen'),
      ),
    );
  

【讨论】:

以上是关于颤振如何与单页网页和不同的路由网址一起工作?的主要内容,如果未能解决你的问题,请参考以下文章

在具有不同主页的单页应用程序中路由

如何设置NGINX以根据位置(在相同的server_name下)部署不同的单页应用程序(SPA的...即静态文件)和子路由

AngularJs之八

磊科路由器的网址是啥?

Svelte - 路由,当我尝试输入任何网址时,我只会收到“未找到网页”错误

我家装了路由器TPLINK之后 有些网页打不开或者要刷新好多次才能刷出来 QQ校内都能