回发或回调参数无效和省市级联的问题

本文介绍了解决ASP.NET中使用无刷新级联时遇到的事件验证错误问题。通过禁用事件验证,并采用隐藏HTML标签的方法成功获取下拉列表的值。

用.net在web开发中我们有时候会用到省市无刷新级联,既然要无刷新就要用到Javascript,大多数人选择控件的时候也会用DropDownList,或许你绞尽脑汁终于把无刷新级联做出来了,但是在后台取DropDownList的值的时候你会惊讶的发现,报黄页了!太痛苦了,想了好久终于写出来的无刷新级联就这样被微软处于安全原因而抛出错误!(我用的是framework3.5和VS2008)。好了,既已引入了话题,我们下面具体的看一下这个错误和对于这个错误的解决方案。

 

错误描述:

回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true" %> 启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件。如果数据有效并且是预期的,则使用 ClientScriptManager.RegisterForEventValidation 方法来注册回发或回调数据以进行验证。

 

页面错误截图:

 123

 

错误出现的地方:

做好省市级联后(默认用的是DropDownList),取省市的SelectedValue时候。

 

解决方案:(这是我自己想的,如果你有更好的可以忽略)

在网上搜了一下,好多好多文章对于这个问题介绍的都是以下三个个原因:

一是Form嵌套,一个页面只能有一个Form,仔细检查代码就可以解决。

二是在下拉菜单中使用ajax,常见于省市联动菜单,可能是由于在aspx页面赋给了下拉菜单初始Item值,在事件回发时提示该错误,将下拉菜单初始Item值删除,在绑定事件中添加Item项。

三是在给DropDownList赋value值的时候有中文。

找到的解决方案也都大同小异:

第一,   在页面头部或者config文件中配置EnableEventValidation="false";

第二,   在web.config中添加如下语句:<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="zh-CN" uiCulture="zh-CN"/>

这两个方法我都试了,都不行,要么与本意:做省市无刷新级联冲突要么没效果。想来想去,我感觉下面的做法是比较好的:

首先,我们要做无刷新级联,必须设置EnableEventValidation="false",设置后会出现一个问题:在后台用SelectedValue获取DropDownList的值的时候永远都是0!无论你换什么方法获取value值,都是0!

然后,我们可以用一个隐藏的html标签代替用SelectedValue取值:

<input type="hidden" id="input_CityID" runat="server" />

  在写这个标签的时候,把它写成runat="server",这样在后台就可以直接获取该隐藏控件的值。在页面写如下的JS代码:

var City=document.getElementById("<%=ddl_City.ClientID %>");

var CityID = City.options[City.selectedIndex].value;

 document.getElementById("<%=input_CityID.ClientID %>").value=CityID;

如此一来,就可以既用无刷新省市级联又可以获取ddl的值。

 

 

enableEventValidation是跟ASP.net中的EVENTVALIDATION有关,具体如下,以下为非原创,原文连接为:http://hi.baidu.com/carsonguo/item/f9d2541bed3323623f87ce29

 

ASP.net 添加了"event validation"的功能, ASP.NET会检查 POST方法中的所带的参数,如果
认为不合法,就会抛出异常,信息如下

     Invalid postback or callback argument. 
         Event validation is enabled using <pages enableEventValidation="true"/> in 
     configuration or <%@ Page EnableEventValidation="true" %> in a page.  
         For security purposes, this feature verifies that arguments to postback or 
     callback events originate from the server control that originally rendered them.  
         If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation 
     method in order to register the postback or callback data for validation. 
    
这个设计的目的是为了防止恶意用户利用post 方法发送一些恶意数据.但是有时一些常见的
case也会出错,比如使用客户端脚本,根据页面上的其他控件的内容来改变一个dropdown list的内容,最常见的case
就是省市县3级联动菜单.又比如在页面上添加一个dropdown list,然后给它添加3个item,再使用客户端脚本在
dropdown list中添加一个item,如果dropdown list的AutoPostBack="True",每次选择list item都会引起postback, 
如果所选的item为dropdown list本来就有的,一切正常.如果所选的item是通过客户端脚本添加的,就会出现异常.

在asp.net render DropDownList 时,会遍历DropDownList的item,并记录所有可能的postback的值,其算法为
hash(DropDownList’s UniqueID XOR hash(ListItem’s Value property)),计算的结果会被保存在page中,

<input type="hidden" 
        name="__EVENTVALIDATION
        id="__EVENTVALIDATION"
        value="/wEWBQKGg9abDQKd9sHMBgKc9s…….." 
/> 
这个过程发生在control的Render()方法中
当页面postback时,ASP.NET会根据这个隐藏值检查postback values,如果找不到对应信息,就会报错

结局方案
1. 禁止这个功能, 但同时会失去一些安全保障:
//—-通过web.config
<system.web>
    <pages enableEventValidation="false"/>
</system.web>
//—-针对某个page
<%@ Page EnableEventValidation="false" … %>

2.Register For Event Validation
其原理就是让asp.net记录这个postback value.
RegisterForEventValidation必须在render时调用.

protected override void Render(HtmlTextWriter writer)
{
    ClientScript.RegisterForEventValidation(_recipeList.UniqueID,"4");
    base.Render(writer);
}

如果我们自己写了一个control,需要使用validate

转载于:https://www.cnblogs.com/huyueping/p/3191739.html

<template> <div class="village-info-container"> <div class="header-card"> <div class="header-content"> <h2>村庄信息管理</h2> <p>管理系统中的村庄信息</p> </div> </div> <el-card class="main-card"> <template #header> <div class="card-header"> <span>村庄信息列表</span> </div> </template> <!-- 搜索表单 --> <el-form :model="searchForm" label-width="80px" class="search-form-inline" style="margin-bottom: 20px;"> <el-row :gutter="20"> <el-col :span="6"> <el-form-item label="村庄名称"> <el-input v-model="searchForm.villageName" placeholder="请输入村庄名称" clearable /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="地理位置"> <el-input v-model="searchForm.location" placeholder="请输入地理位置" clearable /> </el-form-item> </el-col> <el-col :span="12"> <div class="search-buttons"> <el-button type="primary" @click="searchVillageInfos">查询</el-button> <el-button @click="resetSearch">重置</el-button> <el-button type="primary" @click="showAddDialog">新增村庄</el-button> </div> </el-col> </el-row> </el-form> <!-- 表格数据 --> <el-table :data="villageInfoList" v-loading="loading" border style="width: 100%" @selection-change="handleSelectionChange" > <el-table-column type="selection" width="55" /> <el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="villageName" label="村庄名称" width="150" /> <el-table-column prop="location" label="地理位置" width="200" /> <el-table-column prop="population" label="人口数量" width="100" /> <el-table-column prop="cultivatedArea" label="耕地面积(亩)" width="120" /> <el-table-column prop="contactInfo" label="系方式" width="150" /> <el-table-column prop="establishedTime" label="建村时间" width="120"> <template #default="scope"> {{ scope.row.establishedTime }} </template> </el-table-column> <el-table-column label="操作" width="200" fixed="right"> <template #default="scope"> <el-button size="small" @click="showDetail(scope.row)">详情</el-button> <el-button size="small" @click="showEditDialog(scope.row)">编辑</el-button> <el-button size="small" type="danger" @click="deleteVillageInfo(scope.row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 分页 --> <el-pagination v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" class="pagination" /> </el-card> <!-- 添加/编辑对话框 --> <el-dialog v-model="dialogVisible" :title="dialogTitle" width="800px" :before-close="handleDialogClose" > <el-form :model="dialogForm" :rules="dialogRules" ref="dialogFormRef" label-width="100px" > <el-form-item label="村庄名称" prop="villageName"> <el-input v-model="dialogForm.villageName" placeholder="请输入村庄名称" /> </el-form-item> <el-form-item label="地理位置" prop="location"> <div class="location-selector"> <el-input v-model="dialogForm.location" placeholder="请输入地理位置(如:四川省南充市XX县XX镇XX村)" type="textarea" :rows="3" /> <div class="location-hint"> <p>提示:可以手动输入详细地理位置,通过地图选择位置</p> </div> <el-button type="primary" @click="showMapSelector" style="margin-top: 10px;"> 通过地图选择位置 </el-button> </div> </el-form-item> <el-form-item label="人口数量" prop="population"> <el-input-number v-model="dialogForm.population" :min="0" controls-position="right" style="width: 100%" /> </el-form-item> <el-form-item label="耕地面积" prop="cultivatedArea"> <el-input-number v-model="dialogForm.cultivatedArea" :min="0" :precision="2" controls-position="right" style="width: 100%" /> </el-form-item> <el-form-item label="系方式" prop="contactInfo"> <el-input v-model="dialogForm.contactInfo" placeholder="请输入系方式" /> </el-form-item> <el-form-item label="建村时间" prop="establishedTime"> <el-date-picker v-model="dialogForm.establishedTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择建村时间" style="width: 100%" /> </el-form-item> <el-form-item label="村庄简介" prop="villageProfile"> <el-input v-model="dialogForm.villageProfile" placeholder="请输入村庄简介" type="textarea" :rows="3" /> </el-form-item> <el-form-item label="展规划" prop="developmentPlan"> <el-input v-model="dialogForm.developmentPlan" placeholder="请输入展规划" type="textarea" :rows="3" /> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="submitForm">确定</el-button> </span> </template> </el-dialog> <!-- 地图选择对话框 --> <el-dialog v-model="mapDialogVisible" title="选择地理位置" width="800px" @close="handleMapDialogClose" > <div class="map-container"> <div id="map-container" style="width: 100%; height: 400px;"></div> <div class="map-controls"> <el-input v-model="mapSearchKeyword" placeholder="搜索地点(如:四川省南充市)" style="width: 300px; margin-right: 10px;" @keyup.enter="performSearch" /> <el-button type="primary" @click="performSearch">搜索</el-button> <el-button @click="resetMapCenter">重置</el-button> <el-button @click="forceReloadMap" type="warning">重载地图</el-button> </div> <div class="selected-location-info" v-if="selectedLocation"> <p><strong>已选择位置:</strong>{{ selectedLocation.address }}</p> <p><strong>坐标:</strong>{{ selectedLocation.lng }}, {{ selectedLocation.lat }}</p> </div> </div> <template #footer> <span class="dialog-footer"> <el-button @click="mapDialogVisible = false">取消</el-button> <el-button type="primary" @click="confirmLocationSelection" :disabled="!selectedLocation">确定</el-button> </span> </template> </el-dialog> <!-- 详情对话框 --> <el-dialog v-model="detailDialogVisible" title="村庄信息详情" width="600px" > <el-form label-width="100px" class="detail-form"> <el-row> <el-col :span="12"> <el-form-item label="村庄名称:"> <span>{{ detailData.villageName }}</span> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="人口数量:"> <span>{{ detailData.population }}</span> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="耕地面积:"> <span>{{ detailData.cultivatedArea }} 亩</span> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="建村时间:"> <span>{{ detailData.establishedTime }}</span> </el-form-item> </el-col> </el-row> <el-form-item label="地理位置:"> <span>{{ detailData.location }}</span> </el-form-item> <el-form-item label="系方式:"> <span>{{ detailData.contactInfo }}</span> </el-form-item> <el-form-item label="村庄简介:"> <span>{{ detailData.villageProfile }}</span> </el-form-item> <el-form-item label="展规划:"> <span>{{ detailData.developmentPlan }}</span> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button type="primary" @click="detailDialogVisible = false">确定</el-button> </span> </template> </el-dialog> </div> </template> <script setup> import { ref, onMounted, nextTick } from 'vue' import { ElMessage, ElMessageBox } from 'element-plus' import request from '@/utils/request' // 搜索表单 const searchForm = ref({ villageName: '', location: '' }) // 表格数据 const villageInfoList = ref([]) const loading = ref(false) const selectedVillageInfos = ref([]) // 分页参数 const pagination = ref({ pageNum: 1, pageSize: 10, total: 0 }) // 对话框相关 const dialogVisible = ref(false) const dialogTitle = ref('') const dialogForm = ref({ id: null, villageName: '', location: '', population: 0, cultivatedArea: 0, villageProfile: '', developmentPlan: '', contactInfo: '', establishedTime: '' }) // 地图选择相关 const mapDialogVisible = ref(false) const mapSearchKeyword = ref('') const selectedLocation = ref(null) let mapInstance = null let marker = null let currentMapType = 'tencent' // 只使用腾讯地图 let searchTimeout = null // 防抖定时器 // 动态加载地图API const loadMapAPI = () => { return new Promise((resolve, reject) => { console.log('开始加载腾讯地图API') // 检查是否已经存在腾讯地图API if (isTencentMapReady()) { console.log('腾讯地图API已存在且准备就绪') resolve() return } // 检查是否正在加载 const existingScript = document.querySelector('script[src*="map.qq.com"]') if (existingScript) { // 如果正在加载,等待加载完成 console.log('腾讯地图API正在加载中,等待加载完成...') let checkCount = 0 const checkInterval = setInterval(() => { checkCount++ if (isTencentMapReady()) { clearInterval(checkInterval) console.log('腾讯地图API加载完成并准备就绪') resolve() } else if (checkCount > 200) { // 增加超时时间到40秒 clearInterval(checkInterval) console.error('腾讯地图API加载超时') reject(new Error('腾讯地图API加载超时')) } }, 200) return } // 创建script标签加载腾讯地图API,使用callback参数避免document.write问题 const script = document.createElement('script') script.type = 'text/javascript' script.src = 'https://map.qq.com/api/js?v=2.exp&key=FLZBZ-3PLC3-Q4Z3P-RNIS6-EC5TK-UXBTT&callback=onTencentMapCallback' script.async = true script.defer = true script.id = 'tencent-map-script' // 定义回调函数 window.onTencentMapCallback = function() { console.log('腾讯地图API回调执行') // 等待API完全初始化 let checkCount = 0 const checkInterval = setInterval(() => { checkCount++ if (isTencentMapReady()) { clearInterval(checkInterval) console.log('腾讯地图API初始化完成并准备就绪') // 清理回调函数 if (window.onTencentMapCallback) { delete window.onTencentMapCallback } resolve() } else if (checkCount > 200) { // 增加超时时间到40秒 clearInterval(checkInterval) console.error('腾讯地图API初始化超时') // 清理回调函数 if (window.onTencentMapCallback) { delete window.onTencentMapCallback } reject(new Error('腾讯地图API初始化超时')) } }, 200) } script.onload = () => { console.log('腾讯地图API脚本加载成功') } script.onerror = (err) => { console.log('腾讯地图API加载失败', err) // 清理回调函数 if (window.onTencentMapCallback) { delete window.onTencentMapCallback } reject(new Error('腾讯地图API加载失败: ' + (err.message || '未知错误'))) } // 添加额外的安全检查,确保DOM已经准备好 if (document.head) { document.head.appendChild(script) } else { // 如果document.head不存在,等待DOM准备好 const checkDOMInterval = setInterval(() => { if (document.head) { clearInterval(checkDOMInterval) document.head.appendChild(script) } }, 100) } }) } // 修改地图点击事件处理函数 const createTencentMap = () => { try { // 移除可能存在的旧地图实例 if (mapInstance) { mapInstance = null } if (marker) { marker.setMap(null) marker = null } // 再次检查API是否就绪 if (!isTencentMapReady()) { ElMessage.error('腾讯地图API未正确加载,请稍后重试') return } // 检查地图容器 const mapContainer = document.getElementById('map-container') if (!mapContainer) { ElMessage.error('地图容器未找到') return } console.log('创建腾讯地图实例') // 使用更兼容的方式创建地图 const center = new qq.maps.LatLng(39.90923, 116.397428) mapInstance = new qq.maps.Map(mapContainer, { center: center, zoom: 11, disableDefaultUI: false }) // 修复地图点击事件处理 qq.maps.event.addListener(mapInstance, 'click', function(e) { try { // 检查事件对象坐标对象是否存在 if (!e || !e.latLng) { console.error('地图点击事件缺少坐标信息') return } // 关键修复:腾讯地图的LatLng使用属性而非方法获取经纬度 const lat = e.latLng.lat; // 不是e.latLng.lat() const lng = e.latLng.lng; // 不是e.latLng.lng() // 验证坐标是否为有效数字 if (typeof lat !== 'number' || typeof lng !== 'number' || isNaN(lat) || isNaN(lng)) { console.error('获取的坐标不是有效数字:', e.latLng) ElMessage.error('无法获取有效坐标') return } updateTencentMarker({lat, lng}) // 反向地理编码获取地址 const geocoder = new qq.maps.Geocoder({ complete: (res) => { if (res && res.detail) { selectedLocation.value = { lng, lat, address: res.detail.address || `${lng.toFixed(6)}, ${lat.toFixed(6)}` } } else { selectedLocation.value = { lng, lat, address: `${lng.toFixed(6)}, ${lat.toFixed(6)}` } } }, error: () => { selectedLocation.value = { lng, lat, address: `${lng.toFixed(6)}, ${lat.toFixed(6)}` } } }) geocoder.getAddress(e.latLng) } catch (err) { console.error('地图点击事件处理错误:', err) ElMessage.error('处理地图点击事件失败') } }) console.log('腾讯地图实例创建完成') } catch (error) { ElMessage.error('创建腾讯地图实例失败: ' + error.message) console.error('创建腾讯地图实例错误:', error) } } // 增强API就绪检查函数 const isTencentMapReady = () => { try { // 更严格的API检查 if (!window.qq || typeof window.qq !== 'object') { console.log('腾讯地图基础API未加载: window.qq 不存在不是对象') return false } if (!window.qq.maps || typeof window.qq.maps !== 'object') { console.log('腾讯地图基础API未加载: window.qq.maps 不存在不是对象') return false } // 检查核心组件 const requiredConstructors = [ 'Map', 'LatLng', 'Marker', 'Geocoder' ] for (let ctor of requiredConstructors) { if (typeof window.qq.maps[ctor] !== 'function') { console.log(`腾讯地图组件 ${ctor} 未准备好: 不是函数`) return false } } // 检查事件系统 if (!window.qq.maps.event || typeof window.qq.maps.event.addListener !== 'function') { console.log('腾讯地图事件系统未准备好') return false } console.log('所有腾讯地图核心组件均已准备好') return true } catch (error) { console.log('检查腾讯地图状态时出错:', error) return false } } // 详情对话框 const detailDialogVisible = ref(false) const detailData = ref({ id: null, villageName: '', location: '', population: 0, cultivatedArea: 0, villageProfile: '', developmentPlan: '', contactInfo: '', establishedTime: '' }) // 表单验证规则 const dialogRules = { villageName: [ { required: true, message: '请输入村庄名称', trigger: 'blur' } ], location: [ { required: true, message: '请输入地理位置', trigger: 'blur' } ] } // 表单引用 const dialogFormRef = ref(null) // 防抖搜索函数 const debouncedSearch = () => { // 清除之前的定时器 if (searchTimeout) { clearTimeout(searchTimeout) } // 设置新的定时器 searchTimeout = setTimeout(() => { searchMapLocation() }, 500) // 500ms防抖延迟 } // 获取村庄信息列表 const getVillageInfoList = () => { loading.value = true const params = { pageNum: pagination.value.pageNum, pageSize: pagination.value.pageSize, villageName: searchForm.value.villageName, location: searchForm.value.location } request.get('/villageInfo/selectPage', { params }).then(res => { loading.value = false if (res.code === '200') { villageInfoList.value = res.data.list pagination.value.total = res.data.total } else { ElMessage.error(res.msg || '获取村庄信息列表失败') } }).catch(err => { loading.value = false ElMessage.error('获取村庄信息列表失败,请稍后重试') console.error('获取村庄信息列表错误:', err) }) } // 搜索村庄信息 const searchVillageInfos = () => { pagination.value.pageNum = 1 getVillageInfoList() } // 重置搜索 const resetSearch = () => { searchForm.value.villageName = '' searchForm.value.location = '' pagination.value.pageNum = 1 getVillageInfoList() } // 处理分页大小变化 const handleSizeChange = (val) => { pagination.value.pageSize = val pagination.value.pageNum = 1 getVillageInfoList() } // 处理当前页变化 const handleCurrentChange = (val) => { pagination.value.pageNum = val getVillageInfoList() } // 处理选中项变化 const handleSelectionChange = (val) => { selectedVillageInfos.value = val } // 显示添加对话框 const showAddDialog = () => { dialogTitle.value = '新增村庄信息' dialogForm.value = { id: null, villageName: '', location: '', population: 0, cultivatedArea: 0, villageProfile: '', developmentPlan: '', contactInfo: '', establishedTime: '' } dialogVisible.value = true } // 显示编辑对话框 const showEditDialog = (row) => { dialogTitle.value = '编辑村庄信息' dialogForm.value = { ...row } dialogVisible.value = true } // 提交表单 const submitForm = () => { try { dialogFormRef.value.validate((valid) => { if (valid) { const formData = { ...dialogForm.value } if (dialogForm.value.id) { // 更新操作 request.put('/villageInfo/update', formData).then(res => { if (res.code === '200') { ElMessage.success('更新成功') dialogVisible.value = false getVillageInfoList() } else { ElMessage.error(res.msg || '更新失败') } }).catch(err => { ElMessage.error('更新失败,请稍后重试') console.error('更新村庄信息错误:', err) }) } else { // 添加操作 request.post('/villageInfo/add', formData).then(res => { if (res.code === '200') { ElMessage.success('添加成功') dialogVisible.value = false getVillageInfoList() } else { ElMessage.error(res.msg || '添加失败') } }).catch(err => { ElMessage.error('添加失败,请稍后重试') console.error('添加村庄信息错误:', err) }) } } }) } catch (error) { ElMessage.error('表单提交失败: ' + error.message) console.error('表单提交错误:', error) } } // 删除村庄信息 const deleteVillageInfo = (row) => { try { ElMessageBox.confirm(`确定要删除村庄"${row.villageName}"吗?`, '删除确认', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { request.delete(`/villageInfo/delete/${row.id}`).then(res => { if (res.code === '200') { ElMessage.success('删除成功') getVillageInfoList() } else { ElMessage.error(res.msg || '删除失败') } }).catch(err => { ElMessage.error('删除失败,请稍后重试') console.error('删除村庄信息错误:', err) }) }).catch(() => { // 取消删除 }) } catch (error) { ElMessage.error('删除操作失败: ' + error.message) console.error('删除操作错误:', error) } } // 关闭对话框前的处理 const handleDialogClose = (done) => { try { ElMessageBox.confirm('确认关闭?修改的内容将不会保存', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { done() }).catch(() => { // 取消关闭 }) } catch (error) { ElMessage.error('关闭对话框处理失败: ' + error.message) console.error('关闭对话框错误:', error) } } // 显示地图选择器 const showMapSelector = () => { console.log('显示地图选择器') mapDialogVisible.value = true nextTick(() => { console.log('nextTick回调执行') try { // 确保在DOM更新后再初始化地图 setTimeout(() => { initMap() }, 100) } catch (error) { ElMessage.error('初始化地图失败: ' + error.message) console.error('初始化地图失败:', error) } }) } // 初始化地图 const initMap = () => { console.log('开始初始化地图') // 检查地图容器是否存在 const mapContainer = document.getElementById('map-container') if (!mapContainer) { console.error('地图容器不存在') ElMessage.error('地图容器未找到') return } // 直接尝试创建地图,如果API未加载则加载API createMap() } // 创建地图实例 const createMap = () => { console.log('开始创建地图实例') // 检查地图容器是否存在 const mapContainer = document.getElementById('map-container') if (!mapContainer) { console.error('地图容器不存在') ElMessage.error('地图容器未找到') return } if (mapInstance) { console.log('地图实例已存在') return } try { // 检查腾讯地图API是否已加载并且组件可用 if (isTencentMapReady()) { console.log('创建腾讯地图实例') createTencentMap() } else { // 如果API未完全加载,则加载API console.log('需要加载腾讯地图API') ElMessage.info('正在加载地图服务...') loadMapAPI().then(() => { // 确保组件可用后再创建地图 if (isTencentMapReady()) { createTencentMap() } else { ElMessage.error('腾讯地图API组件未正确加载') } }).catch(err => { ElMessage.error('地图加载失败: ' + err.message) console.error('地图加载错误:', err) }) } } catch (error) { ElMessage.error('创建地图实例失败: ' + error.message) console.error('地图初始化错误:', error) } } // 执行搜索 const performSearch = () => { console.log('搜索关键词:', mapSearchKeyword.value) if (!mapSearchKeyword.value) { ElMessage.warning('请输入搜索关键词') return } console.log('使用腾讯地图进行搜索') // 检查API是否已加载 if (isTencentMapReady()) { searchTencentMapLocation() } else { // 如果API未加载,先加载API再搜索 ElMessage.info('正在加载地图服务...') loadMapAPI().then(() => { if (isTencentMapReady()) { searchTencentMapLocation() } else { ElMessage.error('地图服务加载失败') } }).catch(err => { ElMessage.error('地图服务加载失败: ' + err.message) }) } } // 改进地理编码搜索函数 const searchTencentMapLocation = () => { if (!mapSearchKeyword.value) { ElMessage.warning('请输入搜索关键词') return } if (!isTencentMapReady()) { ElMessage.error('腾讯地图API未正确加载') return } try { console.log('开始腾讯地图搜索,关键词:', mapSearchKeyword.value) if (typeof qq.maps.Geocoder !== 'function') { ElMessage.error('地理编码服务不可用') return } // 检查API密钥是否有效(简单验证) const scriptTags = document.getElementsByTagName('script'); let apiKey = null; for (let tag of scriptTags) { if (tag.src && tag.src.includes('map.qq.com/api/js')) { const match = tag.src.match(/key=([^&]+)/); if (match && match[1]) { apiKey = match[1]; break; } } } if (!apiKey) { console.warn('未检测到腾讯地图API密钥,请检查加载地址'); ElMessage.warning('地图服务配置可能存在问题'); } const geocoder = new qq.maps.Geocoder({ complete: (results) => { try { console.log('地理编码完整结果:', results); if (!results || !results.detail) { console.log('地理编码结果结构不完整'); ElMessage.warning('未找到匹配的位置信息'); return; } // 检查是否有错误代码 if (results.detail.error) { console.error('地理编码返错误代码:', results.detail.error); handleGeocoderError(results.detail.error); return; } if (!results.detail.location) { console.log('地理编码结果中没有位置信息'); ElMessage.warning('未找到匹配的位置信息'); return; } // 获取位置信息 const location = results.detail.location; if (typeof location.lat !== 'number' || typeof location.lng !== 'number') { console.error('获取的坐标不是有效数字:', location); ElMessage.error('获取位置坐标失败'); return; } const lat = location.lat; const lng = location.lng; if (isNaN(lat) || isNaN(lng)) { ElMessage.error('获取的坐标无效'); return; } mapInstance.setCenter(location); updateTencentMarker({lat, lng}); let address = ''; if (results.detail.address) { address = results.detail.address; } else if (results.detail.formattedAddress) { address = results.detail.formattedAddress; } else if (results.detail.pois && results.detail.pois.length > 0) { address = results.detail.pois[0].name || mapSearchKeyword.value; } else { address = mapSearchKeyword.value; } selectedLocation.value = { lng, lat, address: address }; ElMessage.success('搜索成功'); } catch (e) { console.error('处理地理编码结果错误:', e); ElMessage.error('处理位置信息失败: ' + e.message); } }, error: (error) => { try { // 详细打印错误信息 console.error('地理编码错误详情:', { error: error, errorType: typeof error, errorString: JSON.stringify(error), keyword: mapSearchKeyword.value }); // 尝试解析常见错误 if (error && error.status === 110) { ElMessage.error('API密钥无效未授权,请检查密钥配置'); } else if (error && error.status === 100) { ElMessage.error('请求参数错误,请检查输入'); } else if (error && error.message) { ElMessage.error('搜索失败: ' + error.message); } else { ElMessage.error('搜索失败,请尝试其他关键词检查网络连接'); } } catch (e) { console.error('处理地理编码错误时出错:', e); ElMessage.error('搜索过程生错误'); } } }); console.log('送地理编码请求:', mapSearchKeyword.value); geocoder.getLocation(mapSearchKeyword.value); } catch (error) { console.error('地理编码初始化失败:', error); ElMessage.warning('无法使用地图搜索,将直接使用输入的文本作为地址'); selectedLocation.value = { lng: 0, lat: 0, address: mapSearchKeyword.value }; } }; // 处理地理编码错误代码 const handleGeocoderError = (errorCode) => { const errorMessages = { 1: '服务器内部错误', 100: '请求参数非法', 101: 'AK不存在非法', 102: '没有权限使用该服务', 103: '请求被限制', 104: '请求次数不足', 105: 'AK过期', 106: '服务当前不可用', 107: '不支持的接口', 108: '接口被禁用' }; const message = errorMessages[errorCode] || `地理编码错误 (代码: ${errorCode})`; ElMessage.error(`搜索失败: ${message}`); // 针对常见错误给出解决方案 if (errorCode === 101 || errorCode === 105) { console.warn('请检查腾讯地图API密钥是否有效,是否已添加当前域名到白名单'); } else if (errorCode === 102 || errorCode === 103) { console.warn('当前API密钥可能没有地理编码服务权限请求频率超限'); } }; // 增加一个测试API连接的函数 const testMapApiConnection = () => { if (!isTencentMapReady()) { ElMessage.error('地图API未就绪'); return; } try { // 创建一个简单的LatLng对象测试API是否正常工作 const testLatLng = new qq.maps.LatLng(39.90923, 116.397428); console.log('API功能测试: 成功创建LatLng对象', testLatLng); // 测试事件系统 const testObj = { test: true }; qq.maps.event.addListener(testObj, 'test', () => { console.log('API功能测试: 事件系统工作正常'); }); qq.maps.event.trigger(testObj, 'test'); ElMessage.success('地图API连接测试成功'); } catch (error) { console.error('API功能测试失败:', error); ElMessage.error('地图API功能异常: ' + error.message); } } // 处理搜索完成结果 const handleSearchComplete = (results) => { try { console.log('腾讯地图搜索结果:', results) // 检查结果对象是否存在 if (!results) { console.log('腾讯地图搜索无结果') ElMessage.error('未找到指定位置,请检查地址是否正确') return } // 检查详细信息是否存在 if (!results.detail) { console.log('腾讯地图搜索详情不存在') ElMessage.error('搜索结果格式不正确') return } console.log('腾讯地图搜索详情:', results.detail) // 检查POI数据 if (results.detail.pois && Array.isArray(results.detail.pois) && results.detail.pois.length > 0) { // 使用第一个结果进行定位 const firstPoi = results.detail.pois[0] console.log('第一个POI:', firstPoi) // 检查POI的坐标信息 if (firstPoi && firstPoi.latLng) { const location = firstPoi.latLng console.log('定位坐标:', location) // 确保坐标值有效 if (typeof location.lat === 'number' && typeof location.lng === 'number') { mapInstance.setCenter(location) updateTencentMarker({lat: location.lat, lng: location.lng}) // 获取地址信息,确保不访问未定义的属性 const name = firstPoi.name || '' const address = firstPoi.address || '' const title = firstPoi.title || '' selectedLocation.value = { lng: location.lng, lat: location.lat, address: name || address || title || mapSearchKeyword.value } ElMessage.success('搜索成功') console.log('已选择位置:', selectedLocation.value) return } } } // 如果没有搜索到结果结果不完整 console.log('腾讯地图搜索无有效结果') ElMessage.error('未找到指定位置位置信息不完整,请检查地址是否正确') } catch (e) { console.error('处理搜索结果时生错误:', e) ElMessage.error('处理搜索结果失败: ' + (e.message || '未知错误')) } } // 处理搜索错误 const handleSearchError = (error) => { try { console.error('腾讯地图搜索失败:', error) // 检查错误对象是否存在及属性访问 const errorMessage = error ? (error.message || '未知错误') : '未知错误' ElMessage.error('搜索失败: ' + errorMessage) } catch (e) { console.error('处理搜索错误时生错误:', e) ElMessage.error('处理搜索错误失败: ' + (e.message || '未知错误')) } } // 使用地理编码器进行搜索(备选方案) const performGeocoderSearch = () => { try { if (!mapSearchKeyword.value) { ElMessage.warning('请输入搜索关键词') return } // 检查地理编码器是否可用 if (typeof qq.maps.Geocoder !== 'function') { ElMessage.error('腾讯地图地理编码服务不可用') return } const geocoder = new qq.maps.Geocoder() // 添加事件监听器 qq.maps.event.addListener(geocoder, 'complete', function(results) { try { console.log('地理编码结果:', results) if (results && results.detail && results.detail.location) { const location = results.detail.location mapInstance.setCenter(location) updateTencentMarker({lat: location.lat, lng: location.lng}) selectedLocation.value = { lng: location.lng, lat: location.lat, address: mapSearchKeyword.value } ElMessage.success('搜索成功') console.log('已选择位置:', selectedLocation.value) } else { ElMessage.error('未找到指定位置,请检查地址是否正确') } } catch (geocoderResultError) { console.error('处理地理编码结果失败:', geocoderResultError) ElMessage.error('处理搜索结果失败: ' + (geocoderResultError.message || '未知错误')) } }) qq.maps.event.addListener(geocoder, 'error', function(error) { try { console.error('地理编码失败:', error) const errorMessage = error ? (error.message || '未知错误') : '未知错误' ElMessage.error('搜索失败: ' + errorMessage) } catch (e) { console.error('处理地理编码错误时生错误:', e) ElMessage.error('处理搜索错误失败: ' + (e.message || '未知错误')) } }) // 执行地理编码 geocoder.getLocation(mapSearchKeyword.value) } catch (geocoderError) { console.error('初始化地理编码器失败:', geocoderError) ElMessage.error('搜索初始化失败: ' + (geocoderError.message || '未知错误')) } } // 处理地图对话框关闭 const handleMapDialogClose = () => { try { // 清理地图实例 if (mapInstance) { mapInstance = null } if (marker) { marker.setMap(null) marker = null } selectedLocation.value = null } catch (error) { console.error('清理地图资源失败:', error) } } // 强制重载地图 const forceReloadMap = () => { try { ElMessage.info('正在重载地图...') // 清理现有地图实例资源 if (mapInstance) { mapInstance = null } if (marker) { marker.setMap(null) marker = null } selectedLocation.value = null // 移除现有的腾讯地图脚本 const existingScript = document.querySelector('#tencent-map-script') if (existingScript) { document.head.removeChild(existingScript) } // 清理全局回调函数 if (window.onTencentMapCallback) { delete window.onTencentMapCallback } // 重新初始化地图 setTimeout(() => { initMap() }, 500) } catch (error) { ElMessage.error('重载地图失败: ' + error.message) console.error('重载地图失败:', error) } } // 重置地图中心 const resetMapCenter = () => { try { if (mapInstance && window.qq && window.qq.maps && typeof qq.maps.LatLng === 'function') { const center = new qq.maps.LatLng(39.90923, 116.397428) mapInstance.setCenter(center) } else { ElMessage.error('地图未正确初始化') return } if (marker) { marker.setMap(null) marker = null } selectedLocation.value = null } catch (error) { ElMessage.error('重置地图失败: ' + error.message) console.error('重置地图错误:', error) } } // 确认位置选择 const confirmLocationSelection = () => { if (selectedLocation.value) { dialogForm.value.location = selectedLocation.value.address mapDialogVisible.value = false } else { ElMessage.warning('请先在地图上选择位置') } } // 腾讯地图点击事件处理 const onTencentMapClick = (e) => { try { // 检查必要组件 if (!window.qq || !window.qq.maps) { ElMessage.error('腾讯地图API未正确初始化') return } const lat = e.latLng.getLat() const lng = e.latLng.getLng() const lnglat = { lat, lng } // 更新标记位置 updateTencentMarker(lnglat) // 设置选中位置 selectedLocation.value = { lng: lng, lat: lat, address: `${lng.toFixed(6)}, ${lat.toFixed(6)}` } ElMessage.info('已选择地图位置') } catch (error) { ElMessage.error('处理地图点击事件失败: ' + error.message) console.error('地图点击事件错误:', error) } } // 更新腾讯地图标记 const updateTencentMarker = (lnglat) => { try { // 检查必要组件是否可用 if (!window.qq || !window.qq.maps) { console.log('腾讯地图API未加载') return } if (typeof qq.maps.Marker !== 'function' || typeof qq.maps.LatLng !== 'function') { console.log('腾讯地图标记组件未准备好') return } // 验证坐标有效性 if (typeof lnglat.lat !== 'number' || typeof lnglat.lng !== 'number' || isNaN(lnglat.lat) || isNaN(lnglat.lng)) { console.error('无效的坐标值:', lnglat) return } // 创建新的LatLng对象,注意这里的参数顺序是纬度(lat)在前,经度(lng)在后 const position = new qq.maps.LatLng(lnglat.lat, lnglat.lng) if (!marker) { marker = new qq.maps.Marker({ position: position, map: mapInstance }) } else { marker.setPosition(position) } mapInstance.setCenter(position) } catch (error) { console.log('更新地图标记失败:', error.message) } } // 页面加载时获取数据 onMounted(() => { try { getVillageInfoList() } catch (error) { ElMessage.error('页面初始化失败: ' + error.message) console.error('页面初始化错误:', error) } }) </script> <style scoped> .village-info-container { padding: 20px; background-color: #f5f7fa; min-height: calc(100vh - 60px); } .header-card { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); color: white; } .header-content h2 { margin: 0 0 10px 0; font-size: 24px; font-weight: 600; } .header-content p { margin: 0; font-size: 14px; opacity: 0.9; } .main-card { margin-bottom: 20px; } .card-header { font-weight: bold; font-size: 16px; } .search-form-inline { display: flex; flex-wrap: wrap; } .search-buttons { display: flex; justify-content: flex-end; align-items: flex-end; height: 100%; gap: 10px; } .pagination { margin-top: 20px; display: flex; justify-content: center; } .detail-form .el-form-item { margin-bottom: 15px; } .detail-form .el-form-item__label { font-weight: bold; } .detail-form .el-form-item__content { display: flex; align-items: center; } .map-container { width: 100%; } .map-controls { margin: 15px 0; display: flex; align-items: center; } .selected-location-info { margin-top: 15px; padding: 10px; background-color: #f5f7fa; border-radius: 4px; } </style>出现搜索任何位置都报错搜索关键词: 四川省南充市高坪区 VillageInfo.vue:810 使用腾讯地图进行搜索 VillageInfo.vue:503 所有腾讯地图核心组件均已准备好 VillageInfo.vue:503 所有腾讯地图核心组件均已准备好 VillageInfo.vue:843 开始腾讯地图搜索,关键词: 四川省南充市高坪区 VillageInfo.vue:961 送地理编码请求: 四川省南充市高坪区 VillageInfo.vue:937 地理编码错误详情: {error: 'ERROR', errorType: 'string', errorString: '"ERROR"', keyword: '四川省南充市高坪区'} error @ VillageInfo.vue:937 De.onError @ VM5520:1 De.onLoad @ VM5520:1 eval @ VM5520:1 f.<computed> @ main.js:1 script sk @ main.js:1 (匿名) @ main.js:1 sa.ready @ main.js:1 send @ main.js:1 De.send @ VM5520:1 De.doSend_changed @ VM5520:1 Lc @ main.js:1 mk @ main.js:1 jb.bindTo @ main.js:1 X @ VM5520:1 (匿名) @ main.js:1 $require @ main.js:1 (匿名) @ main.js:1 (匿名) @ main.js:1 (匿名) @ main.js:1 ha @ main.js:1 E.trigger @ main.js:1 Lc @ main.js:1 jb.set @ main.js:1 (匿名) @ main.js:1 Ui @ main.js:1 hh.send @ main.js:1 kh.getLocation @ main.js:1 searchTencentMapLocation @ VillageInfo.vue:962 performSearch @ VillageInfo.vue:814 callWithErrorHandling @ runtime-core.esm-bundler.js:199 callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:206 emit @ runtime-core.esm-bundler.js:6386 (匿名) @ runtime-core.esm-bundler.js:8099 handleClick @ use-button.ts:61 callWithErrorHandling @ runtime-core.esm-bundler.js:199 callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:206 invoker @ runtime-dom.esm-bundler.js:729
09-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值