(转)AS3.0/Flex中的弱引用 .

本文详细解释了AS3中的弱引用概念及其在addEventListener方法和Dictionary类中的应用,阐述了弱引用与强引用的区别,并通过代码实例展示了如何利用弱引用避免内存泄漏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自:http://blog.youkuaiyun.com/sysu_2010/article/details/6608256

弱引用英文叫做weak reference,与之相反的是强引用(strong reference)。引用不是对象本身,而是类似于指向对象的一个指针。通常都说当至少还存在一个引用指向某个对象的时候,这个对象就不会被gc,这里所说的引用就是强引用,而不是弱引用。反过来说,即使有N多弱引用指向某个对象,而没有一个强引用指向该对象时,这个对象也会被gc,当gc发生后,所有的弱引用指向的对象就不存在了。这就是强引用与弱引用的本质区别。

AS3中常用到弱引用的地方有addEventListener方法和Dictionary类。
addEventListener方法的参数表为addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false)。其中第5个参数表示是否使用弱引用。也就是说当useWeakReference=false时,EventDispatcher.addEventListener就会在EventDispatcher对象中添加一个对listener这个函数对象的强引用;而当useWeakReference=true时,EventDispatcher.addEventListener方法在EventDispatcher对象中添加的是对listener的弱引用,此时如果这个listener函数对象只是作为EventDispatcher对象的征听器被引用时,那么gc执行时就会回收这个listener函数,从而EventDispatcher对象的这个征听器就不存在了。用简单的代码来证明一下:

 

[javascript] view plain copy print ?
  1. var sp:Sprite = new Sprite();  
  2. var eventHandler:Function = function(e:Event){ trace(“event fired”); };  
  3. //添加弱引用   
  4. sp.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);  
  5. //取消eventHandler对函数的引用   
  6. eventHandler = null;  
  7. //强制进行gc,此函数只能在debug版的fp中才有效   
  8. System.gc();  
  9. /* 
  10. 运行结果:因为sp.addEventListener中添加的是对eventHandler函数的弱引用,当唯一指向函数的强引用eventHandler变成null以后,这个征听器函数就会被gc。不过gc不是立即发生,因此要强制进行gc后才能看到在输出窗口中不会有event fired输出。如果在sp.addEventListener使用强引用,那么当eventHandler变成null以后,即使进行强制gc,还是会不断输出event fired。因为征听器函数还作为sp的一个征听器被引用,而且是强引用,因此就不会被gc。 
  11. */  
var sp:Sprite = new Sprite();
var eventHandler:Function = function(e:Event){ trace(“event fired”); };
//添加弱引用
sp.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);
//取消eventHandler对函数的引用
eventHandler = null;
//强制进行gc,此函数只能在debug版的fp中才有效
System.gc();
/*
运行结果:因为sp.addEventListener中添加的是对eventHandler函数的弱引用,当唯一指向函数的强引用eventHandler变成null以后,这个征听器函数就会被gc。不过gc不是立即发生,因此要强制进行gc后才能看到在输出窗口中不会有event fired输出。如果在sp.addEventListener使用强引用,那么当eventHandler变成null以后,即使进行强制gc,还是会不断输出event fired。因为征听器函数还作为sp的一个征听器被引用,而且是强引用,因此就不会被gc。
*/

上面的例子留下来了一个问题:如果sp.addEventListerner添加的是强引用,当指向征听器函数的eventHandler设为空后,这个征听器函数仍然不会被gc,那么怎样才能让它被gc掉呢?答案很显然,也就是当sp被gc掉以后,那么这个征听器函数也会被gc掉,因为sp指向的对象中保留了对征听器的唯一强引用。sp怎么才能被gc掉?从AS2走过来的人往往都容易想到removeChild方法。但是AS3中的removeChild方法作用只是把一个DisplayObject对象从Display List中删除,同时也删除Display List中所存在的对这个DisplayObject对象的引用。但是如果这个DisplayObject对象还被其它变量引用时,它就不会被gc。所以说removeChild是必须的,但不足够,还需要删除Display List之外的所有引用才行!当然如果这个DisplayObject不在Display List中的话,就没有必要removeChild。下面也用一个例子说明一下:

 

 

[javascript] view plain copy print ?
  1. var sp1:Sprite = new Sprite();  
  2. var sp2:Sprite = new Sprite();  
  3. var eventHandler:Function = function(e:Event){trace(“event fired”);};  
  4. //sp1添加对eventHandler的强引用   
  5. sp1.addEventListener(Event.ENTER_FRAME,eventHandler);  
  6. //sp2添加对eventHandler的弱引用,用于查看sp1被gc后征听器是否也被gc   
  7. sp2.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);  
  8. //取消eventHandler对函数的引用   
  9. eventHandler = null;  
  10. //取消sp1对Sprite对象的引用使其可以被gc,因为Sprite对象没有添加到Display List中,所以不需要removeChild。   
  11. sp1 = null;  
  12. //强制进行gc,此函数只能在debug版的fp中使用   
  13. System.gc();  
  14. /* 
  15. 运行结果:当取消eventHandler对函数的引用后,对函数唯一的强引用就只存在与sp1所引用的Sprite对象中,当sp1不再引用Sprite对象时,这个Sprite对象就会被gc,因此对征听器函数的唯一强引用也没了,剩下sp2中对函数的引用是弱引用,因此强制gc后,sp2的征听器就没了,所以就不会看到输出event fired。同样的如果取消sp1对Sprite对象的引用,而是使用sp1的removeEventListerner方法取消对征听器函数的引用,征听器函数也会被gc,而sp1引用的Sprite对象还存在。 
  16. */  
var sp1:Sprite = new Sprite();
var sp2:Sprite = new Sprite();
var eventHandler:Function = function(e:Event){trace(“event fired”);};
//sp1添加对eventHandler的强引用
sp1.addEventListener(Event.ENTER_FRAME,eventHandler);
//sp2添加对eventHandler的弱引用,用于查看sp1被gc后征听器是否也被gc
sp2.addEventListener(Event.ENTER_FRAME,eventHandler,false,0,true);
//取消eventHandler对函数的引用
eventHandler = null;
//取消sp1对Sprite对象的引用使其可以被gc,因为Sprite对象没有添加到Display List中,所以不需要removeChild。
sp1 = null;
//强制进行gc,此函数只能在debug版的fp中使用
System.gc();
/*
运行结果:当取消eventHandler对函数的引用后,对函数唯一的强引用就只存在与sp1所引用的Sprite对象中,当sp1不再引用Sprite对象时,这个Sprite对象就会被gc,因此对征听器函数的唯一强引用也没了,剩下sp2中对函数的引用是弱引用,因此强制gc后,sp2的征听器就没了,所以就不会看到输出event fired。同样的如果取消sp1对Sprite对象的引用,而是使用sp1的removeEventListerner方法取消对征听器函数的引用,征听器函数也会被gc,而sp1引用的Sprite对象还存在。
*/

Dictionary的弱引用与addEventListener的原理相同,只不过Dictionary的弱引用指的是对key的弱引用,而不是对value的弱引用。实际上Dictionary对象中保留的是对value的强引用,而且就算value对应的key对象已经被gc了,Dictionary对象中对value的强引用还存在,而且还造成一个不好的影响,就是key被gc后,就无法删除Dictionary对象中对value的强引用。因此我觉得在使用Dictionary对象的时候,如果要删除key的话,应首先delete Dictionary对象中对value的强引用。

[javascript] view plain copy print ?
  1. //true表示使用弱引用   
  2. var dic:Dictionary = new Dictionary(true);  
  3. //建立key和value,之所以把key和value都定为函数,是为了检查其是否被gc掉   
  4. var key:Function = function (e:Event){trace(“key is alive”);};  
  5. var value:Function = function (e:Event){trace(“value is alive”);};  
  6. //把key和value都加为弱引用的征听器,不影响它们被gc   
  7. addEventListener(Event.ENTER_FRAME,key,false,0,true);  
  8. addEventListener(Event.ENTER_FRAME,value,false,0,true);  
  9. //取消value引用,取消后函数唯一的强引用就存在dic中   
  10. value = null;  
  11. /*取消key引用,dic使用弱引用,因此函数会被gc。再此如果不删除dic中对value的引用,以后就没机会删除了。删除对value的引用可使用delete dic[key];*/  
  12. key = null;  
  13. //强制gc   
  14. System.gc();  
  15. /* 
  16. 运行结果:当取消key对函数的引用后,函数就会被gc。而取消value引用后,在dic中还存在对函数的强引用,因此key对应的征听器不输出了,而value对应的征听器还在输出。而且在取消key引用之前没有删除dic对value的强引用,那么之后只能通过gc掉dic才能使value对应的函数被gc。 
  17. */  
<template> <div @click="handleItemClick" :class="{ active: isActive }" class="flex pr-1 justify-between cursor-pointer text-sm items-center text-gray-600 hover:text-blue-600 hover:bg-gray-50 py-2 rounded" > <div class="label"> {{ item.name }} </div> <!-- 图层从未被添加,为+号 --> <div class="action" v-if="!ishasLayer" @click="handleAddClick"> <svg t="1744775956629" class="icon h-3 w-3 text-gray-400 cursor-pointer hover:text-gray-600" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2776" width="96" height="96" fill="currentColor" > <path d="M864 415H610V161c0-53.3-43.7-97-97-97s-97 43.7-97 97v254H162c-53.3 0-97 43.6-97 97 0 53.3 43.7 97 97 97h254v254c0 53.3 43.7 97 97 97s97-43.7 97-97V609h254c53.3 0 97-43.7 97-97 0-53.4-43.7-97-97-97z" p-id="2777" ></path> </svg> </div> <!-- 图层已被添加,为-号 --> <div class="action" v-else @click="handleDelClick"> <svg t="1744775956629" class="icon h-3 w-3 text-gray-400 cursor-pointer hover:text-gray-600" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2776" width="96" height="96" fill="currentColor" > <path d="M864 415H161c-53.3 0-97 43.7-97 97s43.7 97 97 97h703c53.3 0 97-43.7 97-97s-43.7-97-97-97z" p-id="2777" ></path> </svg> </div> </div> </template> <script setup> import { fromJSON } from &#39;postcss&#39; import { defineProps, onMounted, inject, ref, computed } from &#39;vue&#39; import { addLayerToViewer, delLayerFromViewer } from &#39;@/libs/layerUtil&#39; import { getTrueViewer, getViewer } from &#39;@/libs/viewer&#39; import store from &#39;@/store/index.js&#39; import * as Cesium from &#39;cesium&#39; import { fetchData, fly } from &#39;@/layout/utils/todo.js&#39; // 计算属性,某id图层是否存在 const ishasLayer = computed(() => { return store.getters[&#39;LayerData/hasLayerData&#39;](props.item.id) }) // 使用 ref 存储服务器数据 const jsonData = ref(null) // 计算属性基于已加载的数据 // computed 属性不能直接返回异步函数的结果。fetchData 是一个异步函数,返回的是 Promise,而 computed 属性期望的是同步返回值。 const dataArray = computed(() => { return jsonData.value?.WMS_Capabilities?.Capability?.Layer?.Layer || [] }) // 在组件挂载时或需要时加载数据 // fetchData 返回 Promise:你的 fetchData 函数是异步的,返回的是 Promise 对象 const loadData = async () => { jsonData.value = await fetchData() } const props = defineProps({ item: { type: Object, default: () => {} } }) const isActive = computed(() => { return store.state.LayerData.selectLayer?.id === props.item.id }) // 注入关闭面板的方法 const closePanel = inject(&#39;closeDataAddPanel&#39;) /* * 处理图层项点击事件 * @param {Object} item - 图层项对象 */ const handleItemClick = async () => { store.commit(&#39;LayerData/setSelectLayer&#39;, props.item) } /** * 处理添加图层点击事件 */ // const handleAddClick = async () => { // // 1. 获取Viewer实例 // const viewer = getViewer() // if (!viewer) { // console.error(&#39;Viewer实例未找到&#39;) // return // } // // 2. 检查图层是否已存在 // const layerId = props.item.id // if (store.getters[&#39;LayerData/hasLayerData&#39;](layerId)) { // // 弹窗提示图层已存在 // alert(&#39;图层已存在,请勿重复添加。&#39;) // return // } // // 3.PANO图层另行处理 // if (props.item.type === &#39;PANO&#39; && props.item.subType === &#39;line&#39;) { // console.log(&#39;PANO图层,开始加载线路数据&#39;) // // 获得真实的Viewer实例 // const trueviewer = getTrueViewer() // if (!trueviewer) { // console.error(&#39;Viewer实例未找到&#39;) // return // } // try { // // 存储数据源引用 // const dataSource1 = ref([]) // // 加载第一个GeoJSON数据源 // dataSource1.value = await Cesium.GeoJsonDataSource.load(props.item.url1, { // stroke: Cesium.Color.HOTPINK, // fill: Cesium.Color.PINK.withAlpha(0.3), // strokeWidth: 3, // clampToGround: true // 贴地显示 // }) // // dataSource1.name = `${props.item.id}_line1` // trueviewer.dataSources.add(dataSource1.value) // // // 加载第二个GeoJSON数据源 // // const dataSource2 = await Cesium.GeoJsonDataSource.load(props.item.url2, { // // stroke: Cesium.Color.HOTPINK, // // fill: Cesium.Color.RED.withAlpha(0.3), // // strokeWidth: 3, // // clampToGround: true // 贴地显示 // // }) // // dataSource2.name = `${props.item.id}_line2` // // viewer.dataSources.add(dataSource2) // // dataSources.value.push(dataSource2) // // // 添加到状态管理 // // const layerData = { // // option: { // // ...props.item, // // dataSources: dataSources.value // 保存数据源引用 // // }, // // panel_visible: true, // // id: props.item.id, // // type: &#39;system&#39;, // // name: props.item.name || &#39;PANO线路数据&#39; // // } // // store.commit(&#39;LayerData/addLayerData&#39;, layerData) // // 使用更可靠的flyTo方法 // trueviewer.flyTo(dataSource1.value, { // duration: 3, // offset: new Cesium.HeadingPitchRange(0, -0.5, 0) // }) // // 关闭面板 // closePanel?.() // } catch (error) { // console.error(&#39;加载PANO线路数据失败:&#39;, error) // alert(`加载线路数据失败: ${error.message}`) // // 清理已加载的数据源(如果有) // dataSources.value.forEach((ds) => { // if (viewer.dataSources.contains(ds)) { // viewer.dataSources.remove(ds) // } // }) // } // } else { // console.log(&#39;非PANO图层,开始添加图层&#39;) // // 非PANO图层处理 // try { // // 3. 准备图层数据 // const layerData = { // option: props.item, // panel_visible: true, // id: layerId, // type: &#39;system&#39; // } // console.log(&#39;正在添加图层,ID:&#39;, layerId) // // 4. 添加到地图和状态管理 // const layerInstance = addLayerToViewer(props.item, viewer) // store.commit(&#39;LayerData/addLayerData&#39;, layerData) // // 5. 飞行到图层范围 // // 确保数据已加载 // if (!jsonData.value) { // await loadData() // 等待数据加载完成 // } // fly(dataArray.value, viewer, layerInstance, props.item) // // 关闭面板 // closePanel?.() // } catch (error) { // console.error(&#39;添加图层失败:&#39;, error) // alert(`操作失败: ${error.message}`) // } // } // } const handleAddClick = async () => { const viewer = getViewer() if (!viewer) { console.error(&#39;Viewer实例未找到&#39;) return } const layerId = props.item.id if (store.getters[&#39;LayerData/hasLayerData&#39;](layerId)) { alert(&#39;图层已存在,请勿重复添加。&#39;) return } if (props.item.type === &#39;PANO&#39; && props.item.subType === &#39;line&#39;) { console.log(&#39;PANO图层,开始加载线路数据&#39;) const trueviewer = getTrueViewer() if (!trueviewer) { console.error(&#39;Viewer实例未找到&#39;) return } try { trueviewer.scene.requestRenderMode = false // 暂停渲染模式 // 1. 并行加载点数据和线数据 const [pointsResponse, linesResponse] = await Promise.all([ fetch(props.item.url1), fetch(props.item.url2) ]) const [pointsGeoJson, linesGeoJson] = await Promise.all([ pointsResponse.json(), linesResponse.json() ]) // 创建数组存储所有图元 const linePrimitives = [] // 存储所有线图元 const pointCollection = new Cesium.PointPrimitiveCollection() // 点图元集合 // ==================== 线数据优化处理 ==================== // 处理每条线特征 linesGeoJson.features.forEach((feature, index) => { const geometryType = feature.geometry.type // 处理 LineString 类型 if (geometryType === &#39;LineString&#39;) { const coords = feature.geometry.coordinates const primitive = processLineString(coords, index) if (primitive) linePrimitives.push(primitive) } // 处理 MultiLineString 类型 else if (geometryType === &#39;MultiLineString&#39;) { const multiCoords = feature.geometry.coordinates multiCoords.forEach((lineCoords, lineIndex) => { const primitive = processLineString(lineCoords, index, lineIndex) if (primitive) linePrimitives.push(primitive) }) } }) // 辅助函数:处理单个 LineString function processLineString(coords, featureIndex, lineIndex = 0) { // 检查是否为有效线数据 if (!Array.isArray(coords)) { console.warn(`第${featureIndex + 1}条线数据无效: 坐标不是数组`) return null } if (coords.length < 2) { console.warn(`第${featureIndex + 1}条线数据无效: 至少需要2个点`) return null } // 换坐标并创建位置数组 const positions = [] let isValid = true coords.forEach((coord) => { if (!Array.isArray(coord)) { console.warn(`第${featureIndex + 1}条线的坐标点格式无效`) isValid = false return } const lon = Number(coord[0]) const lat = Number(coord[1]) if (isNaN(lon)) { console.warn(`第${featureIndex + 1}条线的经度无效: ${coord[0]}`) isValid = false return } if (isNaN(lat)) { console.warn(`第${featureIndex + 1}条线的纬度无效: ${coord[1]}`) isValid = false return } positions.push(Cesium.Cartesian3.fromDegrees(lon, lat)) }) if (!isValid || positions.length < 2) { console.warn(`第${featureIndex + 1}条线数据无效`) return null } // 为每条线创建独立的图元实例 const linePrimitive = new Cesium.Primitive({ geometryInstances: new Cesium.GeometryInstance({ geometry: new Cesium.PolylineGeometry({ positions: positions, width: 8.0, // 线宽 vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT, arcType: Cesium.ArcType.GEODESIC // 使用大地线 }), attributes: { color: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.HOTPINK.withAlpha(0.7) ), depthFailColor: Cesium.ColorGeometryInstanceAttribute.fromColor( Cesium.Color.HOTPINK.withAlpha(0.7) ) }, id: `pano-line-${featureIndex}-${lineIndex}` }), appearance: new Cesium.PolylineColorAppearance({ translucent: true, aboveGround: true }), asynchronous: false, depthFailAppearance: new Cesium.PolylineColorAppearance({ translucent: true, aboveGround: true }) }) // 添加到场景 trueviewer.scene.primitives.add(linePrimitive) return linePrimitive } // ==================== 点数据处理 ==================== // 2. 创建点图元集合 pointsGeoJson.features.forEach((feature, i) => { const coord = feature.geometry.coordinates if (Array.isArray(coord) && coord.length >= 2) { const lon = Number(coord[0]) const lat = Number(coord[1]) if (!isNaN(lon) && !isNaN(lat)) { pointCollection.add({ position: Cesium.Cartesian3.fromDegrees(lon, lat), color: Cesium.Color.RED.withAlpha(0.9), pixelSize: 8, id: `pano-point-${i}` }) } } }) // 将点集合添加到场景 trueviewer.scene.primitives.add(pointCollection) // ==================== 计算并飞向视图范围(优化版) ==================== // 收集所有线图元和点图元的坐标点用于计算范围 const allPositions = [] // 添加线坐标(确保使用WGS84椭球体) linesGeoJson.features.forEach((feature) => { const geometryType = feature.geometry.type const coordinates = feature.geometry.coordinates if (geometryType === &#39;LineString&#39; && Array.isArray(coordinates)) { coordinates.forEach((coord) => { if (Array.isArray(coord) && coord.length >= 2) { const lon = Number(coord[0]) const lat = Number(coord[1]) if (!isNaN(lon) && !isNaN(lat)) { allPositions.push( Cesium.Cartesian3.fromDegrees( lon, lat, 0, Cesium.Ellipsoid.WGS84 ) ) } } }) } // 新增 MultiLineString 支持 else if ( geometryType === &#39;MultiLineString&#39; && Array.isArray(coordinates) ) { // MultiLineString 的 coordinates 是一个二维数组 coordinates.forEach((lineString) => { if (Array.isArray(lineString)) { lineString.forEach((coord) => { if (Array.isArray(coord) && coord.length >= 2) { const lon = Number(coord[0]) const lat = Number(coord[1]) if (!isNaN(lon) && !isNaN(lat)) { allPositions.push( Cesium.Cartesian3.fromDegrees( lon, lat, 0, Cesium.Ellipsoid.WGS84 ) ) } } }) } }) } }) // 添加点坐标(同样使用WGS84椭球体) pointsGeoJson.features.forEach((feature) => { const coord = feature.geometry.coordinates if (Array.isArray(coord) && coord.length >= 2) { const lon = Number(coord[0]) const lat = Number(coord[1]) if (!isNaN(lon) && !isNaN(lat)) { allPositions.push( Cesium.Cartesian3.fromDegrees(lon, lat, 0, Cesium.Ellipsoid.WGS84) ) } } }) if (allPositions.length === 0) { console.error(&#39;无法计算视图范围: 没有有效坐标点&#39;) viewer.delegate.scene.requestRenderMode = true return } // 计算精确的包围球(扩大5%边界确保完全包含) const boundingSphere = Cesium.BoundingSphere.fromPoints(allPositions) boundingSphere.radius *= 1.05 // 恢复渲染 viewer.delegate.scene.requestRenderMode = true // 计算飞行参数 const radius = boundingSphere.radius const flyToHeight = Cesium.Math.clamp( radius * 3.0, // 基础高度为半径的3倍 500, // 最低高度限制 20000 // 最高高度限制 ) const pitchAngle = -Cesium.Math.toRadians(30) // 固定30度俯视角 // 直接使用flyToBoundingSphere方案(更可靠) viewer.delegate.camera.flyToBoundingSphere(boundingSphere, { duration: 2.5, offset: new Cesium.HeadingPitchRange( 0, // 正北方向 pitchAngle, // 俯视角 flyToHeight // 飞行高度 ), easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT, complete: () => { console.log(&#39;飞行完成&#39;) // 微调确保最佳视角 viewer.delegate.camera.moveBackward(radius * 0.1) } }) // 存入Vuex状态管理 const layerData = { option: { itemdata: props.item, linePrimitives: linePrimitives, // 存储所有线图元 pointCollection: pointCollection // 存储所有点图元 }, panel_visible: true, id: props.item.id, type: &#39;system_pano&#39;, name: props.item.name } store.commit(&#39;LayerData/addLayerData&#39;, layerData) // 恢复渲染并关闭面板 trueviewer.scene.requestRenderMode = true closePanel?.() } catch (error) { console.error(&#39;PANO图层加载失败:&#39;, error) // 确保发生错误时恢复渲染 if (viewer?.delegate?.scene) { viewer.delegate.scene.requestRenderMode = true } throw error } } else { console.log(&#39;非PANO图层,开始添加图层&#39;) // 非PANO图层处理 try { // 3. 准备图层数据 const layerData = { option: props.item, panel_visible: true, id: layerId, type: &#39;system&#39; } console.log(&#39;正在添加图层,ID:&#39;, layerId) // 4. 添加到地图和状态管理 const layerInstance = addLayerToViewer(props.item, viewer) store.commit(&#39;LayerData/addLayerData&#39;, layerData) // 5. 飞行到图层范围 // 确保数据已加载 if (!jsonData.value) { await loadData() // 等待数据加载完成 } fly(dataArray.value, viewer, layerInstance, props.item) // 关闭面板 closePanel?.() } catch (error) { console.error(&#39;添加图层失败:&#39;, error) alert(`操作失败: ${error.message}`) } } } // // 处理删除图层点击事件 // const handleDelClick = async () => { // // 1. 获取Viewer实例 // const viewer = getViewer() // if (!viewer) { // console.error(&#39;Viewer实例未找到&#39;) // return // } // if (props.item.type === &#39;PANO&#39; && props.item.subType === &#39;line&#39;) { // // 需要deepseek完善 // } else { // // 2. 从地图上删除图层 // delLayerFromViewer(props.item, viewer) // // 3. 更新状态管理 // store.commit(&#39;LayerData/delLayerData&#39;, { // id: props.item.id, // type: &#39;system&#39; // }) // } // } const handleDelClick = async () => { const viewer = getViewer() if (!viewer) { console.error(&#39;Viewer实例未找到&#39;) return } if (props.item.type === &#39;PANO&#39; && props.item.subType === &#39;line&#39;) { const trueviewer = getTrueViewer() if (!trueviewer) { console.error(&#39;TrueViewer实例未找到&#39;) return } try { // 1. 从store获取图层数据 const layerData = store.getters[&#39;LayerData/getLayerDataById&#39;]( props.item.id ) if (!layerData) { console.warn(`未找到ID为 ${props.item.id} 的图层数据`) return } // 2. 从场景中移除所有图元 const { linePrimitives, pointCollection } = layerData.option // // 移除线图元 // if (linePrimitives && Array.isArray(linePrimitives)) { // console.log("1 正在移除线图元") // linePrimitives.forEach((primitive) => { // if (primitive && !primitive.isDestroyed) { // trueviewer.scene.primitives.remove(primitive) // } // }) // } // // 移除点图元集合 // if (pointCollection) { // console.log("2 正在移除点图元集合") // trueviewer.scene.primitives.remove(pointCollection) // } // 2. 正确销毁图元 destroyPanoPrimitives(trueviewer, linePrimitives, pointCollection) // 4. 从状态管理中移除 store.commit(&#39;LayerData/delLayerData&#39;, { id: props.item.id, type: &#39;system_pano&#39; }) console.log(`成功删除PANO图层 ${props.item.id}`) } catch (error) { console.error(&#39;删除PANO图层失败:&#39;, error) alert(`删除图层失败: ${error.message}`) } } else { // 非PANO图层的删除逻辑(保持原样) delLayerFromViewer(props.item, viewer) store.commit(&#39;LayerData/delLayerData&#39;, { id: props.item.id, type: &#39;system&#39; }) } } // 在组件内部定义销毁函数 const destroyPanoPrimitives = (viewer, linePrimitives, pointCollection) => { const scene = viewer.scene const primitives = scene.primitives // 销毁线图元 if (Array.isArray(linePrimitives)) { linePrimitives.forEach(primitive => { if (primitive && !primitive.isDestroyed) { if (primitives.contains(primitive)) { scene.primitives.remove(primitive) // true表示同时销毁 } else { primitive.destroy() } } }) } // 销毁点图元集合 if (pointCollection && !pointCollection.isDestroyed) { if (primitives.contains(pointCollection)) { scene.primitives.remove(pointCollection) } else { pointCollection.destroy() } } scene.requestRender() } onMounted(() => { // loadData() // 在需要时调用 loadData() }) </script> <style scoped> .active { background-color: #f0f9ff; color: #3b82f6; font-weight: bold; } </style> 能不能看着我的代码,进行修改?你先学习了解我的代码,然后在代码里解决问题。
最新发布
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值