文章目录
- 前言
-
- [🧩 总体设计哲学对比](#🧩 总体设计哲学对比)
- [🧱 布局方式详解对比](#🧱 布局方式详解对比)
- [🧭 示例对比:Flex 布局(横向排列)](#🧭 示例对比:Flex 布局(横向排列))
-
- [Flutter 示例](#Flutter 示例)
- [Vue 3 示例(template)](#Vue 3 示例(template))
- [React 示例(JSX)](#React 示例(JSX))
- [🧩 场景 1:页面加载时淡入(入场动画)](#🧩 场景 1:页面加载时淡入(入场动画))
-
- [Flutter 示例(使用 `AnimatedOpacity`)](#Flutter 示例(使用
AnimatedOpacity
))
- [Vue 3 示例(使用 `<transition>`)](#Vue 3 示例(使用
<transition>
))
- [React 示例(使用 CSS Transition + `useEffect`)](#React 示例(使用 CSS Transition +
useEffect
))
- [🧭 场景 2:Tab 切换布局](#🧭 场景 2:Tab 切换布局)
-
- [Flutter 示例(`TabBar` + `TabBarView`)](#Flutter 示例(
TabBar
+ TabBarView
))
- [Vue 3 示例(配合 Element Plus 或自定义 Tab)](#Vue 3 示例(配合 Element Plus 或自定义 Tab))
- [React 示例(配合 Ant Design 或自定义 Tab)](#React 示例(配合 Ant Design 或自定义 Tab))
- [🎮 场景 3:点击按钮后元素平移动画(Translate 动画)](#🎮 场景 3:点击按钮后元素平移动画(Translate 动画))
-
- [Flutter 示例(`AnimatedPositioned` + `Stack`)](#Flutter 示例(
AnimatedPositioned
+ Stack
))
- [Vue 3 示例(CSS 动画 + 绑定 style)](#Vue 3 示例(CSS 动画 + 绑定 style))
- [React 示例(CSS 绑定 style)](#React 示例(CSS 绑定 style))
- [📦 响应式/状态管理对比](#📦 响应式/状态管理对比)
- [🧠 总结对比学习建议](#🧠 总结对比学习建议)
前言
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 树 ,一切皆组件,比如 Row 、Column 、Expanded 等 |
HTML 标签 + CSS,如 div + flex |
JSX + CSS(或 styled-components) |
样式设置方式 |
通过属性传递(如 padding: EdgeInsets.all(10) ) |
CSS 样式或 scoped 样式 |
CSS、styled-components、emotion、Tailwind 等 |
响应式布局 |
使用 LayoutBuilder 、MediaQuery 、Flexible 控制自适应 |
使用媒体查询 + 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 示例
dart
复制代码
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Left"),
Text("Right"),
],
)
Vue 3 示例(template)
html
复制代码
<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)
js
复制代码
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
)
dart
复制代码
class FadeInDemo extends StatefulWidget {
@override
_FadeInDemoState createState() => _FadeInDemoState();
}
class _FadeInDemoState extends State<FadeInDemo> {
double _opacity = 0.0;
@override
void initState() {
super.initState();
Future.delayed(Duration(milliseconds: 300), () {
setState(() {
_opacity = 1.0;
});
});
}
@override
Widget build(BuildContext context) {
return AnimatedOpacity(
duration: Duration(milliseconds: 600),
opacity: _opacity,
child: Text("Hello World"),
);
}
}
Vue 3 示例(使用 <transition>
)
js
复制代码
<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
)
js
复制代码
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>;
}
css
复制代码
.text {
opacity: 0;
transition: opacity 0.6s;
}
.fade-in {
opacity: 1;
}
🧭 场景 2:Tab 切换布局
Flutter 示例(TabBar
+ TabBarView
)
dart
复制代码
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)
js
复制代码
<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)
js
复制代码
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
)
dart
复制代码
class SlideDemo extends StatefulWidget {
@override
_SlideDemoState createState() => _SlideDemoState();
}
class _SlideDemoState extends State<SlideDemo> {
bool moved = false;
@override
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)
js
复制代码
<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)
js
复制代码
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(() => {}, []) |