我正在尝试使用 Web 组件创建一个可调整大小的
<canvas>
,但是,出于某种原因,以我正在做的方式(使用 ResizeObserver
),初始高度在外部 <div>
上从零增长到无限(在下面的示例中,我使用 CSS' max-height
限制了高度)。
我的初始设置可以吗?有更简单的方法吗?
我确实尝试使用
this.canvas.height = this.parentElement.clientHeight
代替this.canvas.height = this.height
,但结果更奇怪。
const hookbanContainerTemplate = document.createElement("template")
hookbanContainerTemplate.innerHTML = "<slot></slot>"
class HookbanContainer extends HTMLElement {
connectedCallback() {
const shadowRoot = this.attachShadow({ mode: "open" })
shadowRoot.appendChild(hookbanContainerTemplate.content.cloneNode(true))
}
}
class HookbanBackground extends HTMLElement {
static get observedAttributes() {
return ["width", "height"]
}
constructor(width = 100, height = 100) {
super()
this.width = width
this.height = height
}
connectedCallback() {
this.canvas = document.createElement("canvas")
const shadowRoot = this.attachShadow({ mode: "open" })
shadowRoot.appendChild(this.canvas)
this.drawBackground()
}
drawBackground() {
this.canvas.width = this.width
this.canvas.height = this.height
const ctx = this.canvas.getContext("2d")
if (!ctx) return
ctx.fillStyle = "blue"
ctx.fillRect(
0,
0,
this.canvas.width,
this.canvas.height
)
}
attributeChangedCallback(
name,
_oldValue,
newValue
) {
switch (name) {
case "width":
this.width = parseFloat(newValue)
break
case "height":
this.height = parseFloat(newValue)
break
default:
}
this.drawBackground()
}
}
customElements.define("hookban-container", HookbanContainer)
customElements.define("hookban-background", HookbanBackground)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hookban</title>
<style>
body {
padding: 10px;
}
#demo-container {
resize: both;
overflow: auto;
height: fit-content;
width: fit-content;
max-height: 300px;
max-width: 300px;
padding: 10px;
border: 1px solid black;
}
</style>
</head>
<body>
<div id="demo-container">
<hookban-container>
<hookban-background />
</hookban-container>
</div>
<script>
const observer = new ResizeObserver((mutations) => {
const { height: newHeight, width: newWidth } = mutations[0].contentRect
const hookbanBackground = document.querySelector("hookban-background")
hookbanBackground.setAttribute("height", newHeight)
hookbanBackground.setAttribute("width", newWidth)
})
const hookbanContainer = document.querySelector("div")
observer.observe(hookbanContainer)
</script>
</body>
</html>
(我不知道为什么该片段会给出错误消息
ResizeObserver loop completed with undelivered notifications
,这在我本地不会发生。)
这个问题中的代码正在这个项目中使用。
我重新开始;你想要一个可调整大小的
canvas
我创建了一个独立的 Web 组件
<full-size-canvas>
您必须根据您的需求重构它。
需要注意的一种行为:如果您观察到属性,要初始化属性,
attributeChangedCallback
将在connectedCallback
之前触发;您可以检查
this.isConnected
是否已触发
connectedCallback
。
<full-size-canvas></full-size-canvas>
<script>
customElements.define("full-size-canvas", class extends HTMLElement {
connectedCallback() {
let width = 200, height = 80, canvas;
const createElement = (tag, props = {}) => Object.assign(document.createElement(tag), props);
const updateCanvas = (color = "blue") => {
const ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
}
Object.assign(this.style, {
display : "inline-block",
resize : "both",
border : "1px solid black",
overflow : "auto"
});
this.attachShadow({ mode: "open"})
.append(
createElement("style", {
innerHTML: `canvas {vertical-align:top}`,
}),
canvas = createElement("canvas")
);
updateCanvas("grey");
let observer = new ResizeObserver((mutations) => {
({ width, height } = mutations[0].contentRect);
if ((canvas.width !== width || canvas.height !== height)) {
observer.unobserve(this); // do not observe on repaint
updateCanvas();
// Re-enable the observer after the current call stack is clear
// also prevents Observer undelivered notifications warning
setTimeout(() => observer.observe(this));
}
});
observer.observe(this);
}// connectedCCallback
})
</script>