[MAUI]集成高德地图组件至.NET MAUI Blazor项目

uniapp H5使用高德地图实现点聚合、行政区域高亮(通俗易懂) uniapp自带的map地图组件功能有限,并且适配性实在让人苦恼,高德地图想对成熟稳定且功能比自带map组件完善很多,但是使用较为麻烦,以下是我在uniapp使用高德地图的一些见解和技巧。 阅读详情


地图组件在手机App中常用地理相关业务,如查看线下门店,设置导航,或选取地址等。是一个较为常见的组件。

在.NET MAUI 中,有两种方案可以集成高德地图,一种是使用原生库绑定。网上也有人实现过:https://blog.youkuaiyun.com/sD7O95O/article/details/125827031

但这种方案需要大量平台原生开发的知识,而且需要对每一个平台进行适配。

在这里我介绍第二种方案:.NET MAUI Blazor + 高德地图JS API 2.0 库的实现。

JS API 2.0 是高德开放平台基于WebGL的地图组件,可以将高德地图模块集成到.NET MAUI Blazor中的BlazorWebView控件,由于BlazorWebView的跨平台特性,可以达到一次开发全平台通用,无需为每个平台做适配。

今天用此方法实现一个地图选择器,使用手机的GPS定位初始化当前位置,使用高德地图JS API库实现地点选择功能。混合开发方案涉及本机代码与JS runtime的交互,如果你对这一部分还不太了解,可以先阅读这篇文章:[MAUI]深入了解.NET MAUI Blazor与Vue的混合开发

.NET MAUI Blazor

使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。

前期准备:注册高德开发者并创建 key

登录控制台

登录 高德开放平台控制台,如果没有开发者账号,请 注册开发者。

在这里插入图片描述

创建 key

进入应用管理,创建新应用,新应用中添加 key,服务平台选择 Web端(JS API)。再创建一个Web服务类型的Key,用于解析初始位置地址。

在这里插入图片描述

获取 key 和密钥

创建成功后,可获取 key 和安全密钥。

在这里插入图片描述

创建项目

新建.NET MAUI Blazor项目,命名AMap

创建JS API Loader

前往https://webapi.amap.com/loader.js另存js文件至项目wwwroot文件夹

在这里插入图片描述

在wwwroot创建amap_index.html文件,将loader.js引用到页面中。创建_AMapSecurityConfig对象并设置安全密钥。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
    <title>AmapApp</title>
    <base href="/" />
    <link href="css/app2.css" rel="stylesheet" />
</head>

<body>

    <div class="status-bar-safe-area"></div>

    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.webview.js" autostart="false"></script>
    <script src="lib/amap/loader.js"></script>
    <script type="text/javascript">
        window._AMapSecurityConfig = {
            securityJsCode: "764832459a38e824a0d555b62d8ec1f0",
        };
    </script>

</body>

</html>


配置权限

打开Android端AndroidManifest.xml文件

在这里插入图片描述

添加权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

打开Info.plist文件,添加权限描述信心

在这里插入图片描述

<key>NSLocationWhenInUseUsageDescription</key>
<string>允许使用设备的GPS更新您的位置信息。</string>

创建定义

创建Position,Poi,Location等类型,用于描述位置信息。由于篇幅这里不展开介绍。

创建模型

创建一个MainPageViewModel类,用于处理页面逻辑。代码如下:

public class MainPageViewModel : ObservableObject
{
    public event EventHandler<FinishedChooiseEvenArgs> OnFinishedChooise;
    private static AsyncLock asyncLock = new AsyncLock();
    public static RateLimitedAction throttledAction = Debouncer.Debounce(null, TimeSpan.FromMilliseconds(1500), leading: false, trailing: true);
    public MainPageViewModel()
    {
        Search = new Command(SearchAction);
        Done = new Command(DoneAction);
        Remove = new Command(RemoveAction);
    }

    private void RemoveAction(object obj)
    {
        this.Address=null;
        this.CurrentLocation=null;
        OnFinishedChooise?.Invoke(this, new FinishedChooiseEvenArgs(Address, CurrentLocation));
    }

    private void DoneAction(object obj)
    {
        OnFinishedChooise?.Invoke(this, new FinishedChooiseEvenArgs(Address, CurrentLocation));

    }

    private void SearchAction(object obj)
    {
        Init();
    }

    public async void Init()
    {
        var location = await GeoLocationHelper.GetNativePosition();
        if (location==null)
        {
            return;
        }
        var amapLocation = new Location.Location()
        {
            Latitude=location.Latitude,
            Longitude=location.Longitude
        };
        CurrentLocation=amapLocation;

    }

    private Location.Location _currentLocation;

    public Location.Location CurrentLocation
    {
        get { return _currentLocation; }
        set
        {

            if (_currentLocation != value)
            {
                if (value!=null &&_currentLocation!=null&&Location.Location.CalcDistance(value, _currentLocation)<100)
                {
                    return;
                }

                _currentLocation = value;
                OnPropertyChanged();
            }
        }
    }

    private string _address;

    public string Address
    {
        get { return _address; }
        set
        {
            _address = value;
            OnPropertyChanged();
        }
    }


    private ObservableCollection<Poi> _pois;

    public ObservableCollection<Poi> Pois
    {
        get { return _pois; }
        set
        {
            _pois = value;
            OnPropertyChanged();
        }
    }

    private Poi _selectedPoi;

    public Poi SelectedPoi
    {
        get { return _selectedPoi; }
        set
        {
            _selectedPoi = value;
            OnPropertyChanged();

        }
    }


    public Command Search { get; set; }
    public Command Done { get; set; }
    public Command Remove { get; set; }

}

注意这里的Init方法,用于初始化位置。

GeoLocationHelper.GetNativePosition()方法用于从你设备的GPS模块,获取当前位置。它调用的是Microsoft.Maui.Devices.Sensors提供的设备传感器访问功能
,详情可参考官方文档地理位置 - .NET MAUI

创建地图组件

创建Blazor页面AMapPage.razor以及AMapPage.razor.js

在AMapPage.razor中引入

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (!firstRender)
        return;
    await JSRuntime.InvokeAsync<IJSObjectReference>(
   "import", "./AMapPage.razor.js");
    await Refresh();
    await JSRuntime.InvokeVoidAsync("window.initObjRef", this.objRef);
}

razor页面的 @Code 代码段中,放置MainPageViewModel属性,以及一个DotNetObjectReference对象,用于在JS中调用C#方法。

@code {
    [Parameter]
    public MainPageViewModel MainPageViewModel { get; set; }
    private DotNetObjectReference<AMapPage> objRef;


    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    private async Task Refresh()
    {

        ...
    }

在AMapPage.razor.js我们加载地图,并设置地图的中心点。和一些地图挂件。此外,我们还需要监听地图的中心点变化,更新中心点。 这些代码可以从官方示例中复制。(https://lbs.amap.com/demo/javascript-api-v2/example/map/map-moving)。

console.info("start load")
window.viewService = {
    map: null,
    zoom: 13,
    amaplocation: [116.397428, 39.90923],
    SetAmapContainerSize: function (width, height) {
        console.info("setting container size")

        var div = document.getElementById("container");
        div.style.height = height + "px";

    },
    SetLocation: function (longitude, latitude) {
        console.info("setting loc", longitude, latitude)
        window.viewService.amaplocation = [longitude, latitude];
        if (window.viewService.map) {
            window.viewService.map.setZoomAndCenter(window.viewService.zoom, window.viewService.amaplocation);

            console.info("set loc", window.viewService.zoom, window.viewService.map)
        }
    },
    isHotspot: true

}
AMapLoader.load({ //首次调用 load
    key: '0896cedc056413f83ca0aee5b029c65d',//首次load key为必填
    version: '2.0',
    plugins: ['AMap.Scale', 'AMap.ToolBar', 'AMap.InfoWindow', 'AMap.PlaceSearch']
}).then((AMap) => {
    console.info("loading..")
    var opt = {
        resizeEnable: true,
        center: window.viewService.amaplocation,
        zoom: window.viewService.zoom,
        isHotspot: true
    }
    var map = new AMap.Map('container', opt);
    console.info(AMap, map, opt)

    map.addControl(new AMap.Scale())
    map.addControl(new AMap.ToolBar())
    window.viewService.marker = new AMap.Marker({
        position: map.getCenter()
    })
    map.add(window.viewService.marker);
    var placeSearch = new AMap.PlaceSearch();  //构造地点查询类
    var infoWindow = new AMap.InfoWindow({});
    map.on('hotspotover', function (result) {
        placeSearch.getDetails(result.id, function (status, result) {
            if (status === 'complete' && result.info === 'OK') {
                onPlaceSearch(result);
            }
        });
    });

    map.on('moveend', onMapMoveend);
    // map.on('zoomend', onMapMoveend);
    //回调函数

    window.viewService.map = map;

    function onMapMoveend() {
        var zoom = window.viewService.map.getZoom(); //获取当前地图级别
        var center = window.viewService.map.getCenter(); //获取当前地图中心位置
        if (window.viewService.marker) {
            window.viewService.marker.setPosition(center);

        }
        window.objRef.invokeMethodAsync('OnMapMoveend', center);


    }
    function onPlaceSearch(data) { //infoWindow.open(map, result.lnglat);
        var poiArr = data.poiList.pois;
        if (poiArr[0]) {
            var location = poiArr[0].location;
            infoWindow.setContent(createContent(poiArr[0]));
            infoWindow.open(window.viewService.map, location);
        }
    }
    function createContent(poi) {  //信息窗体内容
        var s = [];
        s.push('<div class="info-title">' + poi.name + '</div><div class="info-content">' + "地址:" + poi.address);
        s.push("电话:" + poi.tel);
        s.push("类型:" + poi.type);
        s.push('<div>');
        return s.join("<br>");
    }


    console.info("loaded")

}).catch((e) => {
    console.error(e);
});
window.initObjRef = function (objRef) {
    window.objRef = objRef;
}

地图中心点改变时,我们需要使用window.objRef.invokeMethodAsync('OnMapMoveend', center);从JS runtime中通知到C#代码。

同时,在AMapPage.razor中配置一个方法,用于接收从JS runtime发来的回调通知。
在此赋值CurrentLocation属性。


[JSInvokable]
public async Task OnMapMoveend(dynamic location)
{
    await Task.Run(() =>
     {
         var locationArray = JsonConvert.DeserializeObject<double[]>(location.ToString());
         MainPageViewModel.CurrentLocation=new Location.Location()
             {
                 Longitude=locationArray[0],
                 Latitude =locationArray[1]
             };
     });
}

同时监听CurrentLocation属性的值,一旦发生变化,则调用JS runtime中的viewService.SetLocation方法,更新地图中心点。

protected override async Task OnInitializedAsync()
{
    MainPageViewModel.PropertyChanged +=  async (o, e) =>
    {
        if (e.PropertyName==nameof(MainPageViewModel.CurrentLocation))
        {
            if (MainPageViewModel.CurrentLocation!=null)
            {
                var longitude = MainPageViewModel.CurrentLocation.Longitude;
                var latitude = MainPageViewModel.CurrentLocation.Latitude;
                await JSRuntime.InvokeVoidAsync("viewService.SetLocation", longitude, latitude);
            }
        }


    };

}

在MainPageViewModel类中,我们添加一个PropertyChanged事件,用于监听CurrentLocation属性的改变。

当手指滑动地图触发位置变化,导致CurrentLocation属性改变时,将当前的中心点转换为具体的地址。这里使用了高德逆地理编码API服务(https://restapi.amap.com/v3/geocode/regeo)解析CurrentLocation的值, 还需使用了防抖策略,避免接口的频繁调用。


public MainPageViewModel()
{
    PropertyChanged+=MainPageViewModel_PropertyChanged;
    ...
}



private async void MainPageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    if (e.PropertyName == nameof(CurrentLocation))
    {
        if (CurrentLocation!=null)
        {

            // 使用防抖
            using (await asyncLock.LockAsync())
            {

                var amapLocation = new Location.Location()
                {
                    Latitude=CurrentLocation.Latitude,
                    Longitude=CurrentLocation.Longitude
                };
                var amapInverseHttpRequestParamter = new AmapInverseHttpRequestParamter()
                {
                    Locations= new Location.Location[] { amapLocation }
                };
                ReGeocodeLocation reGeocodeLocation = null;
                try
                {
                    reGeocodeLocation = await amapHttpRequestClient.InverseAsync(amapInverseHttpRequestParamter);
                }
                catch (Exception ex)
                {

                    Console.WriteLine(ex.ToString());
                }

                throttledAction.Update(() =>
                {
                    MainThread.BeginInvokeOnMainThread(() =>
                    {
                        CurrentLocation=amapLocation;
                        if (reGeocodeLocation!=null)
                        {
                            Address = reGeocodeLocation.Address;
                            Pois=new ObservableCollection<Poi>(reGeocodeLocation.Pois);

                        }
                    });
                });
                throttledAction.Invoke();
            }
        }
    }
}

至此我们完成了地图组件的基本功能。

创建交互逻辑

在MainPage.xaml中,创建一个选择器按钮,以及一个卡片模拟选择器按钮点击后的弹窗。


<Button Clicked="Button_Clicked"
        Grid.Row="1"
        x:Name="SelectorButton"
        HorizontalOptions="Center"
        VerticalOptions="Center"
        Text="{Binding Address, TargetNullValue=请选择地点}"></Button>


<Border StrokeShape="RoundRectangle 10"
    Grid.RowSpan="2"
    x:Name="SelectorPopup"
    IsVisible="False"
    Margin="5,50"
    MinimumHeightRequest="500">

    <Grid Padding="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label FontSize="Large"
                    Margin="10, 10, 10, 0"
                    FontAttributes="Bold"
                    Text="选择地点"></Label>
            <HorizontalStackLayout Grid.Column="1"
                                    HorizontalOptions="End">
                <Button Text="删除"
                        Margin="5,0"
                        Command="{Binding Remove}"></Button>
                <Button Text="完成"
                        Margin="5,0"
                        Command="{Binding Done}"></Button>
            </HorizontalStackLayout>
        </Grid>

        <Grid Grid.Row="1"
                Margin="10, 10, 10, 0">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label HorizontalTextAlignment="Center"
                    VerticalOptions="Center"
                    x:Name="ContentLabel"
                    Text="{Binding Address}"></Label>
            <Border IsVisible="False"
                    Grid.RowSpan="2"
                    x:Name="ContentFrame">
                <Entry Text="{Binding Address, Mode=TwoWay}"
                        Placeholder="请输入地址, 按Enter键完成"
                        Completed="Entry_Completed"
                        Unfocused="Entry_Unfocused"
                        ClearButtonVisibility="WhileEditing"></Entry>
            </Border>
            <Border x:Name="ContentButton"
                    Grid.Row="1"
                    HorizontalOptions="Center"
                    VerticalOptions="Center">
                <Label>
                    <Label.FormattedText>
                        <FormattedString>
                            <Span FontFamily="FontAwesome"
                                    Text="&#xf044;"></Span>
                            <Span Text=" 修改"></Span>
                        </FormattedString>
                    </Label.FormattedText>

                </Label>
                <Border.GestureRecognizers>
                    <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped">
                    </TapGestureRecognizer>
                </Border.GestureRecognizers>
            </Border>
        </Grid>
        <BlazorWebView Grid.Row="2"
                        Margin="-10, 0"
                        x:Name="mainMapBlazorWebView"
                        HostPage="wwwroot/amap_index.html">
            <BlazorWebView.RootComponents>
                <RootComponent Selector="#app"
                                x:Name="rootComponent"
                                ComponentType="{x:Type views:AMapPage}" />
            </BlazorWebView.RootComponents>
        </BlazorWebView>
    </Grid>
</Border>

在这里插入图片描述

最终效果如下:

在这里插入图片描述

项目地址

Github:maui-samples

高德地图 key 和 安全密钥 的使用 高德地图 key 和 安全密钥 阅读详情

相关推荐

MAUI_SDK_API

MTK 功能机平台操作系统API介绍,包括Applib,Base,Connectivety等接口介绍文档

vue中引入高德地图

vue中引入高德地图

qq_42740298的博客 1333

OpenCV13-图像噪声:椒盐噪声和高斯噪声

考虑到椒盐噪声会在图像中的任何一个位置随机产生,因此对于椒盐噪声的生成,需要使用OpenCV中能够产生随机数的函数。OpenCV中也没有专门为图像添加高斯噪声的函数,对早在图像中添加椒盐噪声的过程,可以根据需求利用能够产生随机数的函数来完成在图像中添加高斯噪声的任务。椒盐噪声又称作脉冲噪声,他会随机改变图像中的像素值,其样子就像是在图像上随机地撒上一些盐粒和黑椒粒,因此被称为椒盐噪声。函数能够产生均匀分布或者高斯分布的随机数,可以利用该函数产生符合高斯分布的随机数,之后在图像中加入这些随机数即可。

SHLYYY 5122

[vue]——高德地图使用

vue3.0使用高德地图正确的打开方式,带你轻松应用,少走弯路

weixin_42067873的博客 4309

信号完整性SI-PI

SI设计的主要难点在于需要综合信号的幅度、噪声、边沿、延时等影响信号质量的多种因素,并且这种因素常常相互依赖、互相影响,交叉在一起。1.1、信号过冲 (欠阻尼状态,可并联一个合适的电容):过冲会造成强烈的电磁干扰,另一方面会损伤后面的电路的输入及,甚至失效。信号完整性SI:是指电路系统中信号的质量,如果在要求的时间内,信号能不失真的从源端传输到接收端。优点:提供较慢的上升时间,减少反系量,产生更小的EMI,从而降低过冲,增加信号质量。导线之间的间距过小, 就会产生串扰,间距越小、串扰越大。

weixin_42304393的博客 4869

eLabRadio软件无线电虚实结合仿真开发平台简介

在使用仿真平台时,不要关闭设备或断开设备与PC机之间的网络连接,否则,仿真平台将无法正常工作。注:采用eNodeX设备认证方式,当出现“设备不存在”的报错时,请检查计算机IP是否和硬件设备IP处于同一网段,或者是否是先连接好网线,再开启硬件设备的。①此登录方式下,需要先建立软件与硬件的通信:在登录窗口点击【网络配置】,参照下图输入设备IP,服务器地址无需设置,设置完成后点击确认,此时登录界面无需设置账号密码;,拷贝到电脑上,使用管理员权限运行setup.exe,下一步直到安装完成,桌面会生成快捷方式。

weixin_55349105的博客 6319

X64指令手册

参考网址: ref.x86asm.net。登录后才能查看或发表评论,立即。

qq_38350702的博客 578

机器学习kaggle案例:风控评分卡模型(Give_Me_Some_Credit)

kaggle链接:https://www.kaggle.com/c/GiveMeSomeCredit ipynb文件:https://github.com/824024445/KaggleCases/blob/master/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0kaggle%E6%A1%88%E4%BE%8B%EF%BC%9A%E9%A3%8E%E6%8E%A7%...

weixin_42662126的博客 1万+

CA 周记|做一个高德地图的 iOS/Android MAUI 控件 - 前言

通过做一个高德地图的 iOS / Android MAUI 控件的示例,帮助大家了解和上手 MAUI 相关控件和基于 MAUI 的 SDK 的开发和使用。

MicrosoftReactor的博客 662

Python调用CANoe

我们可以创建CANoe应用程序对象,打开配置文件,启动模拟,发送和接收消息,并在完成后关闭CANoe应用程序。这使得我们能够使用Python自动化执行测试任务,并集成CANoe的功能到我们的Python应用程序中。CANoe是一款功能强大的汽车网络仿真和测试工具,它能够模拟和分析汽车网络通信,并提供丰富的测试功能。通过Python编程语言,我们可以方便地调用CANoe的API,实现自动化测试和集成CANoe的功能到我们的Python应用程序中。在CANoe中,我们可以为不同的汽车网络创建配置文件。

AzqLinux的博客 1287

手把手教你学Simulink--基础电机控制场景实例:基于Simulink的无刷直流电机六步换相仿真

摘要:本文详细介绍了基于Simulink的无刷直流电机(BLDC)六步换相仿真方法。文章首先阐述了BLDC六步换相控制的原理,包括霍尔传感器定位、六步换相逻辑和方波电流驱动三大支柱。然后通过电动工具(角磨机)应用场景,展示了如何在Simulink中搭建完整的六步换相系统:从主电路构建、霍尔信号生成、Stateflow换相逻辑实现到开环电压控制。仿真结果显示该系统具有低成本优势(仅需霍尔传感器),但存在±20%转矩脉动。文章还提供了核心代码实现,包括霍尔信号生成、六步换相状态机和转矩分析脚本,并对比了六步换相

MHD0815的博客 149

[特殊字符]️ YourWeather:一个跨平台 Blazor 天气应用 Demo

是一个使用Blazor构建的跨平台天气应用 Demo。通过调用多个天气 API 接口,实现精准获取当前天气与未来预报,并支持手动选择城市地点查看天气信息。如果你正在寻找一个适合练习Blazor + 跨平台开发的小项目,绝对值得一看!无论是作为教学案例、技术练手,还是企业级架构参考,它都具备很高的实用价值。欢迎关注我的公众号“Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节。

混迹自留地 1277

在 SAP Fiori 中正确配置 Group 角色:从 PFCG 分配到首页呈现的完整链路

摘要:SAP Fiori项目中,用户登录后能否看到应用往往取决于角色配置而非前端开发。关键在于通过PFCG角色将launchpad designer中创建的tile group关联到用户角色。Catalog是应用池,group是用户首页可见的工作区。正确配置后,用户会看到角色对应的默认分组,同时保留个性化调整能力。项目实施中常见问题是应用开发完成但未正确配置group与角色关联,导致业务用户无法在首页看到应用入口。(150字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 164

一个开源的 Blazor 跨平台入门级实战项目

该项目已收录到C#/.NET/.NET Core优秀项目和框架精选中,关注优秀项目和框架精选能让你及时了解C#、.NET和.NET Core领域的最新动态和最佳实践,提高开发工作效率和质量。坑已挖,欢迎大家踊跃提交PR推荐或自荐(让优秀的项目和框架不被埋没🤞)。Rcl(Razor类库),通过天气API获取当前天气和天气预报,具有多个天气源(高德地图、和风天气 、心知天气等),也可以选择指定位置的天气。支持多个天气源,包括高德地图、OpenWeather、和风天气、心知天气、VisualCrossing。

weixin_37053426的博客 74

Open3D——点云构建Delaunay三角网【2026最新版】

点云构建Delaunay三角网

点云侠的博客 8367

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

上一篇: [.NET项目实战] Elsa开源工作流组件应用(三):实战演练
下一篇: [MAUI]模仿哔哩哔哩的一键三连
林晓lx
林晓lx 2017年优快云移动跨平台大赛优秀奖获得者 2017年优快云移动跨平台大赛优秀奖获得者
博客等级 码龄15年 3761粉丝 123原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林晓lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值