Jotai
微信公众号

个人简介
查看所有标签
这是现代前端开发(尤其是 React)的基石理念:用户界面是应用状态的确定性函数。
简单理解:给定相同的状态,函数 f 永远返回相同的 UI。没有意外,没有隐藏副作用。
状态 → 函数 → 界面 → 用户操作 → 新状态 → ...
界面从不直接修改自己。用户交互触发状态变更,状态变更再触发界面重新渲染。
虽然实际组件不一定完全纯净(可能有副作用),但这一理念鼓励你将渲染逻辑与副作用分离,保持可预测性。
// 给定状态
const state = {
isLoggedIn: true,
username: "张三",
unreadCount: 5
};
// 组件就是这个函数
function HeaderUI(state) {
if (!state.isLoggedIn) {
return <登录按钮 />;
}
return (
<div>
<span>欢迎, {state.username}!</span>
<通知徽章 未读数={state.unreadCount} />
</div>
);
}
// UI 是状态的确定性结果
HeaderUI(state); // → 固定的 UI 树
| 优势 | 说明 |
|---|---|
| 可预测性 | 相同状态 = 相同界面,极易调试 |
| 可调试性 | 支持"时间旅行"调试:记录状态即可重现界面 |
| 可维护性 | UI 逻辑集中,不在事件处理器中零散分布 |
| 可测试性 | 测试函数即可:输入状态,断言输出 UI |
这些情况下,现代框架提供了"逃生舱"(如 ref、useEffect)让你有控制地偏离纯函数模型。
总结:将它视为指导原则而非铁律。目标是让 95% 的 UI 遵循 UI = f(State),剩余 5% 使用受控的"逃生舱"。

在 Flutter 中要将 PNG 图片转换为 JPEG 格式,主要可以通过使用功能强大的 image 第三方库来实现。下面的表格汇总了实现此功能的核心步骤和要点,可以帮助你快速上手。
| 步骤 | 关键方法/操作 | 说明 |
|---|---|---|
| 1. 添加依赖 | 在 pubspec.yaml 中添加 image: ^4.1.3 (或更高版本) | 引入图像处理库 。 |
| 2. 解码图片 | img.decodeImage(file.readAsBytesSync()) | 将图片文件读取为字节数据并解码为可操作的图像对象 。 |
| 3. 编码为JPEG | img.encodeJpg(image, quality: 85) | 将图像对象编码为JPEG格式,可指定压缩质量 (1-100) 。 |
| 4. 保存文件 | File('path/output.jpg').writeAsBytesSync(jpegData) | 将编码后的字节数据写入一个新文件 。 |
下面我们一步步来看如何具体实现,并附上代码示例。
添加依赖与导入库
首先,你需要在项目的 pubspec.yaml 文件的 dependencies 部分添加 image 库的依赖,然后执行 flutter pub get 命令来安装它。
dependencies:
flutter:
sdk: flutter
image: ^4.1.3 # 请使用当时的最新版本
在需要使用格式转换功能的Dart文件中,导入必要的库。
import 'dart:io';
import 'package:image/image.dart' as img; // 使用别名(如img)避免命名冲突
编写转换代码 转换过程主要包含解码、编码和保存三个步骤。下面是一个完整的函数示例,它接收一个PNG图片文件作为输入,然后将其转换为JPEG并保存到指定路径。
/// 将PNG图片文件转换为JPEG格式
/// [pngFile]: 输入的PNG图片文件
/// [outputPath]: 输出的JPEG图片路径
/// [quality]: JPEG压缩质量(1-100),默认85
Future<File?> convertPngToJpeg(File pngFile, String outputPath, {int quality = 85}) async {
try {
// 1. 将PNG文件读取为字节数据
List<int> imageBytes = await pngFile.readAsBytes();
// 2. 解码字节数据,生成可操作的图像对象
img.Image? image = img.decodeImage(Uint8List.fromList(imageBytes));
if (image == null) {
print("错误:图片解码失败。");
return null;
}
// 3. 将图像对象编码为JPEG格式的字节数据,并可选择质量
List<int> jpegData = img.encodeJpg(image, quality: quality);
// 4. 将JPEG字节数据写入到新的输出文件
File jpegFile = File(outputPath);
await jpegFile.writeAsBytes(jpegData);
print("转换成功!JPEG文件已保存至: $outputPath");
return jpegFile;
} catch (e) {
print("转换过程中发生错误: $e");
return null;
}
}
使用方法示例:
// 假设有一个名为 'input.png' 的图片文件
File pngImage = File('/path/to/your/image.png');
// 调用转换函数
convertPngToJpeg(pngImage, '/path/to/your/output.jpg', quality: 80);
为了让转换过程更顺利,这里有一些实用的建议。
quality 参数允许你在文件大小和图片质量之间进行权衡。数值越低,文件越小,但图片质量损耗也越大。对于大多数网页显示,75-85 是一个不错的平衡点;如果需要较高清晰度,可以设置为 90 以上。// 示例:在Isolate中处理图片
Future<File?> convertImageInIsolate(File pngFile) async {
return await compute(_convertImage, pngFile.path);
}
static Future<File?> _convertImage(String path) async {
// ... 这里是上面的转换逻辑 ...
}
ui.Image:你可能会在Flutter中遇到 ui.Image 类型,它通常由 Canvas 绘制或由 Image 组件解析得到。需要注意的是,Flutter 自带的 ui.Image 不能直接转换为JPEG字节流。一个常见的做法是先用 toByteData() 方法将其转换为PNG格式的 ByteData,然后再使用上面介绍的 image 库进行转换。对于追求极致性能或者需要处理超大批量图片的开发者,还有一个高阶选择:使用 Rust 来实现图像处理逻辑,然后通过 flutter_rust_bridge 等工具与Flutter应用桥接。这种方式在处理速度上通常优于纯Dart的实现。当然,这需要额外的学习成本和技术栈,适合对性能有严苛要求的项目。
希望这份详细的指南能帮助你成功在Flutter中实现PNG到JPEG的转换。如果你对某个具体步骤有更多疑问,我们可以继续深入探讨。

通过 flutter_rust_bridge 集成 Rust 图像处理库,并实现生成小于指定大小的 JPEG 图片,是一项能充分发挥 Rust 高性能优势的技术方案。其核心思路是,在 Rust 端编写一个图像处理函数,该函数接收图片数据和目标大小参数,通过动态调整 JPEG 的压缩质量,使输出的图片大小逼近目标值。
下面的流程图直观展示了实现这一需求的核心步骤与关键的循环调整逻辑:
下面我们具体看看如何实现。
首先,在你的 Rust 项目的 Cargo.toml 文件中添加必要的依赖。
[dependencies]
image = "0.25" # 用于图像编解码和基础处理
flutter_rust_bridge = "1.0" # 用于桥接
接下来,实现核心的 Rust 函数。这个函数的核心在于循环调整质量参数并检查输出大小(即流程图中的循环过程)。
// 在 lib.rs 中
use image::{load_from_memory, ImageOutputFormat};
use std::io::Cursor;
/// 将图片字节数据转换为符合指定大小要求的JPEG字节数据
/// 参数:
/// - `image_bytes`: 输入的图片(如PNG)字节数据
/// - `target_size_bytes`: 目标文件大小(单位:字节)
/// 返回: 成功时返回包含JPEG数据的 `Vec<u8>`
pub fn convert_to_jpeg_with_target_size(
image_bytes: Vec<u8>,
target_size_bytes: u32,
) -> Result<Vec<u8>, String> { // 使用Result便于错误处理
// 解码图片
let img = load_from_memory(&image_bytes)
.map_err(|e| format!("Failed to decode image: {}", e))?;
// 初始化质量参数
let mut quality: u8 = 80; // 初始质量参数
let mut min_quality: u8 = 10;
let mut max_quality: u8 = 95;
let tolerance = (target_size_bytes as f32 * 0.05) as usize; // 允许5%的误差
// 循环调整质量以逼近目标大小
loop {
// 编码为JPEG
let mut jpeg_data: Vec<u8> = Vec::new();
{
let mut cursor = Cursor::new(&mut jpeg_data);
img.write_to(&mut cursor, ImageOutputFormat::Jpeg(quality))
.map_err(|e| format!("Failed to encode JPEG: {}", e))?;
}
let current_size = jpeg_data.len();
// 检查是否在容差范围内
if current_size <= target_size_bytes as usize {
return Ok(jpeg_data);
}
// 调整质量参数
if quality <= min_quality {
// 如果质量已降至最低仍太大,则强制返回并提示
return Ok(jpeg_data); // 或者可以考虑返回错误,提示无法压缩到指定大小
}
// 质量调整步进,可以根据当前大小与目标的差距动态调整
let size_ratio = current_size as f32 / target_size_bytes as f32;
let quality_step = if size_ratio > 2.0 { 15 } else if size_ratio > 1.5 { 10 } else { 5 };
quality = quality.saturating_sub(quality_step).max(min_quality);
}
}
代码关键点解析:
quality 参数),逐步逼近目标文件大小。这对应了流程图中的核心循环。tolerance(容差)概念,并设定了循环终止条件,避免无休止的循环。Result 类型将潜在的错误(如解码失败、编码失败)安全地传递到Flutter端。生成Dart绑定
在项目根目录下运行 flutter_rust_bridge_codegen 命令,生成对应的Dart桥接代码。
flutter_rust_bridge_codegen --rust-input path/to/your/rust/src/lib.rs --dart-output path/to/your/flutter/lib/rust_bridge.g.dart
Flutter端调用
在Flutter的Dart代码中,你可以这样调用我们刚刚实现的Rust函数。这里假设你已经正确初始化了 flutter_rust_bridge。
import 'dart:io';
import 'dart:typed_data';
import 'package:file_picker/file_picker.dart';
// 导入生成的桥接文件
import './rust_bridge.g.dart';
class ImageProcessor {
final NativeImpl _nativeApi; // 桥接类的实例
ImageProcessor(this._nativeApi);
Future<File?> convertImageToTargetSize(File inputImage, int targetSizeKB) async {
try {
// 1. 读取原始图片为字节列表
Uint8List imageBytes = await inputImage.readAsBytes();
// 2. 指定目标大小(转换为字节)
int targetSizeBytes = targetSizeKB * 1024;
// 3. 调用Rust函数进行处理
Uint8List jpegBytes = await _nativeApi.convertToJpegWithTargetSize(
imageBytes: imageBytes,
targetSizeBytes: targetSizeBytes,
);
// 4. 保存结果
String outputPath = '${inputImage.parent.path}/converted_${DateTime.now().millisecondsSinceEpoch}.jpg';
File jpegFile = File(outputPath);
await jpegFile.writeAsBytes(jpegBytes);
print('转换成功!输出文件: $outputPath, 大小: ${jpegBytes.length ~/ 1024}KB');
return jpegFile;
} catch (e) {
print('图片转换过程中发生错误: $e');
return null;
}
}
}
// 在Widget中的使用示例
Future<void> _onConvertPressed() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.image);
if (result != null) {
File? inputFile = File(result.files.first.path!);
// 假设 targetSize 来自用户输入,例如50表示50KB
int targetSize = 50;
File? outputFile = await ImageProcessor(yourNativeApiInstance).convertImageToTargetSize(inputFile, targetSize);
if (outputFile != null) {
// 更新UI,显示转换成功的图片
}
}
}
为了获得更好的效果和体验,你还可以考虑以下几点:
性能与用户体验:
async),避免在调整质量参数的循环计算时阻塞Flutter的UI线程。算法调优:
平台特定配置:要使应用在Android、iOS等平台正常运行,需要正确配置各平台的构建脚本(如Android的NDK配置),确保Flutter能正确链接编译好的Rust库。

在 Flutter 应用中,即使设备没有 GPS 模块或 GPS 信号不可用(例如在室内),您也完全可以利用 Wi-Fi 和 IP 地址进行定位。高德地图、百度地图等第三方 SDK 都提供了强大的网络定位能力。
下面这个表格清晰地展示了不同定位方式的原理和适用场景。
| 定位方式 | 技术原理 | 优点 | 缺点/适用场景 |
|---|---|---|---|
| GPS 定位 | 接收卫星信号 | 精度高(可达米级)、不受室内限制 | 耗电高、首次定位慢、室内和城市峡谷信号差 |
| Wi-Fi 定位 | 扫描周围 Wi-Fi 热点,与数据库匹配 | 室内可用、速度快、较省电 | 精度依赖热点数据库(通常10-50米) |
| 基站定位 | 连接移动网络基站三角测量 | 覆盖范围广、室内可用 | 精度较低(几百米到千米) |
| IP 定位 | 根据互联网 IP 地址解析地理位置 | 无需设备硬件权限、实现简单 | 精度最低(通常到城市级别) |
在实际开发中,您通常不需要直接处理 Wi-Fi 或基站的底层信号,而是集成一个提供了融合定位功能的 SDK。这类 SDK(如高德、百度、华为的定位服务)会自动智能结合 GPS、Wi-Fi、基站和传感器等多种数据源,为您提供最优的位置结果。
以下是集成高德定位 SDK 实现网络定位的关键步骤:
添加依赖与配置权限
在 pubspec.yaml 中添加高德定位插件依赖,并在 AndroidManifest.xml 中声明必要的权限,特别是网络访问和粗略/精确定位权限。
# pubspec.yaml
dependencies:
amap_flutter_location: ^3.0.0
permission_handler: ^x.x.x # 用于动态申请权限
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 以下权限有助于提升网络定位的精度和速度 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
设置定位参数以启用网络定位
在代码中,您可以配置定位参数,将定位模式设置为高精度模式(AMapLocationMode.Hight_Accuracy)。此模式会优先使用 GPS,但如果 GPS 不可用,会自动回退到 Wi-Fi 和基站定位。
import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';
void _setLocationOption() {
AMapLocationOption locationOption = AMapLocationOption();
// 设置为高精度定位模式
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
// 设置是否需要返回地址信息
locationOption.needAddress = true;
// ... 其他参数设置
_locationPlugin.setLocationOption(locationOption);
}
申请权限并开始定位
使用 permission_handler 插件动态申请定位权限,然后启动定位。
// 申请定位权限
var status = await Permission.location.request();
if (status == PermissionStatus.granted) {
_setLocationOption();
_locationPlugin.startLocation();
}
监听定位结果 监听定位结果的回调流,SDK 会在获取到位置信息后(可能是通过 GPS、Wi-Fi 或基站)返回数据。
StreamSubscription<Map<String, Object>> _locationListener;
_locationListener = _locationPlugin.onLocationChanged().listen((Map<String, Object> result) {
// 处理返回的位置信息
double latitude = result['latitude'];
double longitude = result['longitude'];
String address = result['address']; // 如果needAddress为true
print("当前位置:纬度$latitude, 经度$longitude, 地址:$address");
});
updatePrivacyShow 和 updatePrivacyAgree 等相关方法。ACCESS_BACKGROUND_LOCATION)需要单独处理。请确保根据您的应用需求正确申请和管理权限。希望这些信息能帮助您顺利在 Flutter 应用中实现网络定位功能!如果您在集成特定 SDK 时遇到更具体的问题,我很乐意提供进一步的探讨。

上传图片同一张照片23M,手机系统剪裁后不能上传,提示图片不能超过2M,手机系统不剪裁可以上传,判断有问题
1.据图片格式决定质量降低的步长
static int _getQualityStep(String extension) {
// 对于PNG等无损格式,可以加大步长,因为质量参数对其影响机制不同
return (extension == 'png') ? 10 : 5;
}
flutter: 图片选择成功,开始处理
flutter: 原始图片大小: 2.429793357849121 MB
flutter: 质量 90% 压缩后: 3.1823205947875977 MB
flutter: 质量 85% 压缩后: 2.8928775787353516 MB
flutter: 质量 80% 压缩后: 2.498446464538574 MB
flutter: 质量 75% 压缩后: 2.4492578506469727 MB
flutter: 质量 70% 压缩后: 2.3891944885253906 MB
flutter: 质量 65% 压缩后: 2.2195205688476562 MB
flutter: 质量 60% 压缩后: 2.0848846435546875 MB
flutter: 质量 55% 压缩后: 1.332777976989746 MB
flutter: 通过质量压缩成功达到目标大小

在地图开发中,坐标系是核心概念。不同地图服务使用不同标准,混用会导致位置偏移。
{lat: 39.9042, lng: 116.4074}// WGS84 → GCJ-02
function wgs84ToGcj02(lng, lat) {
// 复杂非线性转换,实际项目中建议使用成熟库
const pi = 3.141592653589793;
const a = 6378245.0;
const ee = 0.00669342162296594323;
// ... 具体算法实现
}
// GCJ-02 → BD-09
function gcj02ToBd09(lng, lat) {
const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * Math.PI);
const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * Math.PI);
return {
lng: z * Math.cos(theta) + 0.0065,
lat: z * Math.sin(theta) + 0.006
};
}
npm install coord-convertnpm install gcoord(支持多种坐标系)import { wgs84togcj02, gcj02tobd09 } from 'coord-convert';
const [gcjLng, gcjLat] = wgs84togcj02(116.4074, 39.9042);
const [bdLng, bdLat] = gcj02tobd09(gcjLng, gcjLat);
// 直接使用 WGS84 坐标
const position = { lat: 39.9042, lng: 116.4074 }; // 正确
// 如果数据来自高德/腾讯,需先转换
import { gcj02towgs84 } from 'coord-convert';
const wgsPosition = gcj02towgs84(gcjLng, gcjLat);
// 高德地图 API:使用 GCJ-02
const position = [116.4074, 39.9042]; // 直接传入GCJ-02
// 百度地图 API:使用 BD-09
const point = new BMap.Point(116.404, 39.915); // BD-09坐标
// ❌ 错误:将 GCJ-02 坐标用于 Google Maps
// 结果:位置偏移几百米
<Map center={{lat: 39.9042, lng: 116.4074}} /> // 如果这是GCJ-02坐标就会错
// ✅ 正确:确保是 WGS84
const wgs84Coordinate = convertFromGcj02ToWgs84(gcjCoordinate);
如何判断数据坐标系?
function detectCoordinateSystem(lng, lat) {
// 在中国境内
if (lng > 73 && lng < 135 && lat > 18 && lat < 54) {
// 如果与真实位置偏差 < 10m,很可能是 WGS84
// 如果偏差 100-500m,可能是 GCJ-02
// 如果偏差 > 500m,可能是 BD-09
}
}
| 地图服务 | 使用坐标系 | 是否需要转换 |
|---|---|---|
| Google Maps(全球) | WGS84 | 直接适配 |
| Google Maps(中国) | GCJ-02 | 需 WGS84→GCJ-02 |
| 高德/腾讯地图 | GCJ-02 | 需 WGS84→GCJ-02 |
| 百度地图 | BD-09 | 需 WGS84→GCJ-02→BD-09 |
| OpenStreetMap | WGS84 | 直接适配 |
核心建议:保存数据时使用 WGS84,使用时根据目标平台动态转换。

Flutter应用在没有GPS的情况下,可以通过Wi-Fi定位和IP定位两种方案获取位置信息。
Wi-Fi定位通过扫描周围Wi-Fi热点的MAC地址和信号强度,与服务器数据库匹配来计算位置,精度可达20-50米。
国内地图SDK内置Wi-Fi定位功能,自动融合GPS、Wi-Fi、基站数据。
// 使用 flutter_amap_location 插件
import 'package:flutter_amap_location/flutter_amap_location.dart';
// 初始化定位
await AMapLocationClient.startup(new AMapLocationOption(
desiredAccuracy: CLLocationAccuracy.kCLLocationAccuracyHundredMeters,
locationMode: AMapLocationMode.Hight_Accuracy, // 高精度模式会启用Wi-Fi定位
));
// 获取定位
var location = await AMapLocationClient.getLocation(true);
print('纬度: ${location.latitude}, 经度: ${location.longitude}');
import 'package:geolocator/geolocator.dart';
// 检查定位服务是否启用
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
// 获取位置(自动使用最佳可用方案:GPS > Wi-Fi > 基站)
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high, // high会自动启用Wi-Fi定位
);
print('位置: ${position.latitude}, ${position.longitude}');
在 android/app/src/main/AndroidManifest.xml 中声明:
<!-- 网络定位(无GPS情况下的定位)必选 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- Wi-Fi定位必需 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 设备和运营商信息(基站定位辅助) -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
关键点:ACCESS_COARSE_LOCATION 权限允许使用Wi-Fi和基站进行粗略定位。
通过设备的公网IP地址查询地理位置,精度较低(通常只能定位到城市级别),但无需任何特殊权限。
import 'package:ip_geolocation_io/ip_geolocation_io.dart';
// 获取IP定位信息
final ipGeo = IpGeolocationIo();
final geoData = await ipGeo.getGeoData();
print('国家: ${geoData.country}');
print('省份: ${geoData.state}');
print('城市: ${geoData.city}');
print('纬度: ${geoData.latitude}'); // 城市中心坐标
print('经度: ${geoData.longitude}');
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<void> getLocationByIP() async {
final response = await http.get(Uri.parse('http://ip-api.com/json/'));
if (response.statusCode == 200) {
final data = json.decode(response.body);
print('城市: ${data['city']}');
print('坐标: ${data['lat']}, ${data['lon']}');
}
}
| 特性 | Wi-Fi定位 | IP定位 |
|---|---|---|
| 精度 | 高(20-50米) | 低(城市级,误差几公里) |
| 依赖 | 需开启Wi-Fi,无需连接 | 仅需网络连接 |
| 权限 | 需要定位权限 | 无需权限 |
| 速度 | 快(1-3秒) | 极快(毫秒级) |
| 耗电 | 中等 | 极低 |
| 室内支持 | ✅ 优秀 | ❌ 不支持 |
Future<Position?> getLocation() async {
try {
// 优先使用高精度定位(GPS+Wi-Fi)
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
} catch (e) {
// GPS/Wi-Fi都失败,降级到IP定位
final ipData = await getLocationByIP();
return Position(
latitude: ipData.latitude,
longitude: ipData.longitude,
timestamp: DateTime.now(),
accuracy: 5000, // 标记低精度
);
}
}
ACCESS_BACKGROUND_LOCATION 权限才能在后台定位在 ios/Runner/Info.plist 中添加:
<key>NSLocationWhenInUseUsageDescription</key>
<string>App需要您的同意才能访问位置</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App需要您的同意才能在后台访问位置</string>
推荐使用 Wi-Fi定位 作为GPS的替代方案,精度足以满足大多数场景需求。IP定位仅作为最后备用手段。主流地图SDK已内置完善的多源融合定位能力,开发者无需关心底层实现细节。
实现路径:配置权限 → 选择插件 → 调用统一API → 自动处理GPS/Wi-Fi/基站切换。

Figma MCP(Model Context Protocol)是一项创新技术,它作为一个“翻译官”和“桥梁”,将Figma设计工具与AI编程助手(如Cursor、Claude Code等)无缝连接起来。这使得AI能够直接“理解”Figma设计稿中的元素、样式和结构,并自动生成高质量的前端代码,从而显著提升从设计到开发的转换效率 。
通过Figma MCP,AI助手可以为你完成以下一系列自动化任务,覆盖了从设计资源提取到代码生成的全流程 :
Figma官方提供了两种使用MCP服务器的方式,你可以根据自身情况选择一种进行配置 。
| 服务器类型 | 适用场景 | 激活方式 |
|---|---|---|
| 本地服务器(Local) | 适合大多数个人开发者和小团队,通过Figma桌面应用运行,数据在本地处理 。 | 1. 打开最新版的Figma桌面应用。 2. 进入一个设计文件。 3. 切换至Dev Mode(开发模式)。 4. 在检查(Inspect)面板的MCP server区域,点击 Enable desktop MCP server。服务器通常会运行在 http://127.0.0.1:3845/mcp 。 |
| 远程服务器(Remote) | 适合大型团队或希望简化配置的用户,直接连接至Figma的托管端点,无需运行桌面应用 。 | 无需本地激活,服务器地址为:https://mcp.figma.com/mcp。但需要注意,某些高级功能可能需要特定的Figma订阅席位(如Dev或Full seat)。 |
连接到AI工具(以Cursor为例) 配置好服务器后,需要在你的AI编程工具中进行连接。下面以流行的Cursor为例 :
{
"mcpServers": {
"Figma": {
"url": "http://127.0.0.1:3845/mcp"
}
}
}
{
"mcpServers": {
"Figma": {
"url": "https://mcp.figma.com/mcp"
}
}
}
为了获得更精准、高效的代码生成结果,可以参考以下建议 :
CardContainer而非Group 5),这能极大地帮助AI理解你的设计意图 。src/components/ui下的现有组件。”get_metadata工具获取高层级节点图,然后有选择地针对特定节点生成代码 。figma-mcp-full-server),它们可能提供额外的功能,如更强大的批量导出和重试机制 。另外,国内也有类似Pixso这样的设计工具提供了类似的MCP功能,可能更适合部分用户的使用习惯 。希望这份详细的指南能帮助你更好地理解和运用Figma MCP,解锁AI驱动的设计到代码自动化工作流。如果你在配置或使用过程中遇到更具体的问题,欢迎随时提出。

鑫联盟需求要 16 以下的 node版本,但react-native-update-cli需要 18 以上的版本,故而左右为难;
脚本: react-native-update-cli/lib/bundle.js
const reactNativeBundleProcess = (0, _child_process.spawn)('/Volumes/Samsung/Home/.nvm/versions/node/v16.20.2/bin/node', reactNativeBundleArgs);
console.log(`Running bundle command: node ${reactNativeBundleArgs.join(' ')}`);
