uni-app使用瓦片实现离线地图的两种方案
<h1 data-id="heading-0">🧑💻 写在开头</h1><p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<p>最近接到一个安卓App的活儿,虽然功能上不算复杂,但因为原本没怎么做过安卓端,所以也是"摸着石头过河"。简单写一下踩过的坑和淌的水吧~</p>
<p>uni-app实现离线地图主要用 <strong>leafletjs</strong> 实现,但是因为在安卓端运行,存在渲染问题,所以还要用上 <strong>renderjs</strong>。</p>
<h2 data-id="heading-0">实现方案一:web-view</h2>
<p>因为uni-app引入第三方可以采用传统的 <code>NPM</code> 安装的方式,也可以采用引入打包完的<code>js文件</code>的方式。</p>
<p>这里采用 <code>leafletjs</code> 打包完的文件,将 <code>leafletjs</code> 放入 <code>static</code> 文件夹内。</p>
<p>在网上下载了公开的瓦片地图图片,以 <code>{z}/{x}/{y}</code> 的目录结构放入 <code>tiles</code> 文件夹中,将 <code>tiles</code> 放入 <code>static</code> 文件夹内。</p>
<p>在static文件夹下新建一个 <code>offline-map.html</code> 文件</p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;"><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>离线地图</title>
<link rel="stylesheet" href="./leaflet/leaflet.css" />
<style>
html,
body {
margin: 0;
padding: 0;
}
#map {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="./leaflet/leaflet.js"></script>
<script>
const baseUrl = './tiles/{z}/{x}/{y}.jpg';
const map = L.map('map').setView(, 15);
L.tileLayer(baseUrl, {
minZoom: 15,
maxZoom: 18,
tms: true,
attribution: 'Offline Tiles',
errorTileUrl: ''
}).addTo(map);
</script>
</body>
</html></pre>
</div>
<p>找到 <code>pages/index/index.vue</code> 文件,采用 <code>web-view</code> 引用的方式引入上述 html 文件。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// pages/index/index.vue
<template>
<view class="content">
<web-view src="/static/offline-map.html"></web-view>
</view>
</template>
<style>
.content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style></pre>
</div>
<h2 data-id="heading-1">实现方案二:renderjs</h2>
<p>仍然将 <code>leafletjs</code> 和 <code>瓦片图片文件夹tiles</code> 放入 <code>static</code> 文件夹中。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// pages/index/index.vue
<view class="content">
<view id="map" class="map-container"></view>
</view>
<script module="leaflet" lang="renderjs">
import '@/static/leaflet/leaflet.css';
import * as L from "@/static/leaflet/leaflet.js";
export default {
mounted() {
this.initMap();
},
methods: {
initMap() {
const baseUrl = 'static/tiles/{z}/{x}/{y}.jpg'
map = L.map('map').setView(, 15);
L.tileLayer(baseUrl, {
minZoom: 15,
maxZoom: 18,
tms: true,
attribution: 'Offline Tiles',
errorTileUrl: ''
}).addTo(map);
},
}
}
</script></pre>
</div>
<div>
<div>
<p>这里需要注意的是一定要在 <code>renderjs</code> 中实现上述代码,如果在常规 <code>script</code> 中实现,在 <code>H5端</code> 没有任何问题,但是运行到<code>真机</code>上会白屏。(这个问题我反复试了好几次都不行,结果还是上传到 <strong>Trae</strong> 上解决了这个问题)。</p>
<p>导致这种情况的原因是在常规 sctipt 中的代码,在真机上是运行在 <strong>逻辑层</strong> 的代码,无法干扰到 <strong>视图层</strong> 的结构,这一点和Web是不同的。</p>
<p>而 renderjs 是运行在 <strong>视图层</strong> 的js,具备操作 <strong>DOM</strong> 的能力。</p>
<p>其次是引用 static 文件的路径,import static 中的文件可以使用 <code>@/static</code> 的方式,但是在代码中引用 static 文件需要采用 <code>static/</code> 的形式。</p>
<h2 data-id="heading-2">总结</h2>
<p>最后我做完以后让 Trae 给了一下评价,Trae 表示<strong>不建议</strong>采用这种方式实现离线地图,首先瓦片地图文件一般<strong>非常大</strong>,我用的仅仅是其中的一小部分,也超过了 <strong>60MB</strong>,打包出来的 App 包太大了。</p>
<p>其次无论是 <code>web-view</code> 还是 <code>renderjs</code> 本质上是一样的。在app-vue环境下,视图层由webview渲染,而renderjs就是运行在视图层的。</p>
<p>所以无论是渲染效率还是开发上基本没差。</p>
</div>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19806256
頁:
[1]