Files
cssEngine/index.js
2025-08-12 00:35:26 +08:00

218 lines
5.5 KiB
JavaScript

class BaseElement {
constructor(elementType = 'div', engineId) {
this.element = document.createElement(elementType)
this.element.style.position = 'absolute'
this.engineId = engineId
this.x = 0
this.y = 0
this.width = 0
this.height = 0
}
setPosition(x = 0, y = 0) {
this.element.style.left = `${x}px`
this.element.style.top = `${y}px`
this.x = x
this.y = y
}
setSize(width = 0, height = 0) {
if (width) {
this.element.style.width = typeof width === 'number' ? `${width}px` : width
this.width = width
}
if (height) {
this.element.style.height = typeof height === 'number' ? `${height}px` : height
this.height = height
}
}
setStyle(style) {
Object.assign(this.element.style, style)
}
add(child) {
child && this.element.appendChild(child.element || child)
}
remove(child) {
child && this.element.removeChild(child.element || child)
}
on(event, callback) {
this.element.addEventListener(event, callback)
}
off(event, callback) {
this.element.removeEventListener(event, callback)
}
hide() {
this.element.style.display = 'none'
}
show() {
this.element.style.display = 'block'
}
}
class Sprite extends BaseElement {
constructor(img, x, y, width, height, engineId) {
super('div', engineId)
this.imgElement = document.createElement('img')
this.imgElement.src = img.src
this.imgElement.style.cssText = '-webkit-user-drag: none; user-drag: none;'
this.element.appendChild(this.imgElement)
this.setPosition(x, y)
this.setSize(width, height)
this.element.setAttribute('data-sprite-id', engineId)
// 精灵特有方法
this.name = name => this.element.setAttribute('data-name', name)
this.animate = keyframes => (this.element.style.animation = keyframes)
}
}
class Box extends BaseElement {
constructor(x, y, width, height, engineId) {
super('div', engineId)
this.setPosition(x, y)
this.setSize(width, height)
this.element.setAttribute('data-box-id', engineId)
}
}
class TextElement extends BaseElement {
constructor(text, x, y, engineId) {
super('div', engineId)
this.element.innerText = text
this.setPosition(x, y)
this.element.setAttribute('data-text-id', engineId)
// 文本特有方法
this.set = text => (this.element.innerText = text)
this.setColor = color => (this.element.style.color = color)
this.setFont = font => (this.element.style.font = font)
}
}
class HtmlElement extends BaseElement {
constructor(html, x, y, engineId) {
super('div', engineId)
this.element.innerHTML = html
this.setPosition(x, y)
this.element.setAttribute('data-html-id', engineId)
// HTML特有方法
this.set = html => (this.element.innerHTML = html)
this.get = () => this.element.innerHTML
this.getSize = () => {
const rect = this.element.getBoundingClientRect()
return { width: rect.width, height: rect.height }
}
}
}
class SvgElement extends BaseElement {
constructor(x, y, width, height, content, engineId) {
super('div', engineId)
this.element.innerHTML = content
this.setPosition(x, y)
this.setSize(width, height)
this.element.setAttribute('data-svg-id', engineId)
// SVG特有方法
this.setContent = content => (this.element.innerHTML = content)
}
}
class Engine {
constructor(element = document.body, options = {}) {
const defaultOptions = {
width: 800,
height: 600,
background: 'transparent',
}
this.options = { ...defaultOptions, ...options }
this.images = []
this.width = this.options.width
this.height = this.options.height
this.element = typeof element === 'string' ? document.querySelector(element) : element
this.id = Date.now().toString(16)
this.createStage()
}
createStage() {
this.stage = document.createElement('div')
this.stage.setAttribute('data-engine-id', this.id)
Object.assign(this.stage.style, {
width: `${this.options.width}px`,
height: `${this.options.height}px`,
position: 'relative',
userSelect: 'none',
overflow: 'hidden',
background: this.options.background,
transform: 'translateZ(0)',
})
// 添加舞台操作方法
this.stage.add = child => child && this.stage.appendChild(child.element || child)
this.stage.remove = child => child && this.stage.removeChild(child.element || child)
this.element.appendChild(this.stage)
}
load(src = '') {
return new Promise((resolve, reject) => {
const img = new Image()
img.src = src
img.onload = () => resolve(img)
img.onerror = reject
this.images.push(img)
})
}
createSprite(img, x = 0, y = 0, width = 0, height = 0) {
return new Sprite(img, x, y, width, height, this.id)
}
createBox(x = 0, y = 0, width = 0, height = 0) {
return new Box(x, y, width, height, this.id)
}
createText(text = '', x = 0, y = 0) {
return new TextElement(text, x, y, this.id)
}
createHtml(html = '', x = 0, y = 0) {
return new HtmlElement(html, x, y, this.id)
}
createSvg(x = 0, y = 0, width = 0, height = 0, content = '') {
return new SvgElement(x, y, width, height, content, this.id)
}
destroy() {
if (this.stage && this.stage.parentNode) {
this.stage.parentNode.removeChild(this.stage)
}
// 清理所有图像引用
this.images.forEach(img => {
img.onload = null
img.onerror = null
img.src = ''
})
// 清除所有引用
this.images = []
this.stage = null
this.element = null
this.options = null
}
}