腾讯位置服务示例小程序(二)
前言
本篇博文主要对Map组件下的二级菜单进行学习。
Map组件
地图显示
在地图显示页面中,主要由tab导航,地图显示窗口和切换按钮组成。虽然该页面内容较为丰富,但我们只对较为实用对几个功能进行学习。
tab导航组件的初始化
tab导航组件的初始化在这个小程序中非常的简单,只需要在wxml中进行如下声明
<tab tabList="{{tabList}}" bind:clickTab="clickTab"/>
其中,tab为一个组件,在json文件中引入;tabList为需要在js文件中进行定义的数据列表;clickTab为需要在js文件中进行定义的响应函数。至于tab这个组件的详细学习,我们会在稍后进行学习。根据tab组件的要求,tabList中的每一段数据需要包含name属性,故js中的表示如下
tabList: [{
id: 0,
show: true,
name: '基础地图'
},{
id: 1,
show: false,
name: '室内图'
},{
id: 2,
show: false,
name: '海外地图'
},{
id: 3,
show: false,
name: '卫星图'
}],
其中,id可以用来进行唯一标示,show可以用来表示该子tab对应的页面是否应当被显示。当点击tab中的子标签时,会触发tab导航的响应函数,即
// 点击标题栏处的tab的响应函数
clickTab (event) {
// 与之前类似,即使用id来判断当前哪个tab被点击
const id = event.detail.current,list = this.data.tabList;
for (let i = 0, len = list.length; i < len; ++i) {
if (list[i].id === id) {
list[i].show = !list[i].show;
} else {
list[i].show = false;
}
}
// 更新数据
this.setData({
tabList: list
});
},
自此,tab导航组件初始化完毕。
使用tab导航来控制哪一个页面需要被显示
由于tab导航使用show字段来表示当前哪个tab子控件处于激活状态,故在wxml中,使用如下代码来对页面进行显示和不显示的操作
<view class="map-content pl20 {{tabList[0].show ? 'map-content-show' : '' }}">
<view class="map-content pl20 {{tabList[1].show ? 'map-content-show' : '' }}">
<view class="map-content pl20 {{tabList[2].show ? 'map-content-show' : '' }}">
<view class="map-content pl20 {{tabList[3].show ? 'map-content-show' : '' }}">
由上述代码可以看出,当tabList[n].show的值为true时,即表示当前第n个子控件处于激活状态,故将该页面进行展示。
地图控件的显示
微信小程序API提供了一个直接用来显示地图的组件,能够使开发者轻而易举的将地图展现到页面中。在这里,主要列举了两个较为典型的地图组件使用方式
<!-- 这里的latitube和logitude为经纬度
即打开地图是的视野位置 -->
<!-- enable-3D是否显示3D楼块,参数为bool -->
<!-- enable-traffic是否开启实时路况,参数为bool -->
<map class="map" latitude="40.040415" longitude="116.273511" scale="17" enable-3D="{{is3D}}" enable-traffic="{{isRealTraffic}}"></map>
<!-- enable-satellite表示是否开启卫星图,默认为true -->
<map class="map" latitude="40.040415" longitude="116.273511" scale="15" enable-satellite></map>
在上述代码中,经纬度是人为硬编码到代码中。而在我们实际开发中,可以使用数据绑定等方法,在js脚本中对经纬度进行改变,进而渲染到wxml文件中。
切换按钮组件
在这个样例中,出现了一个新的组件,即切换按钮组件。该组件只有两个状态,即开启和关闭状态。它在wxml中的声明如下
<switch color="#3875FF" checked="{{is3D}}" bindchange="onChange3D"></switch>
其中,color为switch组件开启后显示的背景色;checked为一个动态改变值,当switch组件关闭时,checked对应的变量为false,反之为true;bindchange为switch组件状态发生变化时的响应函数。响应函数的例子如下
// 使用切换按钮来确定是否显示3D
onChange3D (event) {
this.setData({
// 这里的is3D即为之前wxml中的is3D
is3D: event.detail.value
});
},
地图视野控制
感觉这个二级菜单没啥好说的。
地图控件
正如小程序里边的提示文字所说,“此页面展示地图提供的控件产品,包含比例尺,指南针,定位控件”。从页面可以看出,比例尺,指南针和定位控件均由switch组件来决定他们是否显示,故主要还是看map组件是如何定义的
<map
class="map"
id="map"
latitude="{{location.latitude}}"
longitude="{{location.longitude}}"
show-location="{{showPosition}}"
show-compass="{{isShowCompass}}"
show-scale="{{isShowScale}}"
scale="16"
>
</map>
这个map组件比之前我们使用的map组件多了很多参数,但新增的参数也很容易理解,即是否开启比例尺,指南针和定位控件有后边的变量来决定。而这些变量的改变权由三个switch组件来决定。
<switch color="#3875FF" checked="{{isShowScale}}" bindchange="onChangeShowScale"></switch>
<switch color="#3875FF" checked="{{isShowCompass}}" bindchange="onChangeShowCompass"></switch>
<switch class="feature-switch" color="#3875FF" checked="{{isShowPosition}}" bindchange="onChangeShowPosition"></switch>
其中,比例尺和指南针对应的switch按钮的响应函数很简单,就是改变对应绑定数据的值而已。定位控件的响应函数还包含了对设备定位的获取
// 激活定位控件
onChangeShowPosition (event) {
// const {value} = event.detail与
// value = event.detail.value等价
const {value} = event.detail;
if (value) {
// 取得设备当前位置
wx.getLocation({
type: 'gcj02',
success: (res) => {
// 将位置的经纬度更新到全局数据中
const {latitude, longitude} = res;
this.setData({
location: {
latitude,
longitude
}
});
}
});
}
this.setData({
showPosition: value
});
},
定位控件显示,也就是在地图上显示设备的位置,并将视野切换到该位置上。
标注点
该页面主要对地图当中对标注点和标注点上方的气泡进行学习。
初始化有marker的地图
<map class="map" markers="{{calloutMarkers}}" latitude="40.040415" longitude="116.273511" scale="15"></map>
该声明与之前的map不同点在于,多了一个marker参数。marker参数的样例如下
const INIT_MARKER = {
// marker上的气泡显示
callout: {
content: '腾讯总部大楼',
// 边缘留白大小
padding: 10,
// 圆角大小
borderRadius: 2,
// 'BYCLICK':点击显示; 'ALWAYS':常显
display: 'ALWAYS'
},
// 坐标位置
latitude: 40.040415,
longitude: 116.273511,
// maker的标志
iconPath: './imgs/Marker1_Activated@3x.png',
// 宽高旋转透明度
width: '34px',
height: '34px',
rotate: 0,
alpha: 1
};
可以看到,在map组件中有经纬度的设置,在makrer中也有经纬度的设置,他们二者不通点在于,map组件中的经纬度控制了镜头的位置,marker中的经纬度控制了marker出现的位置。
选择marker的图标
通过在页面中对不同图标对选择,进而对marker数据进行更新,并刷新到显示页面
<!-- 选择图标,使用for来遍历图标列表 -->
<!-- 响应函数为onSelectMarkerImg -->
<view class="feature-txt-item" bindtap="onSelectMarkerImg" data-index="{{index}}" wx:for="{{markerImgs}}">
<!-- 使用index来判断当前选中那一个图标,并改变图标 -->
<image hidden="{{index === markerImgIndex}}" class="marker-img" src="{{item.normal}}"></image>
<image hidden="{{index !== markerImgIndex}}" class="marker-img" src="{{item.active}}"></image>
</view>
// 选择marker的图标
onSelectMarkerImg (event) {
const markerImgIndex = event.currentTarget.dataset.index;
// 如果未改变
if (markerImgIndex === this.data.markerImgIndex) {
return;
}
// 更新markers的数据
this.setData({
'markers[0].iconPath': this.data.markerImgs[markerImgIndex].active,
markerImgIndex
});
},
上述js脚本有一个注意的点,就是当我们需要对markers[0].iconPath进行值对修改时,不是直接使用markers[0].iconPath: xxxx,而是先将markers[0].iconPath包成字符串,然后再赋值修改。那是因为markers是一个类数组对变量,所有需要进行这样对操作。
改变marker的旋转角度
这里使用了一个新控件,即滑动控制条。当对滑动控制条进行滑动时,该组件会触发响应函数,并将数值回传给js脚本
<!-- slider组件,滑动控制条 -->
<!-- value为组件显示的数值,这里采用双向绑定 -->
<!-- color为剩余部分的颜色,activeColor为挪动的颜色 -->
<!-- min为最小值,max为最大值 -->
<slider class="slider" value="{{markers[0].rotate}}" bindchange="onChangeMarkerRotate" color="#e5e5e5" activeColor="#3875ff" block-size="20" min="0" max="360"/>
使用响应函数来接收调整的值并对js中对数据进行更新
// 改变旋转角度的响应函数
onChangeMarkerRotate (event) {
const {value} = event.detail;
this.setData({
'markers[0].rotate': value
});
},
调整透明度与调整旋转角度类似,唯一区别在于,调整透明度使用了一个新的参数,即步长
<slider class="slider" value="{{markers[0].alpha}}" step="0.01" bindchange="onChangeMarkerAlpha" color="#e5e5e5" activeColor="#3875ff" block-size="20" min="0" max="1"/>
输入设置气泡显示文字
用户通过intup组件可以将自己输入的文字更新到marker气泡上。
<input
class="callout-input"
value="{{calloutMarkers[0].callout.content}}"
placeholder="不得超过 10 字"
bindinput="onInputChange"
/>
其中,双向绑定的数值为calloutMarkers对应的内容;input组件缺省值为不得超过 10 字;每当input组件内的内容发生变化时,就会调用响应函数onInputChange。该响应函数与其他响应函数类似,都是用来更新js脚本中的数据
onInputChange (event) {
const {value} = event.detail;
this.setData({
'calloutMarkers[0].callout.content': value
});
},
弹框调整文字颜色
页面结构主要是通过数据来对文字颜色进行修改。还有一个重要对点在于,点击触发对响应函数
<!-- 绑定点击响应事件 -->
<view class="feature-content border-bottom" bindtap="ontriggerSelectColor">
<text class="feature-label">文本颜色</text>
<view class="feature-txt">
<!-- 通过数据来动态修改文字的样式 -->
<text style="{{'color:' + (calloutMarkers[0].callout.color || '#222')}}">{{calloutMarkers[0].callout.color ? '文本颜色' : '默认颜色'}}</text>
<!-- 右箭头图片 -->
<image class="right-arrow" src="{{imgs.rightArrow}}"></image>
</view>
</view>
在该小程序中,点击文本颜色会从底部弹出一个可选择对列表,这是有响应函数配合组件来实现的
ontriggerSelectColor () {
this.setData({
showColorActionsheet: true
});
},
上述响应函数中将showColorActionsheet这个标志位变成了true,故激活了下方的组件
<mp-actionsheet
bindactiontap="onSelectColor"
ext-class="color-actionsheet"
show="{{showColorActionsheet}}"
actions="{{calloutColors}}">
</mp-actionsheet>
这个组件是一个自定义组件,详细的代码内容我们先暂时不去考虑。可以看到,这个组件中有响应函数bindactiontap,有样式ext-class,有是否展示组件的标志show,以及需要渲染的内容actions。需要actions的值的形式为
calloutColors: [
{text: '文本颜色', value: '#3875FF'},
{text: '文本颜色', value: '#00C562'},
{text: '文本颜色', value: '#F74A14'},
{text: '默认颜色', value: ''}
],
响应函数的内容为
onSelectColor (event) {
const {value} = event.detail;
if (value) {
console.log(value)
// 得到颜色值后,让组件消失,并设置颜色
this.setData({
showColorActionsheet: false,
'calloutMarkers[0].callout.color': value
});
} else {
// 点击默认颜色后
const callout = {...this.data.calloutMarkers[0].callout};
// 删除之前选择的颜色信息
delete callout.color;
// 重置
this.setData({
showColorActionsheet: false,
'calloutMarkers[0].callout': {
...callout
}
});
}
},
页面中的其他选项都大同小异,故不再进行详细讨论。