JavaScript如何让已有MovieClip实例扩展BasicButton类方法
在开发中使用Adobe Animate生成HTML5 canvas,创建标签、文本输入框、MovieClip对象等前端画布元素作为多用途对象。此前使用传统按钮组件时,会出现弹窗被按钮遮挡的层级问题,尝试多种解决方案后,将按钮对象全部替换为MovieClip对象,成功解决了该层级异常问题。
需要让部分MovieClip对象具备按钮的交互能力,因此在项目中创建了名为BasicButton的类,封装对象作为按钮使用所需的核心功能,初始代码如下:
class BasicButton { constructor(obj){ this.obj = obj; } } function onMouseHover() { console.log('Hovering over' + this.obj); } function onMouseDown() { console.log('MouseDown on' + this.obj); }
在主.html文件中,已经可以正常获取到名为FakeButton_1、类型为MovieClip的实例,测试修改其text属性可正常生效,相关代码如下:
<html> ..head ..body <script .. create.js /> <script src="./BasicButton.js" /> <script> function onLoad(){ extractRoot('canvas').FakeButton_1.text = "Hello World"; // 测试可正常修改对象文本 //TODO: 让FakeButton_1可以使用BasicButton的能力 } </script> </html>
核心诉求:让已创建完成的FakeButton_1实例可以使用BasicButton类的成员方法,理想实现方式是将FakeButton_1对象传入BasicButton构造函数,让类可以识别并操作目标对象。
不需要修改原有MovieClip实例的原型链,直接使用组合模式即可实现需求,你最初设想的「把实例传入BasicButton构造函数」的思路完全可行,之前无法生效是因为类内部缺少事件绑定、this指向修正的逻辑。
步骤1:完善BasicButton类逻辑
将交互方法、事件绑定逻辑统一收在类内部,修正this指向问题,避免事件触发时拿不到目标MovieClip引用:
class BasicButton { constructor(targetMc) { // 保存关联的目标MovieClip实例 this.target = targetMc; // 固定事件处理函数的this指向,避免事件触发时this指向错误 this.onMouseHover = this.onMouseHover.bind(this); this.onMouseDown = this.onMouseDown.bind(this); this.onMouseOut = this.onMouseOut.bind(this); // 给目标实例注册CreateJS交互事件 this.target.cursor = "pointer"; // 鼠标悬浮显示手型,匹配按钮交互习惯 this.target.on("rollover", this.onMouseHover); this.target.on("mousedown", this.onMouseDown); this.target.on("rollout", this.onMouseOut); } onMouseHover() { console.log('Hovering over', this.target); // 可自定义悬浮态逻辑,比如修改透明度、跳转到对应帧 this.target.alpha = 0.8; } onMouseDown() { console.log('MouseDown on', this.target); // 可自定义点击按下逻辑,比如触发业务回调、切换按下态样式 } onMouseOut() { // 悬浮离开时恢复默认状态 this.target.alpha = 1; } // 可选:新增销毁方法,移除事件监听避免内存泄漏 destroy() { this.target.off("rollover", this.onMouseHover); this.target.off("mousedown", this.onMouseDown); this.target.off("rollout", this.onMouseOut); } }
步骤2:在加载完成逻辑中实例化BasicButton
直接把获取到的FakeButton_1传入构造函数即可完成能力绑定,不需要修改原实例的类型:
function onLoad(){ const stageRoot = extractRoot('canvas'); // 原有测试逻辑 stageRoot.FakeButton_1.text = "Hello World"; // 传入MovieClip实例,完成按钮能力绑定 const btnInstance = new BasicButton(stageRoot.FakeButton_1); }
可选扩展:直接在原MovieClip实例上挂载方法
如果需要直接通过FakeButton_1调用按钮相关方法,不需要单独保存BasicButton实例引用,可以在构造函数中直接给目标对象挂载方法:
class BasicButton { constructor(targetMc) { this.target = targetMc; // 直接给原实例挂载按钮方法 targetMc.setDisabled = (isDisabled) => { this.target.mouseEnabled = !isDisabled; this.target.alpha = isDisabled ? 0.5 : 1; }; // 其余事件绑定、方法逻辑和之前一致 } }
挂载后可直接调用:
stageRoot.FakeButton_1.setDisabled(true);
方案说明
- 不推荐直接修改MovieClip原型链扩展按钮能力:Adobe Animate导出的CreateJS实例在帧切换、资源重载时可能重置原型属性,容易出现逻辑丢失问题
- 组合模式耦合度更低:可以自由选择需要转为按钮的MovieClip实例,不会给所有同类实例冗余挂载按钮方法
内容的提问来源于stack exchange,提问作者user2529011

