现离线地图主要用 leafletjs 实现,但是因为在安卓端运行,存在渲染问题,所以还要用上 renderjs

实现方案一:web-view

因为uni-app引入第三方可以采用传统的 NPM 安装的方式,也可以采用引入打包完的js文件的方式。

这里采用 leafletjs 打包完的文件,将 leafletjs 放入 static 文件夹内。

在网上下载了公开的瓦片地图图片,以 {z}/{x}/{y} 的目录结构放入 tiles 文件夹中,将 tiles 放入 static 文件夹内。

在static文件夹下新建一个 offline-map.html 文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

<!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([23.56, 113.23], 15);

            L.tileLayer(baseUrl, {

                minZoom: 15,

                maxZoom: 18,

                tms: true,

                attribution: 'Offline Tiles',

                errorTileUrl: ''

            }).addTo(map);

        </script>

    </body>

</html>

找到 pages/index/index.vue 文件,采用 web-view 引用的方式引入上述 html 文件。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// 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>

实现方案二:renderjs

仍然将 leafletjs 和 瓦片图片文件夹tiles 放入 static 文件夹中。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

// 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 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([23.56, 113.23], 15);

                L.tileLayer(baseUrl, {

                    minZoom: 15,

                    maxZoom: 18,

                    tms: true,

                    attribution: 'Offline Tiles',

                    errorTileUrl: ''

                }).addTo(map);

            },

        }

    }

</script>

这里需要注意的是一定要在 renderjs 中实现上述代码,如果在常规 script 中实现,在 H5端 没有任何问题,但是运行到真机上会白屏。(这个问题我反复试了好几次都不行,结果还是上传到 Trae 上解决了这个问题)。

导致这种情况的原因是在常规 sctipt 中的代码,在真机上是运行在 逻辑层 的代码,无法干扰到 视图层 的结构,这一点和Web是不同的。

而 renderjs 是运行在 视图层 的js,具备操作 DOM 的能力。

其次是引用 static 文件的路径,import static 中的文件可以使用 @/static 的方式,但是在代码中引用 static 文件需要采用 static/ 的形式。

总结

最后我做完以后让 Trae 给了一下评价,Trae 表示不建议采用这种方式实现离线地图,首先瓦片地图文件一般非常大,我用的仅仅是其中的一小部分,也超过了 60MB,打包出来的 App 包太大了。

其次无论是 web-view 还是 renderjs 本质上是一样的。在app-vue环境下,视图层由webview渲染,而renderjs就是运行在视图层的。

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐