问题描述
在下面的示例中,将立方体拖动到另一个网格单元格第一次或两次有效。但是如果你一直试图放手,然后将立方体拖到新的单元格中,你会发现有时它不起作用。
您会注意到,当它不起作用时,document
的 pointerup
事件不会像我们期望的那样触发,一旦我们放开指针,立方体即使我们没有拖拽,它也会继续移动。
设置事件处理程序的代码从 JS 的第 159 行开始。在桌面上使其全屏,它可能不适合移动屏幕。不要担心自定义元素的作用,主要问题是最后的事件处理程序似乎没有按预期工作。
(示例后的视频)
编辑:这个特殊问题似乎只发生在 Chromium(桌面)中,但我在 Firefox(桌面)中没有遇到这个问题。也许这是 Chrome 的错误。
{
// Register the LUME HTML elements with the browser.
LUME.useDefaultNames();
const { Node,html,reactify,autorun } = LUME;
class Cube extends Node {
constructor(...args) {
super(...args);
reactify(this,['cubeSize'])
}
cubeSize = 200;
connectedCallback() {
super.connectedCallback();
// Keep it a cube.
this.stop = autorun(() => {
this.size = [this.cubeSize,this.cubeSize,this.cubeSize];
});
}
disconnectedCallback() {
super.disconnectedCallback();
this.stop();
}
// prettier-ignore
template = () => html`
<lume-node size="0 0 0" align="0.5 0.5 0.5">
<lume-node class="cubeFace" position=${() => [0,this.cubeSize/2]} rotation="0 0 0" size=${() => [this.cubeSize,0]} mount-point="0.5 0.5" align="0.5 0.5 0.5"></lume-node>
<lume-node class="cubeFace" position=${() => [0,-this.cubeSize/2]} rotation="0 180 0" size=${() => [this.cubeSize,0]} mount-point="0.5 0.5" align="0.5 0.5 0.5"></lume-node>
<lume-node class="cubeFace" position=${() => [-this.cubeSize/2,0]} rotation="0 -90 0" size=${() => [this.cubeSize,0]} mount-point="0.5 0.5" align="0.5 0.5 0.5"></lume-node>
<lume-node class="cubeFace" position=${() => [this.cubeSize/2,0]} rotation="0 90 0" size=${() => [this.cubeSize,-this.cubeSize/2,0]} rotation="-90 0 0" size=${() => [this.cubeSize,this.cubeSize/2,0]} rotation="90 0 0" size=${() => [this.cubeSize,0]} mount-point="0.5 0.5" align="0.5 0.5 0.5"></lume-node>
</lume-node>
`
css = `
.cubeFace {
background: linear-gradient(43deg,rgb(63,94,251) 0%,rgb(252,70,107) 100%);
}
`;
}
customElements.define('cube-',Cube)
/**
* @mixin
* @class ChildWatcher -
* A mixin class that gives your custom element a childrenChagnedCallback()
* that runs any time your element's children have changed while your element
* is connected into a live DOM tree.
*/
function ChildWatcher(Base) {
return class ChildWatcher extends Base {
connectedCallback() {
super.connectedCallback?.();
// When children have changed,recompute the layout.
this.observer = new MutationObserver(() =>
this.childrenChangedCallback?.()
);
this.observer.observe(this,{ childList: true });
}
disconnectedCallback() {
super.disconnectedCallback?.();
this.observer.disconnect();
}
};
}
class GridLayout extends ChildWatcher(LUME.Node) {
constructor(...args) {
super(...args)
reactify(this,['rows','columns'])
}
// If rows or columns is not provided (both zero),then the default is a square grid
// that fits all images (f.e. give 7 images,the grid rows and columns
// would be 3 and 3,for a total of 9 cells,and two cells would be empty
// in the last row).
rows = 0;
columns = 0;
connectedCallback() {
super.connectedCallback();
// Run an initial layout on connect,and also recompute layout whenever this.rows or this.columns change.
this.stop = LUME.autorun(() => {
this.layout(this.rows,this.columns);
});
}
disconnectedCallback() {
// Don't forget cleanup!
this.stop();
}
childrenChangedCallback() {
// Recompute layout any time this element's children have changed
// (it is batched,so happens once per macrotask,for better performance)
this.layout(this.rows,this.columns);
}
layout(rows,columns) {
// Calculate the grid rows and columns to be a square if rows/columns isn't provided.
if (!rows || !columns) {
const size = Math.ceil(Math.sqrt(this.children.length));
rows = size;
columns = size;
}
const cells = rows * columns;
const gridSize = this.calculatedSize; // [x,y,z] in px units
const cellWidth = gridSize.x / columns;
const cellHeight = gridSize.y / rows;
for (let i = 0; i < cells; i += 1) {
const node = this.children[i];
// If we have less nodes than total cells,quit early.
if (!node) break;
node.size = [cellWidth,cellHeight];
node.position = {
x: (i % columns) * cellWidth,y: Math.floor(i / columns) * cellHeight
};
}
}
}
customElements.define('grid-layout',GridLayout)
}
const cells = document.querySelectorAll("grid-layout > *");
// This event never fires
cells.forEach((n,i) => {
n.addEventListener("gotpointercapture",(event) => {
console.log(" --------------- pointer capture,uncapture it.",event.target);
event.target.releasePointerCapture(event.pointerId);
});
});
// This event also never fires
gridContainer.addEventListener("gotpointercapture",(event) => {
console.log(" --------------- pointer capture,event.target);
event.target.releasePointerCapture(event.pointerId);
});
cube.addEventListener("pointerdown",(event) => {
console.log(" --------------- pointer down,start things.");
event.target.releasePointerCapture(event.pointerId);
cube.classList.add("no-events");
const handlers = [];
cells.forEach((n,i) => {
const handler = (event) => {
console.log(" --------------- pointer over cell,move cube.");
event.target.releasePointerCapture(event.pointerId);
console.log("pointer over cell",i);
cube.position = n.position;
};
handlers.push(handler);
n.addEventListener("pointerover",handler);
});
document.addEventListener(
"pointerup",(event) => {
console.log(" --------------- pointer up,stop things.");
cube.classList.remove("no-events");
cells.forEach((n,i) => n.removeEventListener("pointerover",handlers[i]));
},{ once: true }
);
});
html,body {
width: 100%;
height: 100%;
margin: 0;
background: #444;
}
grid-layout {
outline: 4px solid #fc466b;
touch-action: none;
pointer-events: none;
}
grid-layout > * {
outline: 1px solid #3f5efb;
pointer-events: auto;
}
.no-events {
pointer-events: none;
}
<!--
Made with LUME
http://github.com/lume/lume
-->
<script src="https://assets.codepen.io/191583/LUME.unversioned.2.js"></script>
<lume-scene id="scene" perspective="1000">
<lume-node id="gridContainer" size="600 600" position="20 20" align="0.5 0.5" mount-point="0.5 0.5" rotation="10 30 0">
<cube- class="Xno-events" id="cube" cubeSize="200" position="0 0"></cube->
<!-- Make the grid fill 75% width and 75% height of the scene,and center it. -->
<grid-layout id="grid" size-mode="proportional proportional" size="1 1">
<!-- Put nine cells in the grid,so 3x3 grid by default -->
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
<lume-node></lume-node>
</grid-layout>
</lume-node>
</lume-scene>
video on youtube 表明初始拖动效果很好。松开鼠标后,当我完成拖动时,我摆动鼠标以发出信号。
然后我尝试再次拖动,但立方体没有移动。一旦我松开手,不再按住鼠标按钮,立方体就会开始移动(如果鼠标按钮没有按下,它就不会移动)。
当我不拖动时立方体移动的原因是因为 document
的 pointerup
事件在我上次停止拖动时没有触发,所以它没有删除 pointerover
细胞上的事件。
当我第二次尝试拖动多维数据集时,在我尝试拖动时没有触发任何单元格 pointerover
事件(由于上述问题)。这些事件在我松开鼠标按钮后才开始触发,但这是错误的,当我不拖动时,立方体应该没有移动。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)