简介:本资源是一套开箱即用的校园导航微信小程序模板源码,面向前端初学者及教育类小程序开发者,旨在解决高校场景下新生导览、访客定位与校内服务快速触达等实际需求。压缩包共51个文件,包含10个JS逻辑文件(如map/index.js、app.js)、6个WXML页面结构文件、7个WXSS样式文件、10个JSON配置文件(含app.json、sitemap.json等),以及13张PNG图标与2个SVG矢量图,整体仅118KB,轻量易读。已有165人学习下载,适合快速理解小程序三层架构(视图-逻辑-配置)与校园类应用典型模块设计。源码已集成地图导航基础框架、位置图标资源、搜索与加载组件,并附README.md说明与LICENSE协议,目录结构规范,便于二次开发教学楼查询、食堂营业时间展示、图书馆预约跳转等扩展功能。
1. 校园导航微信小程序不是“地图截图+跳转链接”,而是基于高德地图 SDK 的实时路径规划与 POI 动态渲染系统
很多刚接触校园导航小程序的开发者,第一反应是“把校园平面图切片上传、加几个 marker 点位就行”。但实际交付中,用户真正需要的是:输入“从南门到图书馆”,3 秒内返回步行/骑行路线、避开施工区域、显示实时拥堵色块;点击食堂图标,立刻弹出今日菜单、人均消费、排队人数——这些能力,靠静态图片和硬编码坐标根本无法支撑。本模板源码正是围绕「动态数据驱动 + 原生地图组件深度集成」构建,核心依赖amap-wx.js封装的高德微信小程序 SDK,所有地图交互(缩放、拖拽、点选、路径绘制)均走微信原生map组件生命周期,而非 WebView 嵌套 H5 地图。它面向两类人:一是高校信息化部门需快速上线轻量级导航服务,无需自建 GIS 后台;二是前端开发者想掌握微信小程序中地图类应用的完整链路——从wx.getLocation权限申请、wx.request获取校园 POI 数据,到mapContext.getCenterLocation实时监听视图中心,再到mapContext.includePoints动态适配多点视野。模板已预置gdst.json(广东某高校地理信息结构化数据),可直接替换为本校坐标系,避免从零测绘。
2. 模板结构解析与关键文件职责划分:从app.json入口配置到amap-wx.js地图 SDK 封装逻辑
2.1 页面路由与全局配置:app.json与project.config.json的协同作用
微信小程序的启动流程始于app.json,它定义了页面路径、窗口样式及 tabBar 导航。本模板中app.json的关键配置如下:
{ "pages": [ "pages/index/index", "pages/map/index", "pages/web-views/index" ], "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "img/home.png", "selectedIconPath": "img/home-active.png" }, { "pagePath": "pages/map/index", "text": "地图", "iconPath": "img/map.png", "selectedIconPath": "img/map-active.png" } ] }, "requiredBackgroundModes": ["location"], "permission": { "scope.userLocation": { "desc": "获取您的位置信息,用于精准定位校园建筑" } } }注意:
requiredBackgroundModes必须声明"location",否则 iOS 系统在后台时无法持续获取定位;permission中的desc字段不可为空,否则安卓端会静默拒绝授权。project.config.json则负责开发环境配置,其中"miniprogramRoot": "./"指向源码根目录,"appid"需在开发者工具中登录后自动填充,切勿手动修改为测试 AppID,否则wx.login会返回invalid appid错误。
2.2 地图页面核心逻辑:pages/map/index.js中的生命周期与地图上下文管理
map/index.js是导航功能的中枢,其onLoad和onReady生命周期直接决定地图初始化成败:
// pages/map/index.js Page({ data: { markers: [], polyline: [], scale: 16, latitude: 23.123456, longitude: 113.123456 }, onReady() { // 获取 map 组件实例,必须在 onReady 中调用 this.mapCtx = wx.createMapContext('myMap', this); // 初始化地图中心点(此处应替换为学校真实坐标) this.setData({ latitude: 23.123456, longitude: 113.123456 }); }, onLoad() { // 加载校园 POI 数据(来自 gdst.json) wx.request({ url: '/resources/gdst.json', success: (res) => { const pois = res.data.pois; const markers = pois.map(poi => ({ id: poi.id, latitude: poi.lat, longitude: poi.lng, name: poi.name, iconPath: `/img/${poi.icon || 'mapicon_default.png'}`, width: 30, height: 30 })); this.setData({ markers }); } }); }, // 点击 marker 触发详情页 markertap(e) { const id = e.markerId; const poi = this.data.markers.find(m => m.id === id); wx.navigateTo({ url: `/pages/web-views/index?name=${encodeURIComponent(poi.name)}&id=${id}` }); } });参数说明与踩坑点:
wx.createMapContext('myMap', this)中'myMap'必须与 WXML 中<map id="myMap" />的id完全一致,大小写敏感;polyline数组用于绘制路径,每条线段需包含points(经纬度数组)、color(十六进制,如#FF0000)、width(像素值)字段;markers中iconPath路径以/开头表示绝对路径,指向miniprogramRoot下的img/目录,若使用相对路径(如./img/xxx.png)会导致图标不显示;wx.request请求gdst.json时,若服务器未配置Access-Control-Allow-Origin: *,需将 JSON 文件放入小程序本地resources/目录,改用wx.loadFontFace方式加载(本模板已采用此方案)。
2.3 高德 SDK 封装层:utils/amap-wx.js的请求签名与逆地理编码实现
amap-wx.js并非官方 SDK,而是社区封装的轻量版,其核心在于解决微信小程序无法直接调用高德 Web API 的跨域与鉴权问题。关键方法getWalkingRoute的实现如下:
// utils/amap-wx.js class AMapWX { constructor(key) { this.key = key; // 高德开放平台申请的 Web Service Key } getWalkingRoute(params) { const { origin, destination } = params; const url = `https://restapi.amap.com/v3/direction/walking?origin=${origin}&destination=${destination}&key=${this.key}`; return new Promise((resolve, reject) => { wx.request({ url, method: 'GET', success: (res) => { if (res.data.status === '1') { resolve(res.data.route); } else { reject(new Error(`高德API错误:${res.data.info}`)); } }, fail: reject }); }); } // 逆地理编码:经纬度转地址 getRegeo(lnglat) { const url = `https://restapi.amap.com/v3/geocode/regeo?location=${lnglat}&key=${this.key}`; return wx.request({ url }); } } module.exports = AMapWX;提示:
key必须在高德开放平台创建「Web 服务」类型应用获取,不能使用「微信小程序」类型 Key,因后者仅支持amap-js-api前端 SDK,而本模板走的是wx.request后端代理模式。若返回INVALID_USER_KEY,请检查 Key 是否绑定 IP 白名单(微信小程序无固定 IP,需留空)。
3. 核心功能实现:步行路径规划、POI 搜索与动态 Marker 渲染三步闭环
3.1 步行路径规划:从起点到终点的实时计算与地图绘制
路径规划并非简单调用一次 API,而是需结合用户当前位置与目标 POI 构建完整闭环。pages/map/index.js中的startNavigation方法如下:
// pages/map/index.js startNavigation(targetPoi) { // 1. 获取用户当前定位 wx.getLocation({ type: 'gcj02', // 必须为国测局坐标系,与高德一致 success: (loc) => { const origin = `${loc.longitude},${loc.latitude}`; const destination = `${targetPoi.lng},${targetPoi.lat}`; // 2. 调用高德步行路线 API const amap = new AMapWX('your-amap-key-here'); amap.getWalkingRoute({ origin, destination }) .then(route => { const steps = route.paths[0].steps; const points = steps.map(step => ({ latitude: parseFloat(step.polyline.split(';')[0].split(',')[1]), longitude: parseFloat(step.polyline.split(';')[0].split(',')[0]) })); // 3. 绘制路径线段 this.setData({ polyline: [{ points, color: '#007AFF', width: 6, dottedLine: false }] }); // 4. 自动调整地图视野包含起点、终点、路径 const allPoints = [ { latitude: loc.latitude, longitude: loc.longitude }, { latitude: targetPoi.lat, longitude: targetPoi.lng }, ...points ]; this.mapCtx.includePoints({ points: allPoints }); }) .catch(err => { wx.showToast({ title: '规划失败:' + err.message, icon: 'none' }); }); }, fail: () => { wx.showToast({ title: '请开启定位权限', icon: 'none' }); wx.openSetting(); // 引导用户手动授权 } }); }关键参数逻辑说明:
type: 'gcj02'是强制要求,微信wx.getLocation返回的坐标系必须与高德 API 输入一致,若设为'wgs84'会导致路径偏移 500 米以上;steps[0].polyline是高德返回的贝塞尔曲线坐标串,格式为lng1,lat1;lng2,lat2;...,需按分号分割再取首段作为路径锚点(实际项目中应解析全部点位);mapContext.includePoints的points数组长度不能超过 20,超限时需先调用mapContext.getCenterLocation获取当前中心,再分批包含。
3.2 POI 搜索与动态 Marker 更新:pages/index/index.js中的搜索框联动
首页index.wxml包含搜索框与结果列表,其 JS 层实现搜索-渲染联动:
// pages/index/index.js Page({ data: { searchQuery: '', searchResults: [] }, onSearchInput(e) { this.setData({ searchQuery: e.detail.value }); }, onSearchConfirm() { const query = this.data.searchQuery.trim(); if (!query) return; // 从 gdst.json 中模糊匹配 POI 名称 wx.request({ url: '/resources/gdst.json', success: (res) => { const allPois = res.data.pois; const results = allPois.filter(poi => poi.name.includes(query) || (poi.tags && poi.tags.some(tag => tag.includes(query))) ); this.setData({ searchResults: results }); } }); }, // 点击搜索结果跳转至地图并高亮 onResultTap(e) { const poi = e.currentTarget.dataset.poi; wx.navigateTo({ url: `/pages/map/index?highlight=${poi.id}` }); } });WXML 搜索组件绑定:
<!-- pages/index/index.wxml --> <view class="search-bar"> <input bindinput="onSearchInput" bindconfirm="onSearchConfirm" placeholder="搜索教学楼、食堂、图书馆..." value="{{searchQuery}}" /> </view> <view wx:if="{{searchResults.length > 0}}" class="search-results"> <view wx:for="{{searchResults}}" wx:key="id" bindtap="onResultTap" ><!-- pages/map/index.wxml --> <map id="myMap" class="map-container" longitude="{{longitude}}" latitude="{{latitude}}" scale="{{scale}}" markers="{{markers}}" bindmarkertap="markertap" bindregionchange="onRegionChange" > <!-- 自定义覆盖物:起点/终点图标 --> <cover-image wx:if="{{startPoint}}" class="cover-icon" src="/img/mapicon_start.png" style="left:{{startPoint.x}}px;top:{{startPoint.y}}px;" /> <cover-image wx:if="{{endPoint}}" class="cover-icon" src="/img/mapicon_end.png" style="left:{{endPoint.x}}px;top:{{endPoint.y}}px;" /> </map>cover-image用于覆盖原生map组件无法渲染的 HTML 元素(如带文字的气泡),其x/y坐标需通过mapContext.getScreenCoordinates计算,本模板在onRegionChange中动态更新:
onRegionChange(e) { if (e.type === 'end') { // 当地图停止拖拽/缩放时,更新起点/终点屏幕坐标 this.mapCtx.getCenterLocation({ success: (center) => { // 此处应调用 getScreenCoordinates 获取像素坐标,模板中已预留接口 } }); } }4. 进阶技巧:自定义加载页、离线地图缓存与微信原生分享卡片配置
4.1 替换默认加载页:修改app.js中的onLaunch启动屏逻辑
微信小程序默认白屏时间过长,需在app.js的onLaunch中插入自定义 loading:
// app.js App({ onLaunch() { // 显示自定义启动页 wx.showLoading({ title: '校园地图加载中...', mask: true }); // 模拟资源加载(真实项目中应加载 gdst.json、字体等) setTimeout(() => { wx.hideLoading(); // 检查用户是否已授权定位 wx.getSetting({ success: (res) => { if (!res.authSetting['scope.userLocation']) { wx.authorize({ scope: 'scope.userLocation', success: () => console.log('定位授权成功') }); } } }); }, 1200); } });提示:
wx.showLoading的mask: true可阻止用户操作,避免白屏期间点击无效;1200ms 是经验值,需根据gdst.json大小调整,若 JSON 超过 500KB,建议拆分为多个小文件并行加载。
4.2 离线地图缓存:利用wx.setStorage保存 POI 数据减少重复请求
为提升冷启动速度,将gdst.json缓存至本地存储:
// utils/cache.js const CACHE_KEY = 'campus_pois'; function loadPois() { return new Promise((resolve, reject) => { wx.getStorage({ key: CACHE_KEY, success: (res) => { const now = Date.now(); if (now - res.time < 24 * 60 * 60 * 1000) { // 24小时缓存 resolve(res.data); } else { fetchAndCachePois().then(resolve).catch(reject); } }, fail: () => fetchAndCachePois().then(resolve).catch(reject) }); }); } function fetchAndCachePois() { return new Promise((resolve, reject) => { wx.request({ url: '/resources/gdst.json', success: (res) => { wx.setStorage({ key: CACHE_KEY, data: { data: res.data, time: Date.now() } }); resolve(res.data); }, fail: reject }); }); } module.exports = { loadPois };在map/index.js中调用:
const { loadPois } = require('../../utils/cache.js'); onLoad() { loadPois().then(pois => { const markers = pois.pois.map(...); // 同前 this.setData({ markers }); }); }4.3 微信原生分享卡片:map/index.js中的onShareAppMessage配置
分享卡片直接影响传播效果,需设置title、imageUrl与path:
onShareAppMessage() { return { title: '我在XX大学找到了图书馆!', path: '/pages/map/index?share=1', // 附带参数便于统计 imageUrl: '/img/share-card.jpg' // 900*500 像素,需提前生成 }; }注意:
imageUrl必须为 HTTPS 且尺寸严格符合要求,否则显示默认灰色卡片;path中的参数会在onLoad的options对象中透出,可用于埋点分析分享来源。
| 分享参数 | 用途 | 示例值 |
|---|---|---|
share | 标识分享来源 | 1 |
ref | 推荐人 ID | user_abc123 |
poi_id | 被分享的 POI ID | lib_001 |
最后一步:在app.json中开启requiredBackgroundModes并确保sitemap.json已配置为"setting": {"level": "public"},否则新版本微信将限制搜索直达。
本文还有配套的精品资源,点击获取