写的一个基于之前的门店功能,通过wordpress的REST API 获取后门店数据可以直接在前台渲染成门店地图,最终效果如下图所示。
注,基于其他主题下开发,样式适配了其他主题,根据实际可能需要调整。
之前在wordpress里创建了门店类型的自定义Post Type,https://www.zkcoi.com/365up/program/2342.html
一PHP的部分
包括获取省市区的列表,门店列表等
ssq.txt保存的是省市区的json数据,有需要的可以下载
省市区的json数据文件:ssq.txt
//注册获取省市区的REST API add_action('rest_api_init', function() { register_rest_route('wp/v1', '/ssq/', array( 'methods' => 'GET', 'callback' => 'getSSQ', )); }); // 添加跨域请求头部 add_action('init', function() { header('Access-Control-Allow-Origin: *.zkcoi.com'); }); // 获取 ssq 数据的回调函数 function getSSQ() { $cache_key = 'ssq_data'; // 缓存键名 $cache_time = WEEK_IN_SECONDS; // 缓存时间(1周) // 尝试从 wp_cache 中读取缓存数据 $cached_data = wp_cache_get($cache_key); if ($cached_data !== false) { return $cached_data; } $cacheUrl = __DIR__."/html/ssq.txt"; $content = @file_get_contents($cacheUrl); // 将获取到的数据转换为 JSON 数组 $json_array = json_decode($content, true); // 将获取到的数据保存到缓存中,缓存时间为 $cache_time wp_cache_set($cache_key, $json_array, null, $cache_time); return $json_array; } // 获取门店数组的回调函数 function get_store_addresses_by_location_rest($data) { $cache_key = 'store_addresses_' . md5(serialize($data)); // 缓存键名 $cache_time = DAY_IN_SECONDS; // 缓存时间(1天) $result = wp_cache_get($cache_key); if ($result) { return rest_ensure_response($result); } $args = array( 'post_type' => 'store', 'posts_per_page' => -1, 'meta_key' => 'store_address', 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'store_address', 'compare' => 'EXISTS' ), array( 'key' => 'store_address', // 'value' => '北京', // 默认为北京 'compare' => 'LIKE' ) ) ); // 省份 if (!empty($data['sheng'])) { $args['meta_query'][1]['value'] = $data['sheng']; } // 城市 if (!empty($data['shi'])) { $args['meta_query'][] = array( 'key' => 'store_address', 'value' => $data['shi'], 'compare' => 'LIKE' ); } // 区县 if (!empty($data['qu'])) { $args['meta_query'][] = array( 'key' => 'store_address', 'value' => $data['qu'], 'compare' => 'LIKE' ); } $query = new WP_Query($args); $stores_arr = array(); // 拼接数组 while ($query->have_posts()) { $query->the_post(); $store_id = get_the_ID(); $store_title = get_the_title(); $store_address = get_post_meta($store_id , 'store_address', true); $store_content = get_the_content(); $store_coordinate_str = get_post_meta($store_id , 'store_coordinate', true); $store_phone = get_post_meta($store_id , 'store_phone', true ) ?: "4008001650"; $store_img_url = get_the_post_thumbnail_url($store_id , 'medium'); $coordinates = explode(',', $store_coordinate_str); $longitude = floatval($coordinates[0]); $latitude = floatval($coordinates[1]); $store_coordinate = array( 'longitude' => $longitude, 'latitude' => $latitude ); $store = array( 'name' => $store_title, 'address' => $store_address, 'coordinate' => $store_coordinate, 'content' => $store_content, 'phoneNum' => $store_phone, 'imgUrl' => $store_img_url, ); array_push($stores_arr, $store); } wp_reset_postdata(); // 将数组转换为 JSON 格式并返回 REST API 响应对象 $result = rest_ensure_response($stores_arr); // 设置响应头,指定返回的数据类型为 JSON $result->set_headers(array('Content-Type' => 'application/json;charset=UTF-8')); // 将查询结果缓存 wp_cache_set($cache_key, $stores_arr, '', $cache_time); return $result; } //注册获取门店的REST API add_action('rest_api_init', function() { register_rest_route('wp/v1', '/store', array( 'methods' => WP_REST_Server::READABLE, 'callback' => 'get_store_addresses_by_location_rest', )); });
二、js部分
jQuery(document).ready(function($) { $(function () { var amap = new AMap.Map("map", { zoom: 11 }); var list = []; // 门店列表 var dqs = {}; // 地区筛选条件 var ajax_getSSQ = '/wp-json/wp/v1/ssq/'; // 获取门店列表 function getList() { var sheng = $('#province option:selected').text(); // 获取所选省份的文本内容 var shi = $('#city option:selected').text(); // 获取所选城市的文本内容 var qu = $('#district option:selected').text(); // 获取所选区县的文本内容 var url = '/wp-json/wp/v1/store?'; // 初始化url时只传递省份和区县参数 if (sheng !== "请选择" && sheng !== "市辖区") { // 当所选省份不为“请选择”或“市辖区”时,将省份参数拼接到url中 url += 'sheng=' + encodeURIComponent(sheng); } if (shi !== "请选择" && shi !== "市辖区") { // 当所选城市不为“请选择”或“市辖区”时,将城市参数拼接到url中 url += '&shi=' + encodeURIComponent(shi); } if (qu !== "请选择" && qu !== "市辖区") { // 当所选区县不为“请选择”或“市辖区”时,将区县参数拼接到url中 url += '&qu=' + encodeURIComponent(qu); } $.ajax({ url: url, method: 'GET', dataType: 'json', success: function(response) { // 将返回的 JSON 字符串转换为 JSON 对象 var data = response; // 点击门店列表项时,更新地图中心点和标记 $("#stores").on("click", ".store-item", function () { var index = $(this).index(".store-item"); var poi = new AMap.LngLat(data[index].coordinate.longitude, data[index].coordinate.latitude); amap.setZoomAndCenter(14, poi); }); if (data.length > 0) { var stores = $("#stores"); stores.empty(); // 先清空门店列表 // 添加门店列表项 $.each(data, function (i) { var store = this; if(store.coordinate.latitude && store.coordinate.longitude){ // 判断门店坐标是否存在 var poi = new AMap.LngLat(store.coordinate.longitude, store.coordinate.latitude); var html = '<div class="store-item">' + '<div class="store-b hand pad8' + (i == 0 ? ' active' : '') + '">' + '<div class="store-b1 fl">' + (i + 1) + '</div>' + '<div class="store-b2 overhide">' + '<div class="store-b21 fe11">' + store.name + '</div>' + '<div class="store-b22 co2 f13">地址:' + store.address + '</div>' + '<div class="store-b23 " title="门店电话">电话:'+store.phoneNum+'</div>' + // 添加 info push 图标 '</div>' + '</div>' + '</div>'; stores.append(html); //依次添加到HTML中 // 添加门店地图标记 if (i == 0) { amap.setZoomAndCenter(14, [store.coordinate.longitude, store.coordinate.latitude]); addMarker(poi, store.name, store.address); } else{ addMarker(poi, store.name, store.address); } // 点击 info push 图标显示信息窗口 $(".store-item").eq(i).on("click", function () { var infoContent = '<div class="info-window-content">' + '<div class="info-logo"><img src="[填写logourl]" alt="sitename"></div>'+ '<div class="info-title">' + store.name + '</div>' + '<div class="info-address">' + store.address + '</div>' + '<div class="info-content"><a href="tel:'+store.phoneNum+'">' + store.content + '</a></div>' + '<a class="btn btn-lg btn-primary btn-0" href="https://uri.amap.com/marker?position='+store.coordinate.longitude+','+store.coordinate.latitude+'&name=xx渠道门店-'+ store.name +'&src=www.zkcoi.com&callnative=1" target="_blank" rel="nofollow">点击查看路线</a>' '</div>'; var infoWindow = new AMap.InfoWindow({ content: infoContent, // 信息窗口内容 offset: new AMap.Pixel(0, -30), // 信息窗口偏移量 autoMove: true // 开启信息窗口自动调整位置 }); infoWindow.open(amap, poi); infoWindow.setSize(new AMap.Size(400, 0)); }); } }); } else { // 显示暂无门店信息 $("#stores").html('<div class="store-item"><div class="store-b hand pad8 active">' + '<div class="store-b1 fl">1</div>' + '<div class="store-b2 overhide">' + '<div class="store-b21 fe11">暂无门店信息</div>' + '<div class="store-b22 co2 f13">地址:暂无门店地址</div>' + '</div></div></div>'); } }, error: function(jqXHR, textStatus, errorThrown) { alert(textStatus + ': ' + errorThrown); } }); } // 初始化地区筛选条件 function initDq() { $.get(ajax_getSSQ, function (res) { var list = res; var provinceSel = $("#province"); provinceSel.empty(); // 先清空省份下拉框 provinceSel.append('<option value="">请选择</option>'); // 添加省份选项 $.each(list, function (i, v) { provinceSel.append('<option value="' + i + '">' + v.name + '</option>'); }); // 省份选项改变事件 provinceSel.change(function () { $("#city option:first,#district option:first").prop("selected", 'selected'); var idx = this.value; if (idx != "") { var citySel = $("#city"); var districtSel = $("#district"); var cityList = list[idx].children; citySel.empty(); // 先清空城市下拉框 citySel.append('<option value="">请选择</option>'); $.each(cityList, function (i, v) { citySel.append('<option value="' + i + '">' + v.name + '</option>'); }); dqs.province = list[idx].name; dqs.city = ""; dqs.district = ""; getList(); } else { dqs = {}; getList(); } }); // 城市选项改变事件 $("#city").change(function () { $("#district option:first").prop("selected", 'selected'); var idx = this.value; if (idx != "") { var districtSel = $("#district"); var districtList = list[$("#province")[0].value].children[idx].children; districtSel.empty(); // 先清空区县下拉框 districtSel.append('<option value="">请选择</option>'); $.each(districtList, function (i, v) { districtSel.append('<option value="' + i + '">' + v.name + '</option>'); }); if (list[$("#province")[0].value].children[idx].name.indexOf("市辖区") > -1) { dqs.city = ""; } else { dqs.city = list[$("#province")[0].value].children[idx].name; } dqs.district = ""; getList(); } else { dqs.city = ""; dqs.district = ""; getList(); } }); // 区县选项改变事件 $("#district").change(function () { var idx = this.value; if (idx != "") { dqs.district = list[$("#province")[0].value].children[$("#city")[0].value].children[idx].name; getList(); } else { dqs.district = ""; getList(); } }); }); } // 添加地图标记 function addMarker(position, title, content) { // 创建信息窗口内容,这里以门店名称和地址为例 var infoContent = '<div class="info-window-content">' + '<div class="info-logo"><img src="[填写logourl]" alt="sitename"></div>'+ '<h3 class="info-title">' + title + '</h3>' + '<p class="info-address">' + content + '</p>' + '</div>'; // 创建一个 marker 并将它添加到地图上 var marker = new AMap.Marker({ position: position, title: title }); amap.add(marker); // 点击 marker 显示信息窗口 AMap.event.addListener(marker, 'click', function () { var infoWindow = new AMap.InfoWindow({ content: infoContent, // 信息窗口内容 offset: new AMap.Pixel(0, -30), // 信息窗口偏移量 autoMove: true // 开启信息窗口自动调整位置 }); infoWindow.open(amap, marker.getPosition()); }); } // 初始化地区筛选条件 initDq(); }); });
三、html部分
前端调用方法很多,比如新建页面在模板根目录放在page-[page slug].php中,或者使用get_template_part()等等皆可。
<div class="container"> <div class="map-container"> <div class="store-positions"> <div class="form-group"> <label for="province">省份</label> <select class="form-control" id="province"> <option value="">请选择</option> </select> </div> <div class="form-group"> <label for="city">城市</label> <select class="form-control" id="city"> <option value="">请选择</option> </select> </div> <div class="form-group"> <label for="district">区县</label> <select class="form-control" id="district"> <option value="">请选择</option> </select> </div> </div> <div class="store-wrapper"> <div class="store-map" id="map"></div> <div class="store-list" id="stores"> <div class="store-item active"> <div class="store-b"> <div class="store-b1">1</div> <div class="store-b2"> <div class="store-b21 fe11">请选择地区获取门店信息</div> <div class="store-b22 co2 f13">地址:请选择地区获取门店地址</div> </div> </div> </div> </div> </div> </div> </div> <script src="https://webapi.amap.com/maps?v=1.4.15&key=高德地图api key"></script>
四、css部分
.map-container { width: 100%; margin: 0 auto; flex-direction: column; align-items: center; padding: 44px 0; } .store-wrapper { display: flex; width: 100%; padding: 14px; background-color:#f9f9f9; } .store-list { height: auto; background: #f9f9f9; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) inset; padding: 14px; box-sizing: border-box; display: block; word-wrap: normal; margin-top: 20px; } .store-item { position: relative; align-items: center; padding: 10px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transition: all 0.3s ease-in-out; } .store-b { display: flex; justify-content: center; align-items: center; height: auto; } .store-b1 { display: flex; justify-content: center; align-items: center; width: 32px; height: 32px; font-size: 18px; font-weight: bold; color: #fff; background-color: #ff9800; border-radius: 50%; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transition: all 0.3s ease-in-out; } .store-b1:hover { background-color: #f00; transform: scale(1.2); } .store-b2 { display: flex; flex-direction: column; flex-grow: 1; width: auto; height: auto; padding-left: 12px; box-sizing: border-box; transition: all 0.3s ease-in-out; text-align: left; } .store-b21 { font-size: 17px; font-weight: bold; color: #333; margin-bottom: 5px; word-break: break-word; } .store-b22 ,.store-b23{ font-size: 14px; font-weight: 300; color: #666; margin: 0; word-break: break-word; } .info-content { font-size: 16px; font-weight: bold; color: var(--theme-color); } .store-item:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); } .store-item:hover .store-b1 { background-color: #555; } .store-item.active .store-b1 { background-color: #555; } @media (min-width: 768px) and (max-width: 991px) { .map-container { padding: 60px 0; } .store-positions { justify-content: center; margin: 0px 44px; } .store-wrapper{ display: block; } .store-map { width: 100%; max-width: 900px; height: calc(44vw); border: 1px solid #ff9800; } .store-list{ width: 100%; margin: 0px 4px; } .store-b21 { font-size: 16px; } .store-b22 { font-size: 12px; } } @media (min-width: 992px) and (max-width: 1239px) { .map-container { padding: 60px 0; } .store-positions { justify-content: center; margin: 0px 44px; } .store-wrapper{ justify-content: center; } .store-list{ width: 100%; margin: 0px 44px; } .store-b21 { font-size: 16px; } .store-b22 { font-size: 12px; } } @media (min-width: 1240px) { .map-container { padding: 44px 0; display: flex; } .store-list { max-width: 100%; width: 100%; margin: 0px; } .map-item { margin-right: 20px; } .store-positions { display: flex; width: 100%; justify-content: center; } .form-group { display: inline-block; width: 100%; max-width: 300px; margin: 10px; } label { display: block; font-size: 16px; font-weight: bold; margin-bottom: 10px; } select { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 16px; background-color: #fff; color: #555; } .store-map { width: 100%; max-width: 900px; height: calc(24vw); border: 1px solid #ff9800; } .info-window-content { display: flex; flex-direction: column; justify-content: left; align-items: flex-start; font-family: 'Microsoft YaHei', sans-serif; font-size: 16px; line-height: 1.8; position: relative; padding: 0; width: calc(100% - 2rem); max-width: 380px; } .info-logo { width: 67px; height: 16px; margin-right: 1rem; margin-bottom: 0.75rem; } .info-title { font-size: 14px; font-weight: bold; color: #333; margin-bottom: 0.5rem; } .info-address { margin-bottom: 0.5rem; font-size: 14px; font-weight: 300; } .info-phone { margin-bottom: 0.5rem; font-size: 14px; font-weight: 300; } .info-content { font-size: 14px; font-weight: 400; margin-bottom: 0.5rem; text-align: left; } @media (max-width: 767px){ .info-window-content { align-items: center; text-align: center; } .info-logo { margin-right: 0; } } }
Vue版本
<?php /* Template Name: 门店地图Vue */ global $options; get_header("noscale");?> <link rel="stylesheet" id="zke-stores-style-css" href="<?php echo ZKE_THEME_URI;?>/css/stores.css" type="text/css" media="all"> <script src="https://webapi.amap.com/maps?v=1.4.15&key=58fa9a9f71ea1c7d601a582006c0fad6"></script> <script id="zke-stores-vue" type="text/javascript" src="<?php echo ZKE_THEME_URI;?>/js/vue.min.js" ></script> <div class="container"> <div id="app"> <div class="map-container"> <div class="store-positions"> <div class="form-group"> <label for="province">省份</label> <select class="form-control" v-model="selectedProvince" @change="getCityList"> <option value="">请选择</option> <option v-for="(province, index) in provinces" :value="index" :key="index">{{ province.name }}</option> </select> </div> <div class="form-group"> <label for="city">城市</label> <select class="form-control" v-model="selectedCity" @change="getDistrictList"> <option value="">请选择</option> <option v-for="(city, index) in cities" :value="index" :key="index">{{ city.name }}</option> </select> </div> <div class="form-group"> <label for="district">区县</label> <select class="form-control" v-model="selectedDistrict" @change="getList"> <option value="">请选择</option> <option v-for="(district, index) in districts" :value="index" :key="index">{{ district.name }}</option> </select> </div> </div> <div class="store-wrapper"> <div class="store-map" id="map"></div> <div class="store-list" id="stores"> <div class="store-item" v-for="(store, index) in storeList" :key="index" @click="showInfoWindow(index)"> <div class="store-b"> <div class="store-b1">{{ index + 1 }}</div> <div class="store-b2"> <div class="store-b21 fe11">{{ store.name }}</div> <div class="store-b22 co2 f13">地址:{{ store.address }}</div> <div class="store-b23" title="门店电话">电话:{{ store.phoneNum }}</div> </div> </div> </div> </div> </div> </div> </div> </div> <script> new Vue({ el: '#app', data() { return { selectedProvince: "", selectedCity: "", selectedDistrict: "", provinces: [], cities: [], districts: [], storeList: [], amap: null }; }, mounted() { this.amap = new AMap.Map("map", { zoom: 11 }); this.initDq(); }, methods: { initDq() { fetch("https://www.zkcoi.com/wp-json/zke/v1/ssq/") .then(response => response.json()) .then(data => { this.provinces = data; this.getList(); }) .catch(error => console.error("Error fetching provinces:", error)); }, getCityList() { const selectedProvinceData = this.provinces[this.selectedProvince]; this.cities = selectedProvinceData ? selectedProvinceData.children : []; this.districts = []; this.storeList = []; this.getList(); }, getDistrictList() { const selectedCityData = this.provinces[this.selectedProvince].children[this.selectedCity]; this.districts = selectedCityData ? selectedCityData.children : []; this.storeList = []; this.getList(); }, getList() { const sheng = this.provinces[this.selectedProvince]; const shi = this.cities[this.selectedCity]; const qu = this.districts[this.selectedDistrict]; let url = `https://www.zkcoi.com/wp-json/zke/v1/store?`; if (sheng && sheng.name !== "请选择" && sheng.name !== "市辖区") { url += `sheng=${encodeURIComponent(sheng.name)}`; } if (shi && shi.name !== "请选择" && shi.name !== "市辖区") { url += `&shi=${encodeURIComponent(shi.name)}`; } if (qu && qu.name !== "请选择" && qu.name !== "市辖区") { url += `&qu=${encodeURIComponent(qu.name)}`; } fetch(url) .then(response => response.json()) .then(data => { if (data.length === 0) { // 如果没有数据,添加默认门店信息 this.storeList = [{ name: "请选择地区获取门店信息", address: "请选择地区获取门店地址", phoneNum:"400-XXX-XXX", coordinate: { longitude: 0, latitude: 0 } }]; } else { this.storeList = data; this.showMarkers(data); } }) .catch(error => console.error("Error fetching store list:", error)); }, showInfoWindow(index) { const store = this.storeList[index]; if (store.coordinate && store.coordinate.latitude && store.coordinate.longitude) { const poi = new AMap.LngLat(store.coordinate.longitude, store.coordinate.latitude); let infoContent = `<div class="info-window-content"> <div class="info-logo"><img src="https://www.zkcoi.com/wp-content/uploads/2023/04/logo-mapinfo.png" alt="zkcoi"></div> <h3 class="info-title">${store.name}</h3> <p class="info-address">${store.address}</p>`; if (store.imgUrl) { infoContent += `<div class="info-img"><img class="max-width-img" src="${store.imgUrl}"></div>`; } infoContent += `<a class="btn btn-lg btn-primary btn-0" href="https://uri.amap.com/marker?position=${store.coordinate.longitude},${store.coordinate.latitude}&name=zkcoi渠道门店-${store.name}&src=www.zkcoi.com&callnative=1" target="_blank" rel="nofollow">点击查看路线</a> </div>`; // 创建信息窗口对象 const infoWindow = new AMap.InfoWindow({ offset: new AMap.Pixel(0, -50), autoMove: true // 自动调整位置以确保信息窗口完全可见 }); // 更新信息窗口的内容并重新设置大小 infoWindow.setContent(infoContent); infoWindow.setSize(new AMap.Size(400, 0)); // 设置大小,400为信息窗口的宽度,0为高度,0表示高度自适应 // 打开信息窗口 infoWindow.open(this.amap, poi); // 将地图中心设置为标记位置 this.amap.setCenter(poi); } }, showMarkers(data) { // 清除地图上的所有标记 this.amap.clearMap(); data.forEach((store, index) => { if (store.coordinate && store.coordinate.latitude && store.coordinate.longitude) { const poi = new AMap.LngLat(store.coordinate.longitude, store.coordinate.latitude); const marker = new AMap.Marker({ position: poi, title: store.name }); marker.setMap(this.amap); // 点击 marker 显示信息窗口 AMap.event.addListener(marker, 'click', () => { this.showInfoWindow(index); }); } }); } } }); </script> <?php get_footer();?>
本文作者:𝙕𝙆𝘾𝙊𝙄
文章名称:wordpress高德地图门店地图功能用AJAX异步获取门店数据
文章链接:https://www.zkcoi.com/365up/program/2664.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。