【问题标题】:How does Puppeteer handle the click Object / DevTools Protocol Chromium/ChromePuppeteer 如何处理点击对象/DevTools 协议 Chromium/Chrome
【发布时间】:2020-07-13 08:44:15
【问题描述】:

我需要知道 puppeteer 如何处理点击对象,以及 Chromium DevTools API。我尝试自己研究它,发现自己无法找到处理它的实际代码。

我需要知道的原因是我正在开发一个包装器来测试代码中的事件以测试网页,并且正在寻找实现事件处理例程而不是使用 puppeteers 事件接口(点击和点击悬停,以及其他可能需要的事件,如触摸事件或滚动)

这是我已经走了多远:

Puppeteer API 使用 DevTools 的 Frame Logic 来联系 API: https://github.com/puppeteer/puppeteer/blob/master/lib/Page.js

    /**
       * @param {string} selector
       * @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options
   */
      click(selector, options = {}) {
      return this.mainFrame().click(selector, options);
      }
       /**
       * @return {!Puppeteer.Frame}
       */
      /**
       * @param {!Protocol.Page.Frame} framePayload`
       */
      _onFrameNavigated(framePayload) {
       const isMainFrame = !framePayload.parentId;
       let frame = isMainFrame ? this._mainFrame : this._frames.get(framePayload.id);
       assert(isMainFrame || frame, 'We either navigate top level or have old version of the navigated frame');
    // Detach all child frames first.
        if (frame) {
          for (const child of frame.childFrames())
           this._removeFramesRecursively(child);
        }
        if (isMainFrame) {
          if (frame) {
            // Update frame id to retain frame identity on cross-process navigation.
            this._frames.delete(frame._id);
            frame._id = framePayload.id;
          } else {
            // Initial main frame navigation.
            frame = new Frame(this, this._client, null, framePayload.id);
          }
          this._frames.set(framePayload.id, frame);
          this._mainFrame = frame;
        }

这是我所得到的,因为我试图查找页面协议,但我无法弄清楚那里发生了什么。

我们将不胜感激,即使是在研究中。

【问题讨论】:

    标签: testing events click puppeteer chromium


    【解决方案1】:

    主要部分发生在JSHandlehere

    async click(options) {
        await this._scrollIntoViewIfNeeded();
        const {x, y} = await this._clickablePoint();
        await this._page.mouse.click(x, y, options);
    }
    

    它滚动直到元素在视口中(否则它不会点击),这发生在here,然后它使用 DevTools API here 找到元素上的可点击坐标:

    async _clickablePoint() {
        const [result, layoutMetrics] = await Promise.all([
          this._client.send('DOM.getContentQuads', {
            objectId: this._remoteObject.objectId
          }).catch(debugError),
          this._client.send('Page.getLayoutMetrics'),
        ]);
        if (!result || !result.quads.length)
          throw new Error('Node is either not visible or not an HTMLElement');
        // Filter out quads that have too small area to click into.
        const {clientWidth, clientHeight} = layoutMetrics.layoutViewport;
        const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).map(quad => this._intersectQuadWithViewport(quad, clientWidth, clientHeight)).filter(quad => computeQuadArea(quad) > 1);
        if (!quads.length)
          throw new Error('Node is either not visible or not an HTMLElement');
        // Return the middle point of the first quad.
        const quad = quads[0];
        let x = 0;
        let y = 0;
        for (const point of quad) {
          x += point.x;
          y += point.y;
        }
        return {
          x: x / 4,
          y: y / 4
        };
    }
    

    最后它将鼠标移动到坐标here并点击它here

    async click(x, y, options = {}) {
        const {delay = null} = options;
        if (delay !== null) {
          await Promise.all([
            this.move(x, y),
            this.down(options),
          ]);
          await new Promise(f => setTimeout(f, delay));
          await this.up(options);
        } else {
          await Promise.all([
            this.move(x, y),
            this.down(options),
            this.up(options),
          ]);
        }
    }
    

    使用 DevTools API 与鼠标进行交互here

    async down(options = {}) {
        const {button = 'left', clickCount = 1} = options;
        this._button = button;
        await this._client.send('Input.dispatchMouseEvent', {
          type: 'mousePressed',
          button,
          x: this._x,
          y: this._y,
          modifiers: this._keyboard._modifiers,
          clickCount
        });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多