在 Blazor SPA 上嵌入 Leaflet 地图

Isa*_*aac 1 leaflet blazor blazor-server-side blazor-client-side blazor-webassembly

如何在 Blazor SPA 上嵌入 Leaflet 地图、使用 JSInterop、应定义哪些对象以及如何将表示在地图上单击的位置的数据从 JavaScript 传递到 Blazor

Isa*_*aac 9

注意:下面的示例代码是在独立的 WebAssembly Blazor 应用程序中创建和测试的...

\n
\n

非静态字段、方法或属性“成员”需要对象引用

\n
\n

让我们创建对象类,其对象引用将在初始化时传递给 JavaScript 的对象。当用户点击地图上的某个位置时,会触发 JS 地图对象的点击事件,从中调用 C# 对象的 JSInvokable 方法并传递纬度和经度...

\n

GCSService.cs

\n
public class GCSService\n{\n    public GCSService() {}\n    public event Func<Task> Notify;\n    public string LatLng { get; set; }\n\n    [JSInvokableAttribute("GetLatLng")]\n    public async Task GetLatLng(string latLng)\n    {\n       LatLng = latLng;\n\n       if (Notify != null)\n       {\n           await Notify?.Invoke();\n       }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意名为 Notify 的事件委托的定义。只要从 JavaScript 更改 LatLng 属性的值,就会触发\n此事件。这允许您订阅该事件,并调用 StateHasChanged 方法来刷新 UI。

\n

索引剃刀

\n
@page "/"\n@implements IDisposable\n@inject IJSRuntime JSRuntime\n\n@if (GCS != null)\n{\n    <div>Latitude and Longitude: @GCS.LatLng</div>\n}\n<div id="mapid"></div>\n\n@code{\n    private DotNetObjectReference<GCSService> objRef;\n    private GCSService GCS;\n\n    protected override async Task OnAfterRenderAsync(bool firstRender)\n    {\n        if (firstRender)\n        {\n            await JSRuntime.InvokeAsync<object>(\n            "leafletJsFunctions.initialize", objRef);\n        }\n        base.OnAfterRender(firstRender);\n    }\n\n    protected override void OnInitialized()\n    {\n        GCS = new GCSService();\n\n        objRef = DotNetObjectReference.Create(GCS);\n\n        GCS.Notify += OnNotify;\n    }\n\n    public void Dispose()\n    {\n        GCS.Notify -= OnNotify;\n\n        objRef?.Dispose();\n    }\n\n    public async Task OnNotify()\n    {\n        await InvokeAsync(() =>\n        {\n            StateHasChanged();\n        });\n   }\n }\n
Run Code Online (Sandbox Code Playgroud)\n

将此 CSS 规则添加到 app.css 中:

\n
#mapid {\n    height: 400px;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,您的 JavaScript 对象仅在 OnAfterRenderAsync 生命周期方法中初始化一次......

\n

以下是相关的 JavaScript 代码,应放置在 index.html 文件的底部,位于 blazor.web assembly.js 的脚本元素下方

\n
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"\n          integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="\n          crossorigin="" />\n\n<!-- Make sure you put this AFTER Leaflet\'s CSS -->\n<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"\n        integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="\n        crossorigin="">\n\n</script>\n\n<script type="text/javascript">\n    window.leafletJsFunctions = {\n        initialize: function (dotnetHelper) {\n            var mymap = L.map(\'mapid\').setView([51.505, -0.09], 13);\n            L.tileLayer(\'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw\', {\n                maxZoom: 18,\n                attribution: \'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, \' +\n                    \'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, \' +\n                    \'Imagery \xc2\xa9 <a href="https://www.mapbox.com/">Mapbox</a>\',\n                id: \'mapbox/streets-v11\',\n                tileSize: 512,\n                zoomOffset: -1\n            }).addTo(mymap);\n\n            L.marker([51.5, -0.09]).addTo(mymap)\n                .bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();\n\n            L.circle([51.508, -0.11], 500, {\n                color: \'red\',\n                fillColor: \'#f03\',\n                fillOpacity: 0.5\n            }).addTo(mymap).bindPopup("I am a circle.");\n\n            L.polygon([\n                [51.509, -0.08],\n                [51.503, -0.06],\n                [51.51, -0.047]\n            ]).addTo(mymap).bindPopup("I am a polygon.");\n\n            var popup = L.popup();\n\n            function onMapClick(e) {\n                // Invoke the instance method GetLatLng, passing it the\n                // Latitude and Logitude value\n                return dotnetHelper.invokeMethodAsync(\'GetLatLng\',\n                                            e.latlng.toString());\n             }\n\n            mymap.on(\'click\', onMapClick);\n       }\n     };\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n