在 Blazor SPA 上嵌入 Leaflet 地图
Embedding a Leaflet map on a Blazor SPA
如何使用 JSInterop 在 Blazor SPA 上嵌入 Leaflet 地图,应定义哪些对象,以及如何传递表示在地图上单击的位置的数据,从 JavaScript 到 Blazor
注意:下面的示例代码是在独立的 WebAssembly Blazor 应用程序中创建和测试的...
An object reference is required for the nonstatic field, method, or property 'member'
让我们创建对象 class,其对象引用将在初始化时传递给您 JavaScript 的对象。当用户点击地图上的某个位置时,会触发JS地图对象的点击事件,从中调用C#对象的JSInvokable方法并传递经纬度...
GCSService.cs
public class GCSService
{
public GCSService() {}
public event Func<Task> Notify;
public string LatLng { get; set; }
[JSInvokableAttribute("GetLatLng")]
public async Task GetLatLng(string latLng)
{
LatLng = latLng;
if (Notify != null)
{
await Notify?.Invoke();
}
}
}
注意名为 Notify 的事件委托的定义。此事件被触发
每当 LatLng 属性 的值从 JavaScript 更改时。这允许您订阅事件,并调用 StateHasChanged 方法以刷新 UI.
Index.razor
@page "/"
@implements IDisposable
@inject IJSRuntime JSRuntime
@if (GCS != null)
{
<div>Latitude and Longitude: @GCS.LatLng</div>
}
<div id="mapid"></div>
@code{
private DotNetObjectReference<GCSService> objRef;
private GCSService GCS;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeAsync<object>(
"leafletJsFunctions.initialize", objRef);
}
base.OnAfterRender(firstRender);
}
protected override void OnInitialized()
{
GCS = new GCSService();
objRef = DotNetObjectReference.Create(GCS);
GCS.Notify += OnNotify;
}
public void Dispose()
{
GCS.Notify -= OnNotify;
objRef?.Dispose();
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
}
将此 CSS 规则添加到 app.css:
#mapid {
height: 400px;
}
请注意,您的 JavaScript 对象仅从 OnAfterRenderAsync 生命周期方法初始化一次...
这里是相关的 JavaScript 代码,应该放在 index.html 文件的底部,在 blazor.webassembly.js
的脚本元素下面
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin="">
</script>
<script type="text/javascript">
window.leafletJsFunctions = {
initialize: function (dotnetHelper) {
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1
}).addTo(mymap);
L.marker([51.5, -0.09]).addTo(mymap)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap).bindPopup("I am a circle.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap).bindPopup("I am a polygon.");
var popup = L.popup();
function onMapClick(e) {
// Invoke the instance method GetLatLng, passing it the
// Latitude and Logitude value
return dotnetHelper.invokeMethodAsync('GetLatLng',
e.latlng.toString());
}
mymap.on('click', onMapClick);
}
};
</script>
如何使用 JSInterop 在 Blazor SPA 上嵌入 Leaflet 地图,应定义哪些对象,以及如何传递表示在地图上单击的位置的数据,从 JavaScript 到 Blazor
注意:下面的示例代码是在独立的 WebAssembly Blazor 应用程序中创建和测试的...
An object reference is required for the nonstatic field, method, or property 'member'
让我们创建对象 class,其对象引用将在初始化时传递给您 JavaScript 的对象。当用户点击地图上的某个位置时,会触发JS地图对象的点击事件,从中调用C#对象的JSInvokable方法并传递经纬度...
GCSService.cs
public class GCSService
{
public GCSService() {}
public event Func<Task> Notify;
public string LatLng { get; set; }
[JSInvokableAttribute("GetLatLng")]
public async Task GetLatLng(string latLng)
{
LatLng = latLng;
if (Notify != null)
{
await Notify?.Invoke();
}
}
}
注意名为 Notify 的事件委托的定义。此事件被触发 每当 LatLng 属性 的值从 JavaScript 更改时。这允许您订阅事件,并调用 StateHasChanged 方法以刷新 UI.
Index.razor
@page "/"
@implements IDisposable
@inject IJSRuntime JSRuntime
@if (GCS != null)
{
<div>Latitude and Longitude: @GCS.LatLng</div>
}
<div id="mapid"></div>
@code{
private DotNetObjectReference<GCSService> objRef;
private GCSService GCS;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeAsync<object>(
"leafletJsFunctions.initialize", objRef);
}
base.OnAfterRender(firstRender);
}
protected override void OnInitialized()
{
GCS = new GCSService();
objRef = DotNetObjectReference.Create(GCS);
GCS.Notify += OnNotify;
}
public void Dispose()
{
GCS.Notify -= OnNotify;
objRef?.Dispose();
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
}
将此 CSS 规则添加到 app.css:
#mapid {
height: 400px;
}
请注意,您的 JavaScript 对象仅从 OnAfterRenderAsync 生命周期方法初始化一次...
这里是相关的 JavaScript 代码,应该放在 index.html 文件的底部,在 blazor.webassembly.js
的脚本元素下面<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin="" />
<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin="">
</script>
<script type="text/javascript">
window.leafletJsFunctions = {
initialize: function (dotnetHelper) {
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
'<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1
}).addTo(mymap);
L.marker([51.5, -0.09]).addTo(mymap)
.bindPopup("<b>Hello world!</b><br />I am a popup.").openPopup();
L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap).bindPopup("I am a circle.");
L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(mymap).bindPopup("I am a polygon.");
var popup = L.popup();
function onMapClick(e) {
// Invoke the instance method GetLatLng, passing it the
// Latitude and Logitude value
return dotnetHelper.invokeMethodAsync('GetLatLng',
e.latlng.toString());
}
mymap.on('click', onMapClick);
}
};
</script>