[转][Flash/Flex] 纠结的switch与AS3的XML处理,貌似发现AS3的一个BUG

本文发现了一个关于ActionScript 3 (AS3) 中XML处理的一个奇怪Bug,在特定条件下会导致TypeError错误。通过逐步调整代码结构,作者揭示了触发该Bug的具体条件,并提供了两种可行的解决方案。

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

[url]http://bbs.9ria.com/thread-72294-1-1.html[/url]

资讯类型: 原创
来源页面:
资讯原标题:
资讯原作者: eko
我的评论:
对这篇文你有啥看法,跟贴说说吧!欢迎口水和板砖,哈哈。欢迎大家和我们一同分享更多资讯。
本帖最后由 eko 于 2011-1-13 17:21 编辑


嗯首先这是一则新闻,我发现了AS3下的一个bug,接下来我就和大家一起分享一下这个bug

请大家先在cs5中运行一下下面的类
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.IOErrorEvent;
import flash.events.Event;

var _name:String="eko";
var eko:XML=<setting><version>1.0.0</version><family name="fancy" age="27"/><family name="eko" age="30" /></setting>;
var _url:URLLoader=new URLLoader();
_url.addEventListener(IOErrorEvent.IO_ERROR,onLoadCom);
_url.load(new URLRequest("eko.xml"));
function onLoadCom(e:IOErrorEvent):void
{
switch(_name)
{
case "eko":
var _str4:String=eko.family.(@name=="eko").@age;
break;
}

}


报错
TypeError: Error #1010: 术语尚未定义,并且无任何属性。


大家可能认为我的XML语句写错了
那么我们把var _str4:String=eko.family.(@name=="eko").@age;;注掉,打印eko.family.(@name=="eko").@age;看看
修改后的局部代码为:
trace(eko.family.(@name=="eko").@age);
//var _str4:String=eko.family.(@name=="eko").@age;


输出:
30

结果证明我的XML处理是正确的。那为什么会出现这种事情呢。不急,我们再来修改一下类
我们给case后面加上{}
case "eko":
{
trace(eko.family.(@name=="eko").@age);
var _str4:String=eko.family.(@name=="eko").@age;
break;
}


输出正常,也没有报错。
是不是很神奇?不着急,我们接下来再在最初的代码中这么处理,我们把
var _str4:String=eko.family.(@name=="eko").@age;


换个写法,写成

var _str4:String;
_str4=eko.family.(@name=="eko").@age;


顺便打印一下_str4,输出正常,并且不报错。

至此,大家一定认为最初的switch有问题,但事实并不是如此,我们再来做个试验,把其中的异步去掉,将代码修改如下
var _name:String="eko";
var eko:XML=<setting><version>1.0.0</version><family name="fancy" age="27"/><family name="eko" age="30" /></setting>;
switch(_name)
{
case "eko":
var _str4:String=eko.family.(@name=="eko").@age;
trace(_str4);
break;
}



它,它,它又是正常的……

如果大家认为这段代码没有问题,那么请大家把上面的代码改写成文档类,我们再试验一下

package
{
import flash.display.Sprite;

public class Main extends Sprite
{
private var _name:String="eko";
private var eko:XML=<setting><version>1.0.0</version><family name="fancy" age="27"/><family name="eko" age="30" /></setting>;
public function Main()
{
switch(_name)
{
case "eko":
var _str4:String=eko.family.(@name=="eko").@age;
trace(_str4);
break;
}
}

}

}


再CS5中设置文档类,它又报错了

TypeError: Error #1010: 术语尚未定义,并且无任何属性。


我的文档类写错了?
重复之前的操作给case :后面加上{},或者把先申明_str4然后再赋值


var _str4:String;
_str4=eko.family.(@name=="eko").@age;


它又正常了。
这是怎么回事呢?
我不知道,不过我总结如下

在CS5中帧上写代码,具备以下条件就会出错。

1 异步(去load一个外部文件,无论成功与否)
2 处于switch的第一个case分支中(看下一楼“沙发”的补充)
3 在申明变量的同时进行XML查询匹配并赋值(var _str4:String=eko.version或者给version加个name属性,进行var _str4:String=eko.version.@name是正确的)

如果是在类中,则无论异步与否只要具备以上2,3两点就会报错。

解决办法有两个:
第一种方法: 变量申明和赋值分开写
第二种方法: 给case后面加{}



package
{
import flash.display.Sprite;

public class Main extends Sprite
{
private var eko:XML=<setting><version name="sandal">1.0.0</version><family name="fancy" age="27"/><family name="eko" age="30" /></setting>;
public function Main()
{

onTest("fancy");
onTest("eko");

}
private function onTest(_name:String):void
{
switch(_name)
{
case "eko":
var _str4:String=eko.family.(@name=="eko").@age;
trace(_str4);
break;
case "fancy":
var _str3:String=eko.family.(@name=="eko").@age;
trace(_str3);
break;
}
}

}

}


大家可以看到,两个case分支执行同样的代码,第一个分支case "eko"报错了,case "fancy"却是正常的。
<template> <div id="app"> <div id="container"> <div id="header"> <div class="logo"> <div> <div class="header-title">流程图设计器</div> </div> </div> <div class="button-group"> <button id="save-button" class="button button-save" @click="saveDiagram"><i>💾</i> 保存</button> <button id="reset-button" class="button button-reset" @click="resetDiagram"><i>🔄</i> 重置</button> </div> </div> <div id="canvas-container"> <button id="toggle-sidebar" class="toggle-sidebar" @click="toggleSidebar"> {{ sidebarOpen ? &#39;关闭面板&#39; : &#39;属性面板&#39; }} </button> <div id="canvas"></div> </div> <div id="status-bar"> <div class="status-item"> <div class="status-indicator" :style="statusIndicatorStyle"></div> <span>{{ statusText }}</span> </div> <div class="status-item"> <span>{{ elementCount }} 个元素</span> </div> <div class="status-item"> <span>{{ lastSaveText }}</span> </div> </div> </div> <div id="notification" class="notification" :class="{ show: showNotification, [notificationType]: true }"> {{ notificationMessage }} </div> <div id="sidebar" class="sidebar" :class="{ open: sidebarOpen }"> <h3>元素属性</h3> <div class="properties-group"> <div class="property-item"> <label for="element-name">名称</label> <input type="text" id="element-name" placeholder="输入元素名称" v-model="elementName" @input="updateElementProperties" /> </div> <div class="property-item"> <label for="element-desc">描述</label> <textarea id="element-desc" rows="3" placeholder="输入元素描述" v-model="elementDesc" @input="updateElementProperties" ></textarea> </div> </div> </div> </div> </template> <script> import BpmnJS from &#39;bpmn-js/dist/bpmn-modeler.development.js&#39; import &#39;bpmn-js/dist/assets/diagram-js.css&#39; import &#39;bpmn-js/dist/assets/bpmn-js.css&#39; import &#39;bpmn-js/dist/assets/bpmn-font/css/bpmn.css&#39; export default { name: &#39;ActivitiDesigner&#39;, data() { return { bpmnModeler: null, isModelerReady: false, sidebarOpen: false, showNotification: false, notificationMessage: &#39;&#39;, notificationType: &#39;&#39;, statusText: &#39;就绪&#39;, elementCount: 0, lastSaveText: &#39;未保存&#39;, currentElement: null, elementName: &#39;&#39;, elementDesc: &#39;&#39;, elementBusinessObject: null, } }, computed: { statusIndicatorStyle() { switch (this.statusText) { case &#39;就绪&#39;: return { backgroundColor: &#39;#2ecc71&#39; } case &#39;加载中&#39;: return { backgroundColor: &#39;#f39c12&#39; } case &#39;保存中&#39;: return { backgroundColor: &#39;#3498db&#39; } case &#39;错误&#39;: return { backgroundColor: &#39;#e74c3c&#39; } default: return { backgroundColor: &#39;#95a5a6&#39; } } }, }, mounted() { this.initializeModeler() }, methods: { async initializeModeler() { try { this.showNotification = true this.notificationMessage = &#39;正在初始化流程图设计器...&#39; this.notificationType = &#39;warning&#39; // 创建BPMN模型实例 this.bpmnModeler = new BpmnJS({ container: &#39;#canvas&#39;, keyboard: { bindTo: document, }, }) // 监听模型就绪事件 this.bpmnModeler.on(&#39;import.done&#39;, (event) => { console.log(&#39;BPMN模型加载完成&#39;) this.isModelerReady = true this.statusText = &#39;就绪&#39; // 更新元素计数 this.updateElementCount() // 显示成功通知 this.showNotificationMessage(&#39;流程图加载完成!&#39;, &#39;success&#39;) // 监听元素选择事件 this.bpmnModeler.on(&#39;element.click&#39;, (event) => { this.handleElementSelection(event.element) }) }) // 监听错误事件 this.bpmnModeler.on(&#39;error&#39;, (err) => { console.error(&#39;BPMN模型错误&#39;, err) this.isModelerReady = false this.statusText = &#39;错误&#39; this.showNotificationMessage(`模型错误: ${err.message}`, &#39;error&#39;) }) // 监听元素变化事件 this.bpmnModeler.on(&#39;element.changed&#39;, () => { this.updateElementCount() }) // 创建新流程图 await this.createNewDiagram() } catch (err) { console.error(&#39;初始化BPMN模型失败&#39;, err) this.showNotificationMessage(`初始化失败: ${err.message}`, &#39;error&#39;) } }, async createNewDiagram() { if (!this.bpmnModeler) return try { this.statusText = &#39;加载中&#39; await this.bpmnModeler.createDiagram() console.log(&#39;创建流程图成功&#39;) this.lastSaveText = &#39;未保存&#39; this.showNotificationMessage(&#39;已创建新流程图&#39;, &#39;success&#39;) this.statusText = &#39;就绪&#39; } catch (err) { console.error(&#39;创建流程图失败&#39;, err) this.showNotificationMessage(`创建流程图失败: ${err.message}`, &#39;error&#39;) this.statusText = &#39;错误&#39; } }, async saveDiagram() { if (!this.bpmnModeler || !this.isModelerReady) { this.showNotificationMessage(&#39;模型尚未准备好,请稍后再试&#39;, &#39;warning&#39;) return } try { this.statusText = &#39;保存中&#39; // 保存XML const { xml } = await this.bpmnModeler.saveXML({ format: true }) console.log(&#39;BPMN XML:&#39;, xml) // 在实际应用中,这里可以发送到服务器保存 // await this.saveToServer(xml); // 更新状态 const now = new Date() this.lastSaveText = `最后保存: ${now.toLocaleTimeString()}` // 显示成功通知 this.showNotificationMessage(&#39;流程图保存成功!XML内容已输出到控制台&#39;, &#39;success&#39;) // 恢复状态 setTimeout(() => { this.statusText = &#39;就绪&#39; }, 1000) } catch (err) { console.error(&#39;保存失败&#39;, err) this.showNotificationMessage(`保存失败: ${err.message}`, &#39;error&#39;) this.statusText = &#39;错误&#39; } }, resetDiagram() { if (confirm(&#39;确定要重置吗?当前内容将丢失。&#39;)) { this.createNewDiagram() this.elementName = &#39;&#39; this.elementDesc = &#39;&#39; this.currentElement = null } }, toggleSidebar() { this.sidebarOpen = !this.sidebarOpen }, updateElementCount() { if (!this.bpmnModeler) return try { const elementRegistry = this.bpmnModeler.get(&#39;elementRegistry&#39;) this.elementCount = elementRegistry ? elementRegistry.getAll().length : 0 } catch (err) { console.error(&#39;更新元素计数失败&#39;, err) } }, showNotificationMessage(message, type) { this.notificationMessage = message this.notificationType = type this.showNotification = true setTimeout(() => { this.showNotification = false }, 3000) }, handleElementSelection(element) { this.currentElement = element this.elementBusinessObject = element.businessObject console.log(element,&#39;element&#39;) // 加载元素属性 this.elementName = this.elementBusinessObject.name || &#39;&#39; this.elementDesc = this.elementBusinessObject.description || &#39;&#39; // 打开属性面板 this.sidebarOpen = true }, updateElementProperties() { if (!this.currentElement || !this.bpmnModeler || !this.elementBusinessObject) return try { const modeling = this.bpmnModeler.get(&#39;modeling&#39;) // 更新名称 modeling.updateProperties(this.currentElement, { name: this.elementName, description: this.elementDesc, }) this.showNotificationMessage(&#39;元素属性已更新&#39;, &#39;success&#39;) } catch (err) { console.error(&#39;更新元素属性失败&#39;, err) this.showNotificationMessage(`更新属性失败: ${err.message}`, &#39;error&#39;) } }, }, } </script> <style scoped> * { box-sizing: border-box; margin: 0; padding: 0; } body, html { height: 100%; font-family: &#39;Segoe UI&#39;, Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); color: #333; overflow: hidden; } #container { display: flex; flex-direction: column; height: calc(100vh - 150px) ; max-width: 100%; margin: 0 auto; box-shadow: 0 0 30px rgba(0, 0, 0, 0.1); } #header { background: linear-gradient(to right, #2c3e50, #4a6491); color: white; padding: 15px 20px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); z-index: 10; } .logo { display: flex; align-items: center; gap: 15px; } .logo-icon { font-size: 28px; color: #3498db; } .header-title { font-size: 22px; font-weight: 600; } .header-subtitle { font-size: 14px; opacity: 0.8; margin-top: 3px; } .button-group { display: flex; gap: 12px; } .button { padding: 10px 20px; border: none; border-radius: 5px; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.3s ease; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } .button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } .button:active { transform: translateY(0); } .button-save { background: linear-gradient(to right, #27ae60, #2ecc71); color: white; } .button-reset { background: linear-gradient(to right, #e74c3c, #c0392b); color: white; } .button-export { background: linear-gradient(to right, #3498db, #2980b9); color: white; } #canvas-container { flex: 1; position: relative; overflow: hidden; background: #f8f9fa; } #canvas { height: 100%; width: 100%; } #status-bar { background: #2c3e50; color: #ecf0f1; padding: 8px 20px; font-size: 14px; display: flex; justify-content: space-between; align-items: center; } .status-item { display: flex; align-items: center; gap: 8px; } .status-indicator { width: 10px; height: 10px; border-radius: 50%; background-color: #2ecc71; } .notification { position: fixed; top: 20px; right: 20px; padding: 15px 25px; border-radius: 5px; color: white; font-weight: 500; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; transform: translateX(100%); transition: all 0.4s ease; } .notification.show { opacity: 1; transform: translateX(0); } .notification.success { background: linear-gradient(to right, #27ae60, #2ecc71); } .notification.error { background: linear-gradient(to right, #e74c3c, #c0392b); } .notification.warning { background: linear-gradient(to right, #f39c12, #e67e22); } .sidebar { position: absolute; top: 260px; right: 20px; width: 300px; height: 50%; background: white; box-shadow: -5px 0 15px rgba(0, 0, 0, 0.1); z-index: 5; padding: 20px; overflow-y: auto; display: none; } .sidebar.open { display: inline } .sidebar h3 { margin-bottom: 15px; color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; } .properties-group { margin-bottom: 20px; } .property-item { margin-bottom: 15px; } .property-item label { display: block; margin-bottom: 5px; font-weight: 500; color: #2c3e50; } .property-item input, .property-item textarea, .property-item select { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; } .toggle-sidebar { position: absolute; top: 20px; right: 20px; background: #3498db; color: white; border: none; border-radius: 5px; padding: 8px 15px; cursor: pointer; z-index: 6; } .tools-palette { position: absolute; top: 20px; left: 20px; background: white; border-radius: 8px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); padding: 15px; z-index: 5; display: flex; flex-direction: column; gap: 10px; } .tool-btn { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: #f8f9fa; border: 1px solid #e0e0e0; cursor: pointer; transition: all 0.2s; } .tool-btn:hover { background: #3498db; color: white; transform: scale(1.1); } .tool-btn.active { background: #3498db; color: white; } </style> 描述没有更新
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值