diff --git a/DrissionPage/_functions/web.py b/DrissionPage/_functions/web.py index c9b1987..8527bb4 100644 --- a/DrissionPage/_functions/web.py +++ b/DrissionPage/_functions/web.py @@ -107,12 +107,12 @@ def location_in_viewport(page, loc_x, loc_y): def offset_scroll(ele, offset_x, offset_y): - """接收元素及偏移坐标,把坐标滚动到页面中间,返回该点绝对坐标 + """接收元素及偏移坐标,把坐标滚动到页面中间,返回该点坐标 有偏移量时以元素左上角坐标为基准,没有时以click_point为基准 :param ele: 元素对象 :param offset_x: 偏移量x :param offset_y: 偏移量y - :return: 绝对坐标 + :return: 绝对坐标和相对坐标 """ loc_x, loc_y = ele.rect.location cp_x, cp_y = ele.rect.click_point @@ -122,7 +122,11 @@ def offset_scroll(ele, offset_x, offset_y): clientWidth = ele.owner._run_js('return document.body.clientWidth;') clientHeight = ele.owner._run_js('return document.body.clientHeight;') ele.owner.scroll.to_location(lx - clientWidth // 2, ly - clientHeight // 2) - return lx, ly + cl_x, cl_y = ele.rect.viewport_location + ccp_x, ccp_y = ele.rect.viewport_click_point + cx = cl_x + offset_x if offset_x else ccp_x + cy = cl_y + offset_y if offset_y else ccp_y + return lx, ly, cx, cy def make_absolute_link(link, baseURI=None): diff --git a/DrissionPage/_functions/web.pyi b/DrissionPage/_functions/web.pyi index fdd2d76..2f5e702 100644 --- a/DrissionPage/_functions/web.pyi +++ b/DrissionPage/_functions/web.pyi @@ -6,7 +6,7 @@ @License : BSD 3-Clause. """ from pathlib import Path -from typing import Union, Optional +from typing import Union, Optional, Tuple from .._base.base import DrissionElement, BaseParser from .._elements.chromium_element import ChromiumElement @@ -24,7 +24,7 @@ def format_html(text: str) -> str: ... def location_in_viewport(page: ChromiumBase, loc_x: float, loc_y: float) -> bool: ... -def offset_scroll(ele: ChromiumElement, offset_x: float, offset_y: float) -> tuple: ... +def offset_scroll(ele: ChromiumElement, offset_x: float, offset_y: float) -> Tuple[int, int, int, int]: ... def make_absolute_link(link: str, baseURI: str = None) -> str: ... diff --git a/DrissionPage/_units/clicker.py b/DrissionPage/_units/clicker.py index b748ad9..15a6b9d 100644 --- a/DrissionPage/_units/clicker.py +++ b/DrissionPage/_units/clicker.py @@ -53,7 +53,7 @@ class Clicker(object): try: self._ele.scroll.to_see() if self._ele.states.is_enabled and self._ele.states.is_displayed: - rect = self._ele.rect.corners + rect = self._ele.rect.viewport_corners can_click = True except NoRectError: if by_js is False: @@ -90,14 +90,17 @@ class Clicker(object): r = self._ele.owner._run_cdp('DOM.getNodeForLocation', x=int(x), y=int(y), includeUserAgentShadowDOM=True, ignorePointerEventsNone=True) if r['backendNodeId'] != self._ele._backend_id: - vx, vy = self._ele.rect.midpoint + vx, vy = self._ele.rect.viewport_midpoint + lx, ly = self._ele.rect._get_page_coord(vx, vy) else: - vx, vy = self._ele.rect.click_point + vx, vy = self._ele.rect.viewport_click_point + lx, ly = self._ele.rect._get_page_coord(vx, vy) except CDPError: - vx, vy = self._ele.rect.midpoint + vx, vy = self._ele.rect.viewport_midpoint + lx, ly = self._ele.rect._get_page_coord(vx, vy) - self._click(vx, vy) + self._click(lx, ly, vx, vy) return True if by_js is not False: @@ -110,8 +113,7 @@ class Clicker(object): def right(self): """右键单击""" self._ele.owner.scroll.to_see(self._ele) - x, y = self._ele.rect.click_point - self._click(x, y, 'right') + self._click(*self._ele.rect.click_point, *self._ele.rect.viewport_click_point, button='right') def middle(self, get_tab=True): """中键单击,默认返回新出现的tab对象 @@ -119,9 +121,8 @@ class Clicker(object): :return: Tab对象或None """ self._ele.owner.scroll.to_see(self._ele) - x, y = self._ele.rect.click_point curr_tid = self._ele.tab.browser.tab_ids[0] - self._click(x, y, 'middle') + self._click(*self._ele.rect.click_point, *self._ele.rect.viewport_click_point, button='middle') if get_tab: tid = self._ele.tab.browser.wait.new_tab(curr_tab=curr_tid) if not tid: @@ -142,8 +143,7 @@ class Clicker(object): w, h = self._ele.rect.size offset_x = w // 2 offset_y = h // 2 - x, y = offset_scroll(self._ele, offset_x, offset_y) - self._click(x, y, button, count) + self._click(*offset_scroll(self._ele, offset_x, offset_y), button=button, count=count) def multi(self, times=2): """多次点击 @@ -198,19 +198,18 @@ class Clicker(object): return (self._ele.tab.browser.get_mix_tab(tid) if self._ele.tab._type == 'MixTab' else self._ele.tab.browser.get_tab(tid)) - def _click(self, loc_x, loc_y, button='left', count=1): + def _click(self, loc_x, loc_y, view_x, view_y, button='left', count=1): """实施点击 :param loc_x: 绝对x坐标 :param loc_y: 绝对y坐标 + :param view_x: 视口x坐标 + :param view_y: 视口y坐标 :param button: 'left' 'right' 'middle' 'back' 'forward' :param count: 点击次数 :return: None """ self._ele.owner.actions.move_to((loc_x, loc_y), duration=.1) - sx, sy = self._ele.owner.rect.scrollbar_position - x = loc_x - sx - y = loc_y - sy - self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mousePressed', x=x, - y=y, button=button, clickCount=count, _ignore=AlertExistsError) - self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mouseReleased', x=x, - y=y, button=button, _ignore=AlertExistsError) + self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mousePressed', x=view_x, + y=view_y, button=button, clickCount=count, _ignore=AlertExistsError) + self._ele.owner._run_cdp('Input.dispatchMouseEvent', type='mouseReleased', x=view_x, + y=view_y, button=button, _ignore=AlertExistsError) diff --git a/DrissionPage/_units/clicker.pyi b/DrissionPage/_units/clicker.pyi index 5031e27..af3c7b4 100644 --- a/DrissionPage/_units/clicker.pyi +++ b/DrissionPage/_units/clicker.pyi @@ -45,4 +45,9 @@ class Clicker(object): def for_new_tab(self, by_js: bool = False, timeout: float = 3) -> Union[ChromiumTab, MixTab]: ... - def _click(self, client_x: float, client_y: float, button: str = 'left', count: int = 1) -> None: ... + def _click(self, loc_x: float, + loc_y: float, + view_x: float, + view_y: float, + button: str = 'left', + count: int = 1) -> None: ... diff --git a/DrissionPage/_units/rect.py b/DrissionPage/_units/rect.py index 8250642..f94a94b 100644 --- a/DrissionPage/_units/rect.py +++ b/DrissionPage/_units/rect.py @@ -39,20 +39,17 @@ class ElementRect(object): @property def location(self): """返回元素左上角的绝对坐标""" - cl = self.viewport_location - return self._get_page_coord(cl[0], cl[1]) + return self._get_page_coord(*self.viewport_location) @property def midpoint(self): """返回元素中间点的绝对坐标""" - cl = self.viewport_midpoint - return self._get_page_coord(cl[0], cl[1]) + return self._get_page_coord(*self.viewport_midpoint) @property def click_point(self): """返回元素接受点击的点的绝对坐标""" - cl = self.viewport_click_point - return self._get_page_coord(cl[0], cl[1]) + return self._get_page_coord(*self.viewport_click_point) @property def viewport_location(self): @@ -96,6 +93,13 @@ class ElementRect(object): pr = self._ele.owner._run_js('return window.devicePixelRatio;') return (vx + ex) * pr, (ey + vy) * pr + @property + def scroll_position(self): + """返回滚动条位置,格式:(x, y)""" + r = self._ele._run_js('return this.scrollLeft.toString() + " " + this.scrollTop.toString();') + w, h = r.split(' ') + return int(w), int(h) + def _get_viewport_rect(self, quad): """按照类型返回在可视窗口中的范围 :param quad: 方框类型,margin border padding @@ -177,7 +181,7 @@ class TabRect(object): return int(w), int(h) @property - def scrollbar_position(self): + def scroll_position(self): """返回滚动条位置,格式:(x, y)""" r = self._get_page_rect()['visualViewport'] return r['pageX'], r['pageY'] @@ -238,7 +242,9 @@ class FrameRect(object): return self._frame.frame_ele.rect.viewport_corners @property - def scrollbar_position(self): + def scroll_position(self): """返回滚动条位置,格式:(x, y)""" - r = self._frame._run_cdp_loaded('Page.getLayoutMetrics')['visualViewport'] - return r['pageX'], r['pageY'] + r = self._frame.doc_ele._run_js('return this.documentElement.scrollLeft.toString() + " " ' + '+ this.documentElement.scrollTop.toString();') + w, h = r.split(' ') + return int(w), int(h) diff --git a/DrissionPage/_units/rect.pyi b/DrissionPage/_units/rect.pyi index dff526d..0b2c767 100644 --- a/DrissionPage/_units/rect.pyi +++ b/DrissionPage/_units/rect.pyi @@ -56,6 +56,9 @@ class ElementRect(object): @property def viewport_corners(self) -> Tuple[Tuple[float, float], ...]: ... + @property + def scroll_position(self) -> Tuple[float, float]: ... + def _get_viewport_rect(self, quad: str) -> Union[list, None]: ... def _get_page_coord(self, x: float, y: float) -> Tuple[float, float]: ... @@ -90,7 +93,7 @@ class TabRect(object): def viewport_size_with_scrollbar(self) -> Tuple[int, int]: ... @property - def scrollbar_position(self) -> Tuple[int, int]: ... + def scroll_position(self) -> Tuple[int, int]: ... def _get_page_rect(self) -> dict: ... @@ -121,3 +124,6 @@ class FrameRect(object): @property def viewport_corners(self) -> Tuple[Tuple[float, float], ...]: ... + + @property + def scroll_position(self) -> Tuple[float, float]: ... diff --git a/DrissionPage/_units/scroller.py b/DrissionPage/_units/scroller.py index edf0e82..bc5f334 100644 --- a/DrissionPage/_units/scroller.py +++ b/DrissionPage/_units/scroller.py @@ -16,11 +16,11 @@ class Scroller(object): :param ele: 元素对象 """ self._driver = ele - self.t1 = self.t2 = 'this' + self._t1 = self._t2 = 'this' self._wait_complete = False def _run_js(self, js): - js = js.format(self.t1, self.t2, self.t2) + js = js.format(self._t1, self._t2, self._t2) self._driver._run_js(js) self._wait_scrolled() @@ -125,8 +125,8 @@ class PageScroller(Scroller): :param owner: 页面对象 """ super().__init__(owner) - self.t1 = 'window' - self.t2 = 'document.documentElement' + self._t1 = 'window' + self._t2 = 'document.documentElement' def to_see(self, loc_or_ele, center=None): """滚动页面直到元素可见 @@ -165,7 +165,7 @@ class FrameScroller(PageScroller): :param frame: ChromiumFrame对象 """ super().__init__(frame.doc_ele) - self.t1 = self.t2 = 'this.documentElement' + self._t1 = self._t2 = 'this.documentElement' def to_see(self, loc_or_ele, center=None): """滚动页面直到元素可见 diff --git a/DrissionPage/_units/scroller.pyi b/DrissionPage/_units/scroller.pyi index 7e8b7c6..e48c976 100644 --- a/DrissionPage/_units/scroller.pyi +++ b/DrissionPage/_units/scroller.pyi @@ -13,8 +13,8 @@ from .._pages.chromium_base import ChromiumBase class Scroller(object): def __init__(self, page_or_ele: Union[ChromiumBase, ChromiumElement]): - self.t1: str = ... - self.t2: str = ... + self._t1: str = ... + self._t2: str = ... self._driver: Union[ChromiumBase, ChromiumElement] = ... self._wait_complete: bool = ... @@ -64,7 +64,7 @@ class FrameScroller(PageScroller): :param frame: ChromiumFrame对象 """ self._driver = frame.doc_ele - self.t1 = self.t2 = 'this.documentElement' + self._t1 = self._t2 = 'this.documentElement' self._wait_complete = False def to_see(self, loc_or_ele, center=None):