谷歌浏览器错误?为什么有时不触发pointerover 和document pointerup 事件?

问题描述

在下面的示例中,将立方体拖动到另一个网格单元格第一次或两次有效。但是如果你一直试图放手,然后将立方体拖到新的单元格中,你会发现有时它不起作用。

您会注意到,当它不起作用时,documentpointerup 事件不会像我们期望的那样触发,一旦我们放开指针,立方体即使我们没有拖拽,它也会继续移动。

设置事件处理程序的代码从 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 表明初始拖动效果很好。松开鼠标后,当我完成拖动时,我摆动鼠标以发出信号。

然后我尝试再次拖动,但立方体没有移动。一旦我松开手,不再按住鼠标按钮,立方体就会开始移动(如果鼠标按钮没有按下,它就不会移动)。

当我不拖动时立方体移动的原因是因为 documentpointerup 事件在我上次停止拖动时没有触发,所以它没有删除 pointerover细胞上的事件。

当我第二次尝试拖动多维数据集时,在我尝试拖动时没有触发任何单元格 pointerover 事件(由于上述问题)。这些事件在我松开鼠标按钮后才开始触发,但这是错误的,当我不拖动时,立方体应该没有移动。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)