Flutter、Vue 3 和 React 在 UI 布局比较

发布于:2025-07-12 ⋅ 阅读:(18) ⋅ 点赞:(0)


前言

Flutter、Vue 3 和 React 在 UI 布局方式上的设计哲学和实现方式比较


🧩 总体设计哲学对比

项目 Flutter Vue 3 React
编程语言 Dart JavaScript / TypeScript JavaScript / TypeScript
渲染方式 自绘 UI(Skia 引擎) HTML + CSS(DOM) HTML + CSS(DOM)
样式机制 通过 Widget 实现 单文件组件 + CSS(或 scoped CSS) JSX + CSS-in-JS / CSS Modules 等
布局方式 Widget 嵌套布局 基于 HTML 结构和 CSS 布局模型 同 Vue,靠 CSS 控制布局

🧱 布局方式详解对比

对比项 Flutter Vue 3 React
布局核心机制 使用 Widget 树,一切皆组件,比如 RowColumnExpanded HTML 标签 + CSS,如 div + flex JSX + CSS(或 styled-components)
样式设置方式 通过属性传递(如 padding: EdgeInsets.all(10) CSS 样式或 scoped 样式 CSS、styled-components、emotion、Tailwind 等
响应式布局 使用 LayoutBuilderMediaQueryFlexible 控制自适应 使用媒体查询 + CSS Flex/Grid 等 同 Vue,依赖 CSS 的能力
Flex布局 Row/Column + Expanded/Flexible 控制主轴和交叉轴方向 CSS Flex,例如 display: flex; justify-content: space-between JSX中用 div 加 class 控制 CSS Flex 或 styled-components
Grid布局 GridView, SliverGrid 等自带 widget CSS Grid 同 Vue
Absolute 定位 Stack + Positioned 实现层叠与绝对定位 CSS 的 position: absolute 同 Vue
条件渲染 使用 if/? : 表达式嵌入 widget v-if, v-show, 三元表达式 if () return ...,或三元表达式

🧭 示例对比:Flex 布局(横向排列)

Flutter 示例

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Text("Left"),
    Text("Right"),
  ],
)

Vue 3 示例(template)

<template>
  <div class="flex-container">
    <span>Left</span>
    <span>Right</span>
  </div>
</template>

<style scoped>
.flex-container {
  display: flex;
  justify-content: space-between;
}
</style>

React 示例(JSX)

function App() {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between' }}>
      <span>Left</span>
      <span>Right</span>
    </div>
  );
}

好的,我们来通过 实际开发中常见的 UI 场景,对比 Flutter、Vue 3 和 React 的实现方式,重点包括 布局、动画、交互、状态管理等方面。每个场景都提供三者的代码示例,以便你直观对比和学习。


🧩 场景 1:页面加载时淡入(入场动画)

Flutter 示例(使用 AnimatedOpacity

class FadeInDemo extends StatefulWidget {
  
  _FadeInDemoState createState() => _FadeInDemoState();
}

class _FadeInDemoState extends State<FadeInDemo> {
  double _opacity = 0.0;

  
  void initState() {
    super.initState();
    Future.delayed(Duration(milliseconds: 300), () {
      setState(() {
        _opacity = 1.0;
      });
    });
  }

  
  Widget build(BuildContext context) {
    return AnimatedOpacity(
      duration: Duration(milliseconds: 600),
      opacity: _opacity,
      child: Text("Hello World"),
    );
  }
}

Vue 3 示例(使用 <transition>

<template>
  <transition name="fade">
    <div v-if="show" class="text">Hello World</div>
  </transition>
</template>

<script setup>
import { ref, onMounted } from 'vue'
const show = ref(false)

onMounted(() => {
  setTimeout(() => show.value = true, 300)
})
</script>

<style scoped>
.fade-enter-active {
  transition: opacity 0.6s;
}
.fade-enter-from {
  opacity: 0;
}
.fade-enter-to {
  opacity: 1;
}
</style>

React 示例(使用 CSS Transition + useEffect

import { useState, useEffect } from "react";
import "./App.css";

export default function App() {
  const [show, setShow] = useState(false);
  useEffect(() => {
    setTimeout(() => setShow(true), 300);
  }, []);
  
  return <div className={`text ${show ? "fade-in" : ""}`}>Hello World</div>;
}
.text {
  opacity: 0;
  transition: opacity 0.6s;
}
.fade-in {
  opacity: 1;
}

🧭 场景 2:Tab 切换布局

Flutter 示例(TabBar + TabBarView

DefaultTabController(
  length: 2,
  child: Scaffold(
    appBar: AppBar(
      bottom: TabBar(
        tabs: [
          Tab(text: "Home"),
          Tab(text: "Profile"),
        ],
      ),
    ),
    body: TabBarView(
      children: [
        Center(child: Text("Home Page")),
        Center(child: Text("Profile Page")),
      ],
    ),
  ),
)

Vue 3 示例(配合 Element Plus 或自定义 Tab)

<template>
  <el-tabs v-model="activeTab">
    <el-tab-pane label="Home" name="home">Home Page</el-tab-pane>
    <el-tab-pane label="Profile" name="profile">Profile Page</el-tab-pane>
  </el-tabs>
</template>

<script setup>
import { ref } from 'vue'
const activeTab = ref('home')
</script>

React 示例(配合 Ant Design 或自定义 Tab)

import { Tabs } from "antd";
const { TabPane } = Tabs;

export default function App() {
  return (
    <Tabs defaultActiveKey="1">
      <TabPane tab="Home" key="1">Home Page</TabPane>
      <TabPane tab="Profile" key="2">Profile Page</TabPane>
    </Tabs>
  );
}

🎮 场景 3:点击按钮后元素平移动画(Translate 动画)

Flutter 示例(AnimatedPositioned + Stack

class SlideDemo extends StatefulWidget {
  
  _SlideDemoState createState() => _SlideDemoState();
}

class _SlideDemoState extends State<SlideDemo> {
  bool moved = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        AnimatedPositioned(
          left: moved ? 200 : 0,
          duration: Duration(milliseconds: 500),
          child: ElevatedButton(
            onPressed: () => setState(() => moved = !moved),
            child: Text("Move Me"),
          ),
        ),
      ],
    );
  }
}

Vue 3 示例(CSS 动画 + 绑定 style)

<template>
  <button :style="style" @click="toggle">Move Me</button>
</template>

<script setup>
import { ref, computed } from 'vue'
const moved = ref(false)
const toggle = () => moved.value = !moved.value
const style = computed(() => ({
  transform: `translateX(${moved.value ? '200px' : '0px'})`,
  transition: 'transform 0.5s'
}))
</script>

React 示例(CSS 绑定 style)

import { useState } from "react";

export default function App() {
  const [moved, setMoved] = useState(false);
  return (
    <button
      onClick={() => setMoved(!moved)}
      style={{
        transform: `translateX(${moved ? "200px" : "0px"})`,
        transition: "transform 0.5s"
      }}
    >
      Move Me
    </button>
  );
}

📦 响应式/状态管理对比

功能 Flutter Vue 3 React
响应式机制 setState / Provider / Riverpod 等 ref, reactive useState, useEffect
组件更新机制 自动刷新使用该状态的 widget 响应式引用追踪 函数组件执行时重新渲染

🧠 总结对比学习建议

特性 Flutter Vue 3 React
动画支持 强大,组件级支持(如 Animated* 原生 CSS 动画 + transition 插件 原生 CSS 或动画库(framer-motion)
样式控制 属性式控制,强结构性 类 + CSS,配合 scoped 或 tailwind JSX 样式 + styled-components 等
状态响应 setState / Riverpod / GetX ref/reactive + watch useState / useEffect
生命周期 initState, build, dispose onMounted, onUnmounted useEffect(() => {}, [])


网站公告

今日签到

点亮在社区的每一天
去签到