1. 运行截图

演示地址

2. 在文件夹wwwroot/lib,添加geolocation子文件夹,添加geolocation.js文件

本组件主要是调用浏览器两个API实现基于浏览器的定位功能,现代桌面和移动端都支持.包括MAUI Blazor

  1. navigator.geolocation.getCurrentPosition
  2. navigator.geolocation.watchPosition

2.1 获取定位

其中持续定位watchPosition方法会通过wrapper.invokeMethodAsync('UpdateWatchID', id)返回监听器ID到c#存起来,移除的监听器和注销时候用到.

js代码
  1. export function getLocation(wrapper, getPosition = true) {
  2. console.log('start ' + (getPosition ? 'getLocation' : 'watchPosition'));
  3. var currentDistance = 0.0;
  4. var totalDistance = 0.0;
  5. var lastLat;
  6. var lastLong;
  7. var status;
  8. if (getPosition) getCurrentPosition(); else watchPosition();
  9. Number.prototype.toRadians = function () {
  10. return this * Math.PI / 180;
  11. }
  12. function distance(latitude1, longitude1, latitude2, longitude2) {
  13. // R is the radius of the earth in kilometers
  14. var R = 6371;
  15. var deltaLatitude = (latitude2 - latitude1).toRadians();
  16. var deltaLongitude = (longitude2 - longitude1).toRadians();
  17. latitude1 = latitude1.toRadians(), latitude2 = latitude2.toRadians();
  18. var a = Math.sin(deltaLatitude / 2) *
  19. Math.sin(deltaLatitude / 2) +
  20. Math.cos(latitude1) *
  21. Math.cos(latitude2) *
  22. Math.sin(deltaLongitude / 2) *
  23. Math.sin(deltaLongitude / 2);
  24. var c = 2 * Math.atan2(Math.sqrt(a),
  25. Math.sqrt(1 - a));
  26. var d = R * c;
  27. return d;
  28. }
  29. function updateStatus(message) {
  30. status = message;
  31. wrapper.invokeMethodAsync('UpdateStatus', message);
  32. }
  33. function watchPosition() {
  34. if (navigator.geolocation) {
  35. status = "HTML5 Geolocation is supported in your browser.";
  36. updateStatus(status);
  37. var id = navigator.geolocation.watchPosition(updateLocation,
  38. handleLocationError,
  39. { maximumAge: 20000 });
  40. wrapper.invokeMethodAsync('UpdateWatchID', id);
  41. }
  42. }
  43. function getCurrentPosition() {
  44. if (navigator.geolocation) {
  45. updateStatus("HTML5 Geolocation is supported in your browser.");
  46. navigator.geolocation.getCurrentPosition(updateLocation,
  47. handleLocationError);
  48. }
  49. }
  50. function updateLocation(position) {
  51. var latitude = position.coords.latitude;
  52. var longitude = position.coords.longitude;
  53. var accuracy = position.coords.accuracy;
  54. var timestamp = position.timestamp;
  55. // sanity test... don't calculate distance if accuracy
  56. // value too large
  57. if (accuracy >= 500) {
  58. updateStatus("Need more accurate values to calculate distance.");
  59. }
  60. // calculate distance
  61. currentDistance = 0.0;
  62. if ((lastLat != null) && (lastLong != null)) {
  63. currentDistance = distance(latitude, longitude, lastLat, lastLong);
  64. totalDistance += currentDistance;
  65. }
  66. lastLat = latitude;
  67. lastLong = longitude;
  68. updateStatus("Location successfully updated.");
  69. console.log("updateLocation end");
  70. var geolocationitem = {
  71. "Status": status,
  72. "Latitude": latitude,
  73. "Longitude": longitude,
  74. "Accuracy": accuracy,
  75. "Timestamp": timestamp,
  76. "CurrentDistance": currentDistance,
  77. "TotalDistance": totalDistance,
  78. "LastLat": lastLat,
  79. "LastLong": lastLong,
  80. };
  81. wrapper.invokeMethodAsync('GetResult', geolocationitem);
  82. }
  83. function handleLocationError(error) {
  84. switch (error.code) {
  85. case 0:
  86. updateStatus("There was an error while retrieving your location: " + error.message);
  87. break;
  88. case 1:
  89. updateStatus("The user prevented this page from retrieving a location.");
  90. break;
  91. case 2:
  92. updateStatus("The browser was unable to determine your location: " + error.message);
  93. break;
  94. case 3:
  95. updateStatus("The browser timed out before retrieving the location.");
  96. break;
  97. }
  98. }
  99. }

2.2 组件页面点击停止持续定位,把监听器ID传入移除的监听器.

  1. export function clearWatchLocation(wrapper,id) {
  2. //扩展阅读:移除的监听器
  3. //id = navigator.geolocation.watchPosition(success, error, options);
  4. console.log('clearWatch ' + id);
  5. navigator.geolocation.clearWatch(id);
  6. wrapper.invokeMethodAsync('UpdateStatus', 'clearWatch ok');
  7. }

3. 打开Components文件夹 , 新建Geolocation文件夹,新建三个文件

3.1 GeolocationItem.cs 定位数据类

cs代码
  1. using System;
  2. using System.ComponentModel;
  3. namespace Blazor100.Components
  4. {
  5. /// <summary>
  6. /// 定位数据类
  7. /// </summary>
  8. public class Geolocationitem
  9. {
  10. /// <summary>
  11. /// 状态
  12. /// </summary>
  13. /// <returns></returns>
  14. [DisplayName("状态")]
  15. public string? Status { get; set; }
  16. /// <summary>
  17. /// 纬度
  18. /// </summary>
  19. /// <returns></returns>
  20. [DisplayName("纬度")]
  21. public decimal Latitude { get; set; }
  22. /// <summary>
  23. /// 经度
  24. /// </summary>
  25. /// <returns></returns>
  26. [DisplayName("经度")]
  27. public decimal Longitude { get; set; }
  28. /// <summary>
  29. /// 准确度(米)<para></para>
  30. /// 将以m指定维度和经度值与实际位置的差距,置信度为95%.
  31. /// </summary>
  32. [DisplayName("准确度(米)")]
  33. public decimal Accuracy { get; set; }
  34. /// <summary>
  35. /// 时间戳
  36. /// </summary>
  37. [DisplayName("时间戳")]
  38. public long Timestamp { get; set; }
  39. /// <summary>
  40. /// 时间
  41. /// </summary>
  42. [DisplayName("时间")]
  43. public DateTime LastUpdateTime { get => UnixTimeStampToDateTime(Timestamp); }
  44. /// <summary>
  45. /// 移动距离
  46. /// </summary>
  47. [DisplayName("移动距离")]
  48. public decimal CurrentDistance { get; set; } = 0.0M;
  49. /// <summary>
  50. /// 总移动距离
  51. /// </summary>
  52. [DisplayName("总移动距离")]
  53. public decimal TotalDistance { get; set; } = 0.0M;
  54. /// <summary>
  55. /// 最后一次获取到的纬度
  56. /// </summary>
  57. [DisplayName("最后一次获取到的纬度")]
  58. public decimal LastLat { get; set; }
  59. /// <summary>
  60. /// 最后一次获取到的经度
  61. /// </summary>
  62. [DisplayName("最后一次获取到的经度")]
  63. public decimal LastLong { get; set; }
  64. /// <summary>
  65. ///
  66. /// </summary>
  67. /// <param name="unixTimeStamp"></param>
  68. /// <returns></returns>
  69. public static DateTime UnixTimeStampToDateTime(long unixTimeStamp)
  70. {
  71. // Unix timestamp is seconds past epoch
  72. System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
  73. dtDateTime = dtDateTime.AddMilliseconds(unixTimeStamp).ToLocalTime();
  74. return dtDateTime;
  75. }
  76. }
  77. }

3.1 Geolocation.razor 组件razor

  1. @implements IAsyncDisposable
  2. @namespace Blazor100.Components
  3. <div @ref="GeolocationElement">
  4. @if (ShowButtons)
  5. {
  6. if (WatchID == null)
  7. {
  8. <button class="btn btn-primary" type="button" onclick="@GetLocation">@GetLocationButtonText</button>
  9. <button class="btn btn-primary" type="button" onclick="@WatchPosition">@WatchPositionButtonText</button>
  10. }
  11. else
  12. {
  13. <button class="btn btn-primary" type="button" onclick="@ClearWatch">@ClearWatchPositionButtonText</button>}
  14. }
  15. </div>

3.2 Geolocation.razor.cs 组件代码

cs代码
  1. using Microsoft.AspNetCore.Components;
  2. using Microsoft.JSInterop;
  3. using System.Diagnostics.CodeAnalysis;
  4. namespace Blazor100.Components;
  5. /// <summary>
  6. /// Geolocation 组件基类
  7. /// <para></para>
  8. /// 扩展阅读:Chrome中模拟定位信息,清除定位信息<para></para>
  9. /// https://blog.csdn.net/u010844189/article/details/81163438
  10. /// </summary>
  11. public partial class Geolocation
  12. {
  13. [Inject] IJSRuntime? JS { get; set; }
  14. /// <summary>
  15. /// 获得/设置 定位
  16. /// </summary>
  17. [Parameter]
  18. [NotNull]
  19. public string? GeolocationInfo { get; set; }
  20. /// <summary>
  21. /// 获得/设置 获取位置按钮文字 默认为 获取位置
  22. /// </summary>
  23. [Parameter]
  24. [NotNull]
  25. public string? GetLocationButtonText { get; set; } = "获取位置";
  26. /// <summary>
  27. /// 获得/设置 获取持续定位监听器ID
  28. /// </summary>
  29. [Parameter]
  30. public long? WatchID { get; set; }
  31. /// <summary>
  32. /// 获得/设置 获取移动距离追踪按钮文字 默认为 移动距离追踪
  33. /// </summary>
  34. [Parameter]
  35. [NotNull]
  36. public string? WatchPositionButtonText { get; set; } = "移动距离追踪";
  37. /// <summary>
  38. /// 获得/设置 获取停止追踪按钮文字 默认为 停止追踪
  39. /// </summary>
  40. [Parameter]
  41. [NotNull]
  42. public string? ClearWatchPositionButtonText { get; set; } = "停止追踪";
  43. /// <summary>
  44. /// 获得/设置 是否显示默认按钮界面
  45. /// </summary>
  46. [Parameter]
  47. public bool ShowButtons { get; set; } = true;
  48. /// <summary>
  49. ///
  50. /// </summary>
  51. protected ElementReference GeolocationElement { get; set; }
  52. /// <summary>
  53. /// 获得/设置 定位结果回调方法
  54. /// </summary>
  55. [Parameter]
  56. public Func<Geolocationitem, Task>? OnResult { get; set; }
  57. /// <summary>
  58. /// 获得/设置 状态更新回调方法
  59. /// </summary>
  60. [Parameter]
  61. public Func<string, Task>? OnUpdateStatus { get; set; }
  62. private IJSObjectReference? module;
  63. private DotNetObjectReference<Geolocation>? InstanceGeo { get; set; }
  64. protected override async Task OnAfterRenderAsync(bool firstRender)
  65. {
  66. try
  67. {
  68. if (firstRender)
  69. {
  70. module = await JS!.InvokeAsync<IJSObjectReference>("import", "./lib/geolocation/geolocation.js");
  71. InstanceGeo = DotNetObjectReference.Create(this);
  72. }
  73. }
  74. catch (Exception e)
  75. {
  76. if (OnError != null) await OnError.Invoke(e.Message);
  77. }
  78. }
  79. async ValueTask IAsyncDisposable.DisposeAsync()
  80. {
  81. if (module is not null)
  82. {
  83. //await module.InvokeVoidAsync("destroy");
  84. InstanceGeo!.Dispose();
  85. await module.DisposeAsync();
  86. }
  87. }
  88. /// <summary>
  89. /// 获取定位
  90. /// </summary>
  91. public virtual async Task GetLocation()
  92. {
  93. try
  94. {
  95. await module!.InvokeVoidAsync("getLocation", InstanceGeo);
  96. }
  97. catch (Exception e)
  98. {
  99. if (OnError != null) await OnError.Invoke(e.Message);
  100. }
  101. }
  102. /// <summary>
  103. /// 持续定位
  104. /// </summary>
  105. public virtual async Task WatchPosition()
  106. {
  107. try
  108. {
  109. await module!.InvokeVoidAsync("getLocation", InstanceGeo, false);
  110. }
  111. catch (Exception e)
  112. {
  113. if (OnError != null) await OnError.Invoke(e.Message);
  114. }
  115. }
  116. /// <summary>
  117. /// 持续定位
  118. /// </summary>
  119. public virtual async Task ClearWatch()
  120. {
  121. await module!.InvokeVoidAsync("clearWatchLocation", InstanceGeo, WatchID);
  122. WatchID = null;
  123. }
  124. /// <summary>
  125. /// 定位完成回调方法
  126. /// </summary>
  127. /// <param name="geolocations"></param>
  128. /// <returns></returns>
  129. [JSInvokable]
  130. public async Task GetResult(Geolocationitem geolocations)
  131. {
  132. try
  133. {
  134. if (OnResult != null) await OnResult.Invoke(geolocations);
  135. }
  136. catch (Exception e)
  137. {
  138. if (OnError != null) await OnError.Invoke(e.Message);
  139. }
  140. }
  141. /// <summary>
  142. /// 获得/设置 错误回调方法
  143. /// </summary>
  144. [Parameter]
  145. public Func<string, Task>? OnError { get; set; }
  146. /// <summary>
  147. /// 状态更新回调方法
  148. /// </summary>
  149. /// <param name="status"></param>
  150. /// <returns></returns>
  151. [JSInvokable]
  152. public async Task UpdateStatus(string status)
  153. {
  154. if (OnUpdateStatus != null) await OnUpdateStatus.Invoke(status);
  155. }
  156. /// <summary>
  157. /// 监听器ID回调方法
  158. /// </summary>
  159. /// <param name="watchID"></param>
  160. /// <returns></returns>
  161. [JSInvokable]
  162. public Task UpdateWatchID(long watchID)
  163. {
  164. this.WatchID = watchID;
  165. return Task.CompletedTask;
  166. }
  167. }

4. Pages文件夹添加GeolocationPage.razor文件,用于演示组件调用.

4.1 GeolocationPage.razor

razor代码
  1. @page "/geolocations"
  2. <h3>定位/持续定位 Geolocation</h3>
  3. <p>@message</p>
  4. <Blazor100.Components.Geolocation OnResult="@OnResult" OnUpdateStatus="@OnUpdateStatus" OnError="@OnError" />
  5. <p>@status</p>
  6. <div class="table-container">
  7. <div class="table-toolbar">
  8. </div>
  9. <div class="table-wrapper">
  10. <table class="table is-single table-demo">
  11. <colgroup>
  12. <col>
  13. <col>
  14. <col>
  15. </colgroup>
  16. <thead>
  17. <tr>
  18. <th><div class="table-cell"><span class="table-text">纬度</span></div></th>
  19. <th><div class="table-cell"><span class="table-text">经度</span></div></th>
  20. <th><div class="table-cell"><span class="table-text">准确度(米)</span></div></th>
  21. <th><div class="table-cell"><span class="table-text">时间戳</span></div></th>
  22. <th><div class="table-cell"><span class="table-text">时间</span></div></th>
  23. </tr>
  24. </thead>
  25. <tbody>
  26. <tr>
  27. <td><div class="table-cell">@geolocations?.Latitude</div></td>
  28. <td><div class="table-cell">@geolocations?.Longitude</div></td>
  29. <td><div class="table-cell">@geolocations?.Accuracy</div></td>
  30. <td><div class="table-cell">@geolocations?.Timestamp</div></td>
  31. <td><div class="table-cell">@geolocations?.LastUpdateTime</div></td>
  32. </tr>
  33. </tbody>
  34. <thead>
  35. <tr>
  36. <th><div class="table-cell"><span class="table-text">移动距离</span></div></th>
  37. <th><div class="table-cell"><span class="table-text">总移动距离</span></div></th>
  38. <th><div class="table-cell"><span class="table-text">最后一次获取到的纬度</span></div></th>
  39. <th><div class="table-cell"><span class="table-text">最后一次获取到的经度</span></div></th>
  40. <th><div class="table-cell"><span class="table-text">状态</span></div></th>
  41. </tr>
  42. </thead>
  43. <tbody>
  44. <tr>
  45. <td><div class="table-cell">@geolocations?.CurrentDistance</div></td>
  46. <td><div class="table-cell">@geolocations?.TotalDistance</div></td>
  47. <td><div class="table-cell">@geolocations?.LastLat</div></td>
  48. <td><div class="table-cell">@geolocations?.LastLong</div></td>
  49. <td><div class="table-cell">@geolocations?.Status</div></td>
  50. </tr>
  51. </tbody>
  52. </table>
  53. </div>
  54. </div>

4.2 GeolocationPage.razor.cs

扩展阅读:Chrome中模拟定位信息,清除定位信息

  1. using Blazor100.Components;
  2. namespace Blazor100.Pages;
  3. /// <summary>
  4. /// Geolocation 地理定位/移动距离追踪
  5. /// <para></para>
  6. /// 扩展阅读:Chrome中模拟定位信息,清除定位信息<para></para>
  7. /// https://blog.csdn.net/u010844189/article/details/81163438
  8. /// </summary>
  9. public sealed partial class GeolocationPage
  10. {
  11. private string? status { get; set; }
  12. private Geolocationitem? geolocations { get; set; }
  13. private string message;
  14. private Task OnResult(Geolocationitem geolocations)
  15. {
  16. this.geolocations = geolocations;
  17. StateHasChanged();
  18. return Task.CompletedTask;
  19. }
  20. private Task OnUpdateStatus(string status)
  21. {
  22. this.status = status;
  23. StateHasChanged();
  24. return Task.CompletedTask;
  25. }
  26. private Task OnError(string message)
  27. {
  28. this.message = message;
  29. StateHasChanged();
  30. return Task.CompletedTask;
  31. }
  32. }

5. _Imports.razor加入一行引用组件的命名空间.

  1. @using Blazor100.Components

6. 首页引用组件演示页 <GeolocationPage /> 或者 Shared/NavMenu.razor 添加导航

  1. <div class="nav-item px-3">
  2. <NavLink class="nav-link" href="geolocations">
  3. 定位
  4. </NavLink>
  5. </div>

7. F5运行程序

至此,使用JS隔离制作定位/持续定位组件大功告成! Happy coding!

Blazor组件自做系列

Blazor组件自做一 : 使用JS隔离封装viewerjs库

Blazor组件自做二 : 使用JS隔离制作手写签名组件

Blazor组件自做三 : 使用JS隔离封装ZXing扫码

Blazor组件自做四: 使用JS隔离封装signature_pad签名组件

Blazor组件自做五: 使用JS隔离封装Google地图

Blazor组件自做六: 使用JS隔离封装Baidu地图

Blazor组件自做七: 使用JS隔离制作定位/持续定位组件

Blazor组件自做八: 使用JS隔离封装屏幕键盘kioskboard.js组件<03-27>

项目源码 Github | Gitee

Blazor组件自做七 : 使用JS隔离制作定位/持续定位组件的更多相关文章

  1. Blazor组件自做二 : 使用JS隔离制作手写签名组件

    Blazor组件自做二 : 使用JS隔离制作手写签名组件 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazor组件自做一 : 使用JS隔离 ...

  2. Blazor组件自做八 : 使用JS隔离封装屏幕键盘kioskboard.js组件

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加kioskboard子文件夹,添加kioskboards.js文件 2.1 常规操作,懒加载js库, export function ...

  3. Blazor组件自做一 : 使用JS隔离封装viewerjs库

    Viewer.js库是一个实用的js库,用于图片浏览,放大缩小翻转幻灯片播放等实用操作 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazo ...

  4. Blazor组件自做三 : 使用JS隔离封装ZXing扫码

    Blazor组件自做三 : 使用JS隔离封装ZXing扫码 本文基础步骤参考前两篇文章 Blazor组件自做一 : 使用JS隔离封装viewerjs库 Blazor组件自做二 : 使用JS隔离制作手写 ...

  5. Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件

    运行截图 演示地址 响应式演示 感谢szimek写的棒棒的signature_pad.js项目, 来源: https://github.com/szimek/signature_pad 正式开始 1. ...

  6. Blazor组件自做五 : 使用JS隔离封装Google地图

    Blazor组件自做五: 使用JS隔离封装Google地图 运行截图 演示地址 正式开始 1. 谷歌地图API 谷歌开发文档 开始学习 Maps JavaScript API 的最简单方法是查看一个简 ...

  7. Blazor组件自做六 : 使用JS隔离封装Baidu地图

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加baidu子文件夹,添加baidumap.js文件 2.1 跟上一篇类似,用代码方式异步加载API,脚本生成新的 body > ...

  8. 一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app

    一步一步教你用 Vue.js + Vuex 制作专门收藏微信公众号的 app 转载 作者:jrainlau 链接:https://segmentfault.com/a/1190000005844155 ...

  9. (day67)组件、组件化、组件传参、JS补充(命名转换、for in 、数据转换)、css取消选中和模拟小手

    目录 一.初识组件 (一)概念 (二)特点 二.组件的分类 (一)根组件 (二)局部组件 (三)全局组件 二.数据组件化 三.组件的传参 (一)父传子 (二)子传父 四.JS补充 (一)与html命名 ...

随机推荐

  1. SQL从零到迅速精通【实用函数(3)】

    1.LOWER()函数 使用LOWER函数将字符串中所有字幕字符转换为小写,输入语句如下. SELECT LOWER('BEAUTIFUL'),LOWER('Well'); 2.UPPER()函数 S ...

  2. 阿里云CND加速

    1: :2: 3: 4: 5: 6: 7:将解析信息如实添加 8:如果报错添加 CNAME 记录提示和 A 记录冲突,也就是说如果你要添加 CDN 全站加速,域名解析那里就不能再有 A 记录了, 只有 ...

  3. laravel 登录+中间件拦截+红柚小说网小说采集+图片本地化

    .......................登录界面 <!doctype html> <html lang="en"> <head> < ...

  4. npm vue路由配置

    npm vue路由 复习:1.README.md文件:保存如何使用的命令 (1)     npm install:拷项目时可以不拷node_modules文件,运行该命令时,会自动下载node_mod ...

  5. 基于python 实现KNN 算法

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/11/7 14:50 # @Author : gylhaut # @Site ...

  6. Go 循环语句

    Go 循环语句 一.概述 在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句. 循环程序的流程图: Go 语言提供了以下几种类型循环处理语句: 循环类型 描述 for 循环 ...

  7. 字节跳动社会招聘&内推-帮助你更快加入字节跳动

    字节跳动社会招聘&内推「[内推码]:4J8CA3W」 内推时间:一直有效 招聘对象:根据招聘要求而定 社招投递链接: https://job.toutiao.com/s/de5teaA 应届生 ...

  8. 容器化 | 在 K8s 上部署 RadonDB MySQL Operator 和集群

    作者:程润科 数据库研发工程师 编辑:张莉梅 高级文档工程师 视频:钱芬 高级测试工程师 本文将演示在 Kubernetes 上部署 RadonDB MySQL Kubernetes 2.X(Oper ...

  9. 面试之Java String 编码相关

    实话说,作为一个多年Java老年程序员,直到近来,在没有决心花时间搞清楚Java String的编码相关问题之前, 自己也都还是似懂非懂,一脸懵逼的.设想如果在面试中,有同学能够条理清晰的回答下面的问 ...

  10. Java中CAS 基本实现原理 和 AQS 原理

    一.前言了解CAS,首先要清楚JUC,那么什么是JUC呢?JUC就是java.util.concurrent包的简称.它有核心就是CAS与AQS.CAS是java.util.concurrent.at ...