Flutter for OpenHarmony TabBar 高级标签系统与导航交互优化
深入解析 Flutter TabBar 系统架构,涵盖固定、滚动、图标、自定义指示器、动画切换、分段及底部标签栏等多种导航模式的实现方案。通过提供完整的代码示例,展示了如何构建高性能标签系统,并针对 OpenHarmony 平台给出了手势冲突处理、屏幕适配及性能优化建议,旨在帮助开发者提升移动应用导航体验。

深入解析 Flutter TabBar 系统架构,涵盖固定、滚动、图标、自定义指示器、动画切换、分段及底部标签栏等多种导航模式的实现方案。通过提供完整的代码示例,展示了如何构建高性能标签系统,并针对 OpenHarmony 平台给出了手势冲突处理、屏幕适配及性能优化建议,旨在帮助开发者提升移动应用导航体验。

在现代移动应用中,标签导航是最常见的导航模式之一。从简单的固定标签到复杂的滑动标签,Flutter 提供了 TabBar 组件来实现各种标签导航效果。理解这套架构的底层原理,是构建高性能标签导航系统的基础。
Flutter 的 TabBar 系统由多个核心层次组成,每一层都有其特定的职责:
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 (Application Layer) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ TabBar, TabBarView, TabController, DefaultTabController │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 指示器层 (Indicator Layer) │ │
│ │ TabIndicator, UnderlineTabIndicator, BoxDecoration... │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 动画层 (Animation Layer) │ │
│ │ AnimationController, Tween, CurvedAnimation... │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 状态管理层 (State Management Layer) │ │
│ │ TabController, TickerProvider, ChangeNotifier... │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Flutter TabBar 系统的核心组件包括以下几个部分:
TabBar(标签栏)
TabBar 是显示标签列表的组件,支持多种自定义样式。
TabBar(
tabs: const [
Tab(text: '首页'),
Tab(text: '发现'),
Tab(text: '我的'),
],
controller: tabController,
indicatorColor: Colors.blue,
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
indicatorSize: TabBarIndicatorSize.label,
)
TabBarView(标签视图)
TabBarView 是显示标签内容的组件,支持滑动切换。
TabBarView(
controller: tabController,
children: [
HomePage(),
DiscoverPage(),
ProfilePage(),
],
)
TabController(标签控制器)
TabController 用于控制标签切换和监听标签变化。
final tabController = TabController(
length: 3,
vsync: this,
);
tabController.addListener(() {
if (!tabController.indexIsChanging) {
print('当前标签:${tabController.index}');
}
});
tabController.animateTo(1);
设计优秀的标签导航需要遵循以下原则:
┌─────────────────────────────────────────────────────┐
│ 标签导航设计原则 │
├─────────────────────────────────────────────────────┤
│ 1. 清晰性 - 标签名称简洁明了,图标含义清晰 │
│ 2. 一致性 - 标签样式统一,交互方式一致 │
│ 3. 反馈性 - 选中状态明显,切换动画流畅 │
│ 4. 可访问性 - 标签数量适中,易于点击 │
│ 5. 上下文 - 标签内容相关,导航逻辑清晰 │
└─────────────────────────────────────────────────────┘
标签类型对比:
| 类型 | 特点 | 适用场景 |
|---|---|---|
| 固定标签 | 数量固定,等宽分布 | 底部导航栏 |
| 滚动标签 | 数量可变,支持滑动 | 顶部分类导航 |
| 图标标签 | 图标 + 文字,直观 | 主导航 |
| 纯文字标签 | 简洁,节省空间 | 次级导航 |
基础标签导航包括固定标签、滚动标签和图标标签。这些是构建复杂标签导航系统的基础。
固定标签导航是最常见的标签模式,标签数量固定且等宽分布。
import 'package:flutter/material.dart';
/// 固定标签导航示例
class FixedTabDemo extends StatefulWidget {
const FixedTabDemo({super.key});
@override
State<FixedTabDemo> createState() => _FixedTabDemoState();
}
class _FixedTabDemoState extends State<FixedTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('固定标签导航'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '首页'),
Tab(text: '发现'),
Tab(text: '我的'),
],
indicatorColor: Colors.blue,
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildTabPage('首页', Colors.blue),
_buildTabPage('发现', Colors.green),
_buildTabPage('我的', Colors.orange),
],
),
);
}
Widget _buildTabPage(String title, Color color) {
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: 20,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: Container(
width: 50,
height: 50,
decoration: BoxDecoration(
color: color.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
),
),
title: Text('$title - ${index + 1}'),
subtitle: Text('这是 $title 的第 ${index + 1} 项'),
),
);
},
);
}
}
滚动标签导航支持大量标签,用户可以滑动查看更多标签。
/// 滚动标签导航示例
class ScrollableTabDemo extends StatefulWidget {
const ScrollableTabDemo({super.key});
@override
State<ScrollableTabDemo> createState() => _ScrollableTabDemoState();
}
class _ScrollableTabDemoState extends State<ScrollableTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final List<String> _tabs = [
'推荐', '热门', '视频', '小说', '娱乐',
'科技', '体育', '财经', '军事', '历史'
];
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('滚动标签导航'),
bottom: TabBar(
controller: _tabController,
isScrollable: true,
tabs: _tabs.map((tab) => Tab(text: tab)).toList(),
indicatorColor: Colors.teal,
labelColor: Colors.teal,
unselectedLabelColor: Colors.grey,
labelStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
unselectedLabelStyle: const TextStyle(fontSize: 14),
),
),
body: TabBarView(
controller: _tabController,
children: _tabs.map((tab) => _buildTabPage(tab)).toList(),
),
);
}
Widget _buildTabPage(String title) {
return GridView.builder(
padding: const EdgeInsets.all(8),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemCount: 10,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Expanded(
child: Container(
color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.2),
child: Center(child: Text('$title - ${index + 1}')),
),
),
Padding(
padding: const EdgeInsets.all(8),
child: Text('$title 内容 ${index + 1}'),
),
],
),
);
},
);
}
}
图标标签导航结合图标和文字,提供更直观的导航体验。
/// 图标标签导航示例
class IconTabDemo extends StatefulWidget {
const IconTabDemo({super.key});
@override
State<IconTabDemo> createState() => _IconTabDemoState();
}
class _IconTabDemoState extends State<IconTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('图标标签导航'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(icon: Icon(Icons.home), text: '首页'),
Tab(icon: Icon(Icons.search), text: '搜索'),
Tab(icon: Icon(Icons.favorite), text: '收藏'),
Tab(icon: Icon(Icons.person), text: '我的'),
],
indicatorColor: Colors.purple,
labelColor: Colors.purple,
unselectedLabelColor: Colors.grey,
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildIconPage(Icons.home, '首页', Colors.blue),
_buildIconPage(Icons.search, '搜索', Colors.green),
_buildIconPage(Icons.favorite, '收藏', Colors.red),
_buildIconPage(Icons.person, '我的', Colors.orange),
],
),
);
}
Widget _buildIconPage(IconData icon, String title, Color color) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: color.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(icon, size: 50, color: color),
),
const SizedBox(height: 16),
Text(title, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
高级标签导航包括自定义指示器、动画标签、分段标签和底部标签栏。
自定义标签指示器可以实现各种独特的视觉效果。
/// 自定义指示器示例
class CustomIndicatorDemo extends StatefulWidget {
const CustomIndicatorDemo({super.key});
@override
State<CustomIndicatorDemo> createState() => _CustomIndicatorDemoState();
}
class _CustomIndicatorDemoState extends State<CustomIndicatorDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('自定义指示器'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '推荐'),
Tab(text: '热门'),
Tab(text: '最新'),
Tab(text: '关注'),
],
indicator: _CustomTabIndicator(color: Colors.blue, radius: 20),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey,
),
),
body: TabBarView(
controller: _tabController,
children: List.generate(4, (index) => Center(child: Text('页面 ${index + 1}'))),
),
);
}
}
class _CustomTabIndicator extends Decoration {
final Color color;
final double radius;
const _CustomTabIndicator({required this.color, this.radius = 20});
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return _CustomTabIndicatorPainter(color, radius);
}
}
class _CustomTabIndicatorPainter extends BoxPainter {
final Color color;
final double radius;
_CustomTabIndicatorPainter(this.color, this.radius);
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
final rect = offset & configuration.size!;
final paint = Paint()..color = color..style = PaintingStyle.fill;
final rrect = RRect.fromRectAndRadius(
Rect.fromCenter(center: rect.center, width: rect.width - 16, height: rect.height - 8),
Radius.circular(radius),
);
canvas.drawRRect(rrect, paint);
}
}
动画标签切换通过动画效果增强用户体验。
/// 动画标签切换示例
class AnimatedTabDemo extends StatefulWidget {
const AnimatedTabDemo({super.key});
@override
State<AnimatedTabDemo> createState() => _AnimatedTabDemoState();
}
class _AnimatedTabDemoState extends State<AnimatedTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final List<String> _tabs = ['消息', '通讯录', '发现', '我'];
int _currentIndex = 0;
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
_tabController.addListener(_onTabChanged);
}
void _onTabChanged() {
if (!_tabController.indexIsChanging) {
setState(() => _currentIndex = _tabController.index);
}
}
@override
void dispose() {
_tabController.removeListener(_onTabChanged);
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('动画标签切换')),
body: Column(
children: [
_buildAnimatedTabBar(),
Expanded(
child: TabBarView(
controller: _tabController,
children: _tabs.map((tab) => _buildTabPage(tab)).toList(),
),
),
],
),
);
}
Widget _buildAnimatedTabBar() {
return Container(
height: 56,
color: Colors.white,
child: Stack(
children: [
AnimatedPositioned(
duration: const Duration(milliseconds: 300),
curve: Curves.easeOutCubic,
left: _currentIndex * (MediaQuery.of(context).size.width / _tabs.length),
top: 0,
child: Container(
width: MediaQuery.of(context).size.width / _tabs.length,
height: 56,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.blue, width: 3)),
),
),
),
Row(
children: List.generate(_tabs.length, (index) {
final isSelected = index == _currentIndex;
return Expanded(
child: GestureDetector(
onTap: () => _tabController.animateTo(index),
behavior: HitTestBehavior.opaque,
child: AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: TextStyle(
color: isSelected ? Colors.blue : Colors.grey,
fontSize: isSelected ? 16 : 14,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
child: Center(child: Text(_tabs[index])),
),
),
);
}),
),
],
),
);
}
Widget _buildTabPage(String title) {
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: 15,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
title: Text('$title - ${index + 1}'),
subtitle: Text('这是 $title 的内容'),
),
);
},
);
}
}
分段标签类似于 iOS 的分段控制器,适合少量选项的切换。
/// 分段标签示例
class SegmentedTabDemo extends StatefulWidget {
const SegmentedTabDemo({super.key});
@override
State<SegmentedTabDemo> createState() => _SegmentedTabDemoState();
}
class _SegmentedTabDemoState extends State<SegmentedTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
final List<String> _tabs = ['日', '周', '月', '年'];
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('分段标签')),
body: Column(
children: [
Container(
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(12),
),
child: TabBar(
controller: _tabController,
tabs: _tabs.map((tab) => Tab(text: tab)).toList(),
indicator: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
labelColor: Colors.white,
unselectedLabelColor: Colors.grey[700],
dividerColor: Colors.transparent,
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: _tabs.map((tab) => _buildTabPage(tab)).toList(),
),
),
],
),
);
}
Widget _buildTabPage(String title) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.calendar_today, size: 80, color: Colors.blue),
const SizedBox(height: 16),
Text('$title 统计数据', style: const TextStyle(fontSize: 24)),
],
),
);
}
}
底部标签栏是移动应用中最常见的导航模式。
/// 底部标签栏示例
class BottomTabDemo extends StatefulWidget {
const BottomTabDemo({super.key});
@override
State<BottomTabDemo> createState() => _BottomTabDemoState();
}
class _BottomTabDemoState extends State<BottomTabDemo>
with SingleTickerProviderStateMixin {
late TabController _tabController;
int _currentIndex = 0;
final List<_TabItem> _tabs = [
_TabItem(icon: Icons.home_outlined, activeIcon: Icons.home, title: '首页'),
_TabItem(icon: Icons.search_outlined, activeIcon: Icons.search, title: '发现'),
_TabItem(icon: Icons.add_box_outlined, activeIcon: Icons.add_box, title: '发布'),
_TabItem(icon: Icons.favorite_border, activeIcon: Icons.favorite, title: '消息'),
_TabItem(icon: Icons.person_outline, activeIcon: Icons.person, title: '我的'),
];
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
_tabController.addListener(() {
if (!_tabController.indexIsChanging) setState(() => _currentIndex = _tabController.index);
});
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: TabBarView(
controller: _tabController,
physics: const NeverScrollableScrollPhysics(),
children: _tabs.map((tab) => _buildTabPage(tab.title)).toList(),
),
bottomNavigationBar: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 10)],
),
child: SafeArea(
child: SizedBox(
height: 60,
child: Row(
children: List.generate(_tabs.length, (index) {
final tab = _tabs[index];
final isSelected = index == _currentIndex;
return Expanded(
child: GestureDetector(
onTap: () => _tabController.animateTo(index),
behavior: HitTestBehavior.opaque,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(isSelected ? tab.activeIcon : tab.icon, color: isSelected ? Colors.cyan : Colors.grey, size: isSelected ? 28 : 24),
const SizedBox(height: 4),
Text(tab.title, style: TextStyle(color: isSelected ? Colors.cyan : Colors.grey, fontSize: 12, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal)),
],
),
),
);
}),
),
),
),
),
);
}
Widget _buildTabPage(String title) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(Icons.home, size: 50, color: Colors.blue),
),
const SizedBox(height: 16),
Text(title, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
);
}
}
class _TabItem {
final IconData icon;
final IconData activeIcon;
final String title;
const _TabItem({required this.icon, required this.activeIcon, required this.title});
}
下面是一个完整的 TabBar 高级标签系统示例入口页:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const TabBarHomePage(),
);
}
}
class TabBarHomePage extends StatelessWidget {
const TabBarHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('📑 TabBar 高级标签系统')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildSectionCard(context, title: '固定标签', description: '基础固定标签导航', icon: Icons.tab, color: Colors.blue, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const FixedTabDemo()))),
_buildSectionCard(context, title: '滚动标签', description: '可滑动标签导航', icon: Icons.swipe, color: Colors.teal, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const ScrollableTabDemo()))),
_buildSectionCard(context, title: '图标标签', description: '图标 + 文字标签', icon: Icons.image, color: Colors.purple, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const IconTabDemo()))),
_buildSectionCard(context, title: '自定义指示器', description: '圆角背景指示器', icon: Icons.brush, color: Colors.orange, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const CustomIndicatorDemo()))),
_buildSectionCard(context, title: '动画标签', description: '动画切换效果', icon: Icons.animation, color: Colors.pink, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const AnimatedTabDemo()))),
_buildSectionCard(context, title: '分段标签', description: 'iOS 风格分段', icon: Icons.view_module, color: Colors.indigo, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const SegmentedTabDemo()))),
_buildSectionCard(context, title: '底部标签栏', description: '底部导航栏', icon: Icons.navigation, color: Colors.cyan, onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const BottomTabDemo()))),
],
),
);
}
Widget _buildSectionCard(BuildContext context, {required String title, required String description, required IconData icon, required Color color, required VoidCallback onTap}) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(width: 56, height: 56, decoration: BoxDecoration(color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12)), child: Icon(icon, color: color, size: 28)),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 4),
Text(description, style: TextStyle(fontSize: 13, color: Colors.grey[600])),
],
),
),
Icon(Icons.chevron_right, color: Colors.grey[400]),
],
),
),
),
);
}
}
// ... 包含上述所有 Demo 类的代码 ...
AutomaticKeepAliveClientMixin 保持标签页状态。class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return ListView(...);
}
}
在 OpenHarmony 平台上,需要注意:
本文详细介绍了 Flutter for OpenHarmony 的 TabBar 高级标签系统,包括:
| 组件类型 | 核心技术 | 应用场景 |
|---|---|---|
| 固定标签 | TabBar + TabController | 主导航 |
| 滚动标签 | isScrollable: true | 分类导航 |
| 图标标签 | Tab(icon:, text:) | 底部导航 |
| 自定义指示器 | Decoration + BoxPainter | 品牌定制 |
| 动画标签 | AnimatedPositioned | 增强交互 |
| 分段标签 | 圆角背景指示器 | iOS 风格 |
| 底部标签栏 | TabBarView + bottomNavigationBar | 主导航 |
💡 提示:标签导航是移动应用的核心导航模式,合理设计可以显著提升用户体验。建议根据具体场景选择合适的标签类型,并注意状态管理和性能优化。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online