真宝玲的家家 發表於 2026-4-1 12:26:00

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;">&lt;!DOCTYPE html&gt;
&lt;html&gt;
        &lt;head&gt;
                &lt;meta charset="utf-8" /&gt;
                &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
                &lt;title&gt;离线地图&lt;/title&gt;
                &lt;link rel="stylesheet" href="./leaflet/leaflet.css" /&gt;
                &lt;style&gt;
                        html,
                        body {
                                margin: 0;
                                padding: 0;
                        }

                        #map {
                                height: 100vh;
                                width: 100vw;
                                margin: 0;
                                padding: 0;
                        }
                &lt;/style&gt;
        &lt;/head&gt;
        &lt;body&gt;
                &lt;div id="map"&gt;&lt;/div&gt;
                &lt;script src="./leaflet/leaflet.js"&gt;&lt;/script&gt;
                &lt;script&gt;
                        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);
                &lt;/script&gt;
        &lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<p>找到&nbsp;<code>pages/index/index.vue</code>&nbsp;文件,采用&nbsp;<code>web-view</code>&nbsp;引用的方式引入上述 html 文件。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// pages/index/index.vue
&lt;template&gt;
        &lt;view class="content"&gt;
                &lt;web-view src="/static/offline-map.html"&gt;&lt;/web-view&gt;
        &lt;/view&gt;
&lt;/template&gt;

&lt;style&gt;
        .content {
                width: 100%;
                height: 100%;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
        }
&lt;/style&gt;</pre>
</div>
<h2 data-id="heading-1">实现方案二:renderjs</h2>
<p>仍然将&nbsp;<code>leafletjs</code>&nbsp;和&nbsp;<code>瓦片图片文件夹tiles</code>&nbsp;放入&nbsp;<code>static</code>&nbsp;文件夹中。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// pages/index/index.vue
&lt;view class="content"&gt;
    &lt;view id="map" class="map-container"&gt;&lt;/view&gt;
&lt;/view&gt;

&lt;script module="leaflet" lang="renderjs"&gt;
    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);
                        },
      }
    }
&lt;/script&gt;</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]
查看完整版本: uni-app使用瓦片实现离线地图的两种方案