实现样式效果如图,比较复杂,内容较多。会在api文件夹创建接口,会在components写一个组件,阅读大概10分钟
复制这块,放在 地图的div下面
<div class="main">
<h4 class="title">
<van-icon name="location-o" />
{{ locationInfo.formattedAddress }}
h4>
<van-search v-model="input" placeholder="请输入搜索关键词" readonly @focus="onJumpSearch" />
<van-dropdown-menu>
<van-dropdown-item title="位置距离" v-model="radius" :options="radiusList" @change="getParkList" />
<van-dropdown-item title="推荐排序" v-model="type" :options="typeList" />
van-dropdown-menu>
<section class="park-list">
<map-item v-for="item in showParkList" :key="item.id" :item="item">
<p>
评分{{ item.biz_ext.rating }}分 距离
{{
getDistances(position[1], position[0], item.location.split(',')[1], item.location.split(',')[0]).km
}}千米
p>
map-item>
section>
div>
复制放在 .map 后面
.main {
background-color: #fff;
padding: 20px;
> h4 {
/*第一步: 溢出隐藏 */
overflow: hidden;
/* 第二步:让文本不会换行, 在同一行继续 */
white-space: nowrap;
/* 第三步:用省略号来代表未显示完的文本 */
text-overflow: ellipsis;
}
.park-list {
padding: 10px;
height: calc(100vh - 680px);
overflow-y: auto;
box-sizing: border-box;
}
}
可以看到缺少了很多东西,一个一个来
代码如下(示例):
input: '', // 输入框绑定值
radius: '', // 范围选择
type: 'a', // 类型选择
radiusList: [
{ text: '全部', value: '' },
{ text: '500米', value: 500 },
{ text: '1000米', value: 1000 },
{ text: '2000米', value: 2000 },
{ text: '5000米', value: 5000 },
],
typeList: [
{ text: '距离优先', value: 'a' },
{ text: '好评优先', value: 'b' },
],
parkList: [],
代码如下(示例):
onJumpSearch() {
this.$router.push('/park/search');
},
onJumpDetail(id) {
this.$router.push('/park/detail/' + id);
},
这个showParkList是我用于渲染页面的parkList,由于高德地图没有条件查询,它只有按照距离来,所以我只能,按距离查询到之后,自己用里面的参数进行一遍过滤。
computed: {
showParkList() {
let array = [...this.parkList];
if (this.type === 'a') {
return array;
} else if (this.type === 'b') {
return array.sort((a, b) => {
// 使用parseFloat将rating属性的值解析为数字
const ratingA = parseFloat(a.biz_ext.rating);
const ratingB = parseFloat(b.biz_ext.rating);
// 根据rating属性从大到小排序
return ratingB - ratingA;
});
}
},
},
还剩下最后一个报错,缺少列表请求方法
由于东西太多,开一个新标题、
在src下的api文件夹里面
看不懂没关系,高德地图文档传送门
// 我使用的poi是1.0,不是2.0, 2.0的话后缀是v5
import axios from 'axios';
import Vue from 'vue';
const baseUrl = 'https://restapi.amap.com/v3';
axios.defaults.headers.common['key'] = Vue.prototype.mapServiceKey;
// 周边搜索
export function mapPlaceAround(params) {
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: baseUrl + '/place/around',
params,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
}
// 关键字搜索
export function mapPlaceText(params) {
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: baseUrl + '/place/text',
params,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
}
// 查询地点详情
export function mapPlaceDetail(params) {
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: baseUrl + '/place/detail',
params,
})
.then((res) => {
resolve(res.data);
})
.catch((err) => {
reject(err);
});
});
}
我已经都封装好了,直接复制粘贴
复制放到export default上面
import { mapPlaceAround } from '@/api/map';
复制粘贴放到methods里面
getParkList() {
console.log('查询');
mapPlaceAround({
location: this.position.join(','), // 当前经纬度拼接, 需要格式为 '113.110748,28.246296'
keywords: '公园',
types: '080000|110000', // 体育休闲服务|风景名胜
radius: this.radius, // 距离
page: 1,
offset: 20,
extensions: 'all', // all全部信息, base基础信息
}).then((res) => {
this.parkList = res.pois;
console.log(JSON.parse(JSON.stringify(res.pois)));
});
},
在获取到定位的时候去调用this.getParkList()方法
把这段代码放在public下的index.html中,你的项目就会有一个控制台了,在手机端测试的时候就可以看见网络请求和控制台打印了
<script src="https://cdn.bootcss.com/vConsole/3.2.0/vconsole.min.js">script>
<script>
// 初始化 引入的调试组件
var vConsole = new VConsole();
console.log('控制台打印信息 最新');
script>
发现手机端好像没啥反应, 其实是组件还没开始写
这里直接复制粘贴我的了,懒得说明了,样式拿去用就随便改改吧。
在components中创建文件夹 MapItem
,再创建index.vue
<template>
<div class="com-map-item" v-if="item">
<div class="img">
<van-image v-if="item.photos.length > 0" width="50" height="50" :src="item.photos[0].url" />
<van-image v-else width="50" height="50" fit="cover" :src="require('@/assets/images/park.png')" />
<slot name="top">slot>
div>
<div class="park-name" @click="onJumpDetail(item.id)">
<h4>{{ item.name }}h4>
<slot>slot>
div>
<div class="park-right" @click="onJumpView">
<van-image width="30" height="30" :src="require('@/assets/images/icons/toRight.png')" />
<span>去这里span>
div>
div>
template>
<script>
export default {
name: 'vinit',
props: {
item: {
type: Object,
default: () => {},
},
position: {
type: Array,
default: () => [],
},
},
data() {
return {};
},
computed: {},
watch: {},
filters: {},
created() {},
methods: {
onJumpDetail(id) {
this.$router.push('/park/detail/' + id);
},
onJumpView() {
this.$router.push('/park/view/' + this.item.id);
},
},
};
script>
<style scoped lang="scss">
.com-map-item {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 10px;
border-bottom: 1px solid #eee;
.img {
position: relative;
}
::v-deep .van-image__img {
border-radius: 5px;
}
.park-name {
width: 70%;
p {
color: #666;
font-size: 28px;
margin-top: 10px;
/*第一步: 溢出隐藏 */
overflow: hidden;
/* 第二步:让文本不会换行, 在同一行继续 */
white-space: nowrap;
/* 第三步:用省略号来代表未显示完的文本 */
text-overflow: ellipsis;
}
}
.park-right {
display: flex;
flex-direction: column;
align-items: center;
}
}
style>
把MapItem
挂载全局,你要按需引入也可以
代码中需要用到图片,缺少图片请看下一步
// 地图列表item
import MapItem from '@/components/MapItem';
Vue.component('MapItem', MapItem);
发现报错
由于我的组件调用了一个图片,所以这里继续引入图片
这里你可以自己修改,如果怕出错,那就用我的,不过这个也简单
图片随便找一个图标叫 toRight.png
一个叫park.png
图标网站传送门iconfont-阿里巴巴矢量图标库
图标在icons里面,图片在images里面,或者你自己改也行。反正是组件。
还是报错,因为没有计算距离方法
在utils中创建 distances.js
// 根据经纬度计算距离,参数分别为第一点的纬度,经度;第二点的纬度,经度
function getDistances(lat1, lng1, lat2, lng2) {
let EARTH_RADIUS = 6378.137; // 地球半径
let radLat1 = (lat1 * Math.PI) / 180.0; //lat1 * Math.PI / 180.0=>弧度计算
let radLat2 = (lat2 * Math.PI) / 180.0;
let a = radLat1 - radLat2;
let b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
let s =
2 *
Math.asin(
Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2))
);
s = s * EARTH_RADIUS;
s = Math.round(s * 10000) / 10000; // 输出为公里
return { m: Math.round(s * 1000), km: Number(s.toFixed(2)) };
}
export default getDistances;
在main.js中
// 传入经纬度,计算出m || km
import getDistances from '@/utils/distances';
Vue.prototype.getDistances = getDistances; // 计算距离
提示:这里对文章进行总结:
挂载了计算距离方法后,发现页面不报错了,正常运行了
因为没有我所需要的评分,我需要根据评分来排序,如果需要地图显示点,可以用mark批量添加,看到这里相信你已经会基本操作了。mark加标记点我在后面会有一片教程,不过不是批量,不过都差不多,反正都是给经纬度然后整个循环。
如果看到这里还是没有正常运行。
请检查
如果都正常,看看你手机是不是禁用了位置授权。
记得用手机端控制台查看报错,禁用控制台直接注释就好了