likes
comments
collection
share

懂 Vue、React 就懂 Flutter 路由管理

作者站长头像
站长
· 阅读数 30

在现代应用程序中,页面之间的导航是一个重要的组成部分。无论是前端开发还是Flutter开发,路由都是用于管理不同页面之间导航的关键技术。在本文中,我们将深入研究Flutter路由管理的各个方面,帮助你更好地理解Flutter中的路由概念和使用方法。

路由介绍

无论是前端还是Flutter,路由都是用于管理应用程序中不同页面之间的导航。它们都允许用户通过点击链接或按钮来切换到不同的页面。这使得用户能够轻松地浏览不同的内容,无论是在浏览器中还是在Flutter应用程序中。

它们的相似点:

  • 都用于实现页面之间的导航和切换。
  • 都可以通过路由名称或路径进行页面跳转。
  • 都支持传递参数给目标页面。

它们的不同点:

  • 原生路由通常是基于操作系统提供的导航机制,而Flutter路由是在Flutter框架内部实现的。
  • 原生路由通常使用操作系统提供的界面元素(如导航栏、标签栏),而Flutter路由可以自定义界面元素。
  • 浏览器路由通常是基于URL的,可以直接通过URL进行导航,而Flutter路由通常使用命名路由来进行页面跳转。

Flutter 路由的使用场景

基本路由

基本路由是最简单的路由形式,用于在不同页面之间进行简单的切换。在Flutter中,可以通过使用Navigator进行基本路由的管理。在前端中我们通常可以通过 history 包来做页面的切换

import { useHistory } from 'react-router-dom';

// ...

const history = useHistory();

// ...

history.push('/about');

那在 Flutter 中也是一样的。

Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondScreen()),
);

除了这种编程式导航外,前端还可以通过 Link 标签做跳转

import { Link } from 'react-router-dom';
<Link to="/about">About</Link>

Flutter 没有对应的语法支持,但是可以通过 InkWell 组件实现类似的效果

InkWell(
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SecondScreen()),
    );
  },
  child: Text('About'),
)

在这个示例中,当用户点击About文本时,将会导航到名为SecondScreen的页面。

命名路由

当页面路由多了以后,我们就会“找个地方”统一的定义路由,来管理整个页面的 url 和组件的对应关系, 在React中

import { BrowserRouter as Router, Route } from 'react-router-dom';

const App = () => {
  return (
    <Router>
      <Route path="/" exact component={HomeScreen} />
      <Route path="/second" component={SecondScreen} />
      <Route path="/third" component={ThirdScreen} />
    </Router>
  );
};

在上述示例中,通过组件的path属性指定了每个页面的URL路径,并使用component属性指定了对应的组件。这样,当用户访问相应的URL时,React Router会根据path属性匹配到对应的组件进行渲染。

在 Flutter 中还是熟悉的感觉

MaterialApp(
  routes: {
    '/': (context) => HomeScreen(),
    '/second': (context) => SecondScreen(),
    '/third': (context) => ThirdScreen(),
  },
);

命名路由允许我们在应用程序中为每个页面指定一个唯一的名称,并通过该名称进行路由切换。这种路由形式在大型应用程序中尤其有用。

嵌套路由

React 和 Flutter 中的嵌套路由实现方式略有不同,但基本原理相似。

当我们的页面变得复杂,我们想在页面中嵌套其他页面, 举个例子,我们页面上面有个header 是导航条,有一个 Home, 和 Profile 的链接,下面是具体 Home 或者 Profile 的页面。相当于我们要在当前页面中嵌套 Home 和 Profile。 在 React 中怎么做呢?

import { BrowserRouter as Router, Route, Link } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/profile">Profile</Link>
            </li>
          </ul>
        </nav>

        <Route path="/" exact component={Home} />
        <Route path="/profile" component={Profile} />
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function Profile() {
  return <h2>Profile</h2>;
}

只要用把这2页面的路由嵌入这个页面里,如果当前url的path是/ , 则渲染 home 页面,如果浏览器的 url 是 /profile 则渲染 Profile页面。

Flutter 中我们想实现同样的效果也很简单,唯一区别是上面的映射关系是自动的, Flutter中我们需要写个 swtich case 自己判断一下,什么 “url” 显示什么页面

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My App'),
        ),
        body: Navigator(
          initialRoute: '/',
          onGenerateRoute: (RouteSettings settings) {
            WidgetBuilder builder;
            switch (settings.name) {
              case '/':
                builder = (BuildContext context) => HomeScreen();
                break;
              case '/profile':
                builder = (BuildContext context) => ProfileScreen();
                break;
            }
            return MaterialPageRoute(builder: builder, settings: settings);
          },
        ),
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text('Home'),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text('Profile'),
      ),
    );
  }
}

路由传值

路由传值在路由的使用中场景太常见了, 比如:

  • 在新闻app中,将新闻文章ID传递给文章详情页面,以便显示特定文章的内容、评论和分享功能。
  • 在社交媒体应用中,将用户ID传递给用户个人资料页面,以便显示特定用户的个人信息、帖子和活动。
  • 在旅行预订应用中,将目的地ID传递给目的地详情页面,以便显示特定目的地的景点、酒店和旅游活动。
  • balabala

在 React 中传个值,比如传这个ID,只需2步,先定义这个路由接收 id这个参数,然后在当前页面的 url 中获取这个ID。

// 定义一个组件,接收路由参数
const MyComponent = ({ match }) => {
  const { id } = match.params;

  return (
    <div>
      <h1>Hello React!</h1>
      <p>路由参数: {id}</p>
    </div>
  );
};

// 在路由中定义对应的路径和组件
<Route path="/example/:id" component={MyComponent} />

当然也可以编程式传 ID

import React from 'react';
import { useHistory } from 'react-router-dom';

const MyComponent = () => {
  const history = useHistory();
  const id = '123'; // 替换为你要传递的ID

  const handleClick = () => {
    history.push(`/example/${id}`);
  };

  return (
    <div>
      <h1>Hello React!</h1>
      <button onClick={handleClick}>跳转到例子页面</button>
    </div>
  );
};

export default MyComponent;

在 Flutter 中我们会使用 Navigator这个路由管理组件,它提供了打开和退出路由页方法。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // 定义路由
      routes: {
        '/': (context) => HomeScreen(),
        '/example': (context) => ExampleScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter App'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('跳转到例子页面'),
          onPressed: () {
            final String id = '123'; // 替换为你要传递的ID
            Navigator.pushNamed(context, '/example', arguments: id);
          },
        ),
      ),
    );
  }
}

class ExampleScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final String id = ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text('例子页面'),
      ),
      body: Center(
        child: Text('参数值: $id'),
      ),
    );
  }
}

上面代码先在MaterialApp小部件内,定义了routes属性来处理应用程序的不同路由。/路由对应HomeScreen小部件,/example路由对应ExampleScreen小部件。当按钮被按下时,它使用Navigator.pushNamed()方法导航到/example路由。它还传递了一个参数(id)给路由。

/example 路由该如何获取这个 id 参数呢? 可以通过ModalRoute.of(context).settings.arguments方法检索传递的参数(id),并在一个Text小部件中显示它。

结束语

通过本文,我们详细介绍了Flutter路由管理的不同方面,并与前端路由进行了对比。无论你是前端开发者还是Flutter开发者,理解如何有效地管理和使用路由都是非常重要的。

如果你觉得这篇文章有帮助,请点个赞和关注吧❤️!我将持续分享更多有价值的技术知识和经验。谢谢!

转载自:https://juejin.cn/post/7283798844235792419
评论
请登录