@sanyueqi/web-components
Version:
Web components
2 lines (1 loc) • 6.27 kB
JavaScript
!function(e){"function"==typeof define&&define.amd?define(e):e()}(function(){"use strict";const e={cdn:"https://unpkg.com/@esotericsoftware/spine-webcomponents@4.2.*/dist/iife/spine-webcomponents.min.js",local:"/public/lib/spine-webcomponents.min.js"};class t{animationGroupId;container;spinePackageUrl;animations=[];constructor(t,i="default",n=e){i&&this.setAnimationGroupId(i),t&&this.setContainer(t),this.spinePackageUrl=n,this.animations=[],this.initialized=!1,this._loadCallbacks={resolve:null,reject:null}}setAnimationGroupId(e){this.animationGroupId=e}setContainer(e){if(this.container="string"==typeof e?document.querySelector(e):e,!this.container)throw new Error("找不到容器元素")}async init(e=this.animations||[],t=!1){try{return window.spine||(console.log("SpineManager: window.spine不存在,开始动态加载..."),await this.waitForSpine()),this.animations=e,this.renderAnimations(),t||this.addOverlay(),this.initialized=!0,console.log("SpineManager: 初始化成功"),!0}catch(e){throw console.error("SpineManager: 初始化失败:",e),e}}waitForSpine(){return new Promise(async(e,t)=>{if(window.spine)e();else{this._loadCallbacks.resolve=e,this._loadCallbacks.reject=t;try{if("string"==typeof this.spinePackageUrl)await this.loadScript(this.spinePackageUrl);else{if(!this.spinePackageUrl||"object"!=typeof this.spinePackageUrl)return void t(new Error("无效的spine包地址配置"));try{await this.loadScript(this.spinePackageUrl.cdn)}catch(e){console.warn("SpineManager: CDN加载失败,尝试本地加载:",e),await this.loadScript(this.spinePackageUrl.local)}}}catch(e){t(e)}}})}loadScript(e){return new Promise((t,i)=>{if(document.querySelector(`script[src="${e}"]`)){if(window.spine)t();else{const e=()=>{document.removeEventListener("spine-loaded",e),t()};document.addEventListener("spine-loaded",e),setTimeout(()=>{document.removeEventListener("spine-loaded",e),i(new Error("等待spine加载超时"))},1e4)}return}const n=document.createElement("script");n.src=e,n.onload=()=>{this.waitForSpineInitialization().then(()=>{document.dispatchEvent(new CustomEvent("spine-loaded")),this._loadCallbacks.resolve&&this._loadCallbacks.resolve()}).catch(e=>{this._loadCallbacks.reject&&this._loadCallbacks.reject(e)})},n.onerror=()=>{console.error("SpineManager: Spine脚本加载失败:",e),this._loadCallbacks.reject&&this._loadCallbacks.reject(new Error(`无法加载Spine脚本: ${e}`))},document.head.appendChild(n)})}waitForSpineInitialization(){return new Promise((e,t)=>{const i=()=>{window.spine?e():setTimeout(i,100)},n=setTimeout(()=>{t(new Error("等待spine初始化超时"))},1e4);i(),window.addEventListener("spine-loaded",()=>{clearTimeout(n),e()})})}renderAnimations(){this.container?(this.container.innerHTML="",this.animations.forEach(e=>{const t=document.createElement("div");t.id=e.id;const i={position:"absolute",width:"100%",height:"100%",overflow:"hidden"};Object.keys(i).forEach(e=>{t.style[e]=i[e]});["position","width","height","overflow","top","bottom","left","right","display","zIndex","margin","padding","background","opacity","transform"].forEach(i=>{void 0!==e[i]&&(t.style[i]=e[i])});const n=document.createElement("spine-skeleton");n.setAttribute("identifier",e.id),n.setAttribute("atlas",e.atlas),n.setAttribute("skeleton",e.skeleton),n.setAttribute("overlay-id",this.animationGroupId),e.animation&&n.setAttribute("animation",e.animation),e.scale&&n.setAttribute("scale",e.scale),e.fit&&n.setAttribute("fit",e.fit),e["offset-x"]&&n.setAttribute("offset-x",e["offset-x"]),e["offset-y"]&&n.setAttribute("offset-y",e["offset-y"]),e["x-axis"]&&n.setAttribute("x-axis",e["x-axis"]),e["y-axis"]&&n.setAttribute("y-axis",e["y-axis"]),e.drag&&n.setAttribute("drag",""),e.clip&&n.setAttribute("clip",""),e.skin&&n.setAttribute("skin",e.skin),e["raw-data"]&&n.setAttribute("raw-data",e["raw-data"]),e["json-skeleton-key"]&&n.setAttribute("json-skeleton-key",e["json-skeleton-key"]),e.extraData&&Object.keys(e.extraData).forEach(t=>{n.setAttribute(t,e.extraData[t])}),t.appendChild(n),this.container.appendChild(t)})):console.error("SpineManager: 容器不存在:",this.container)}addOverlay(){const e=document.createElement("spine-overlay");e.setAttribute("overlay-id",this.animationGroupId),this.container.appendChild(e)}getSkeleton(e){if(!this.initialized)return console.warn("SpineManager: 尚未初始化"),null;return this.container.querySelector(`spine-skeleton[identifier="${e}"]`)}addAnimation(e){e.id?(this.animations.push(e),this.initialized&&(this.renderAnimations(),this.addOverlay())):console.error("SpineManager: 动画配置必须包含id字段")}removeAnimation(e){this.animations=this.animations.filter(t=>t.id!==e),this.initialized&&(this.renderAnimations(),this.addOverlay())}getAnimations(){return[...this.animations]}isInitialized(){return this.initialized}async destroy(){await this.disposeAllSpineResources(),this.container&&(this.container.innerHTML=""),this.initialized=!1,this._loadCallbacks.resolve=null,this._loadCallbacks.reject=null}async disposeAllSpineResources(e=this.container){const t="string"==typeof e?document.querySelector(e):e;if(t)try{const e=t.querySelectorAll("spine-skeleton"),i=[];for(const t of e)try{const e=t.getAttribute("identifier");if(e&&window.spine&&window.spine.getSkeleton){const n=window.spine.getSkeleton(e);if(n&&n.whenReady){const s=n.whenReady.then(e=>{e&&"function"==typeof e.dispose&&e.dispose(),t.remove()}).catch(i=>{console.warn(`释放骨架 ${e} 时出错:`,i),t.remove()});i.push(s)}else t.remove()}else t.dispose&&"function"==typeof t.dispose&&t.dispose(),t.remove()}catch(e){console.error("处理骨架时出错:",e),t.remove()}await Promise.allSettled(i);const n=t.querySelector("spine-overlay");if(n)try{n.dispose&&"function"==typeof n.dispose&&n.dispose(),n.remove()}catch(e){console.error("释放overlay时出错:",e),n.remove()}}catch(e){console.error("释放Spine资源过程中发生错误:",e)}else console.warn("容器未找到")}async disposeAllSpineResourcesWithRetry(e,t=3){for(let i=1;i<=t;i++)try{await this.disposeAllSpineResources(e);break}catch(e){if(i===t)throw e;await new Promise(e=>setTimeout(e,100*i))}}}"undefined"!=typeof module&&module.exports&&(module.exports=t),"undefined"!=typeof window&&(window.SpineManager=t)});