diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py
index c57eb52..2d9d072 100644
--- a/DrissionPage/_elements/chromium_element.py
+++ b/DrissionPage/_elements/chromium_element.py
@@ -666,41 +666,15 @@ class ChromiumElement(DrissionElement):
     def drag_to(self, ele_or_loc, duration=.5):
         """拖拽当前元素,目标为另一个元素或坐标元组(x, y)
         :param ele_or_loc: 另一个元素或坐标元组,坐标为元素中点的坐标
-        :param duration: 拖动用时,传入0即瞬间到j达
+        :param duration: 拖动用时,传入0即瞬间到达
         :return: None
         """
-        # x, y:目标点坐标
         if isinstance(ele_or_loc, ChromiumElement):
-            target_x, target_y = ele_or_loc.locations.midpoint
-        elif isinstance(ele_or_loc, (list, tuple)):
-            target_x, target_y = ele_or_loc
-        else:
+            ele_or_loc = ele_or_loc.locations.midpoint
+        elif not isinstance(ele_or_loc, (list, tuple)):
             raise TypeError('需要ChromiumElement对象或坐标。')
 
-        current_x, current_y = self.locations.midpoint
-        width = target_x - current_x
-        height = target_y - current_y
-
-        duration = .02 if duration < .02 else duration
-        num = int(duration * 50)
-
-        # 将要经过的点存入列表
-        points = [(int(current_x + i * (width / num)), int(current_y + i * (height / num))) for i in range(1, num)]
-        points.append((target_x, target_y))
-
-        from .._units.action_chains import ActionChains
-        actions = ActionChains(self.page)
-        actions.hold(self)
-
-        # 逐个访问要经过的点
-        for x, y in points:
-            t = perf_counter()
-            actions.move(x - current_x, y - current_y)
-            current_x, current_y = x, y
-            ss = .02 - perf_counter() + t
-            if ss > 0:
-                sleep(ss)
-        actions.release()
+        self.page.actions.hold(self).move_to(ele_or_loc, duration=duration).release()
 
     def _get_obj_id(self, node_id=None, backend_id=None):
         """根据传入node id或backend id获取js中的object id
diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py
index d3ec6f7..e9d4bde 100644
--- a/DrissionPage/_pages/chromium_base.py
+++ b/DrissionPage/_pages/chromium_base.py
@@ -84,7 +84,13 @@ class ChromiumBase(BasePage):
         self._scroll = None
 
         if not tab_id:
-            tab_id = self.browser.tabs[0]
+            tabs = self.browser.driver.get(f'http://{self.address}/json').json()
+            tabs = [(i['id'], i['url']) for i in tabs if i['type'] == 'page' and not i['url'].startswith('devtools://')]
+            if tabs[0][1] == 'chrome://privacy-sandbox-dialog/notice' and len(tabs) > 1:
+                tab_id = tabs[1][0]
+                close_privacy_dialog(self, tabs[0][0])
+            else:
+                tab_id = tabs[0][0]
 
         self._driver_init(tab_id)
         if self.ready_state == 'complete' and self._ready_state is None:
@@ -100,9 +106,6 @@ class ChromiumBase(BasePage):
         """
         self._is_loading = True
         self._driver = self.browser._get_driver(tab_id)
-        if self._driver.run('Target.getTargetInfo',
-                            targetId=self._target_id)['targetInfo']['url'] == 'chrome://privacy-sandbox-dialog/notice':
-            self._driver = close_privacy_dialog(self)
 
         self._alert = Alert()
         self._driver.set_callback('Page.javascriptDialogOpening', self._on_alert_open)
@@ -1038,33 +1041,33 @@ class Alert(object):
         self.response_text = None
 
 
-def close_privacy_dialog(page):
+def close_privacy_dialog(page, tid):
     """关闭隐私声明弹窗
     :param page: ChromiumBase对象
+    :param tid: tab id
     :return: ChromiumDriver对象
     """
-    tid = page.tab_id
-    page._driver.run('Runtime.enable')
-    page._driver.run('DOM.enable')
-    page._driver.run('DOM.getDocument')
-    sid = page._driver.run('DOM.performSearch', query='//*[name()="privacy-sandbox-notice-dialog-app"]',
-                           includeUserAgentShadowDOM=True)['searchId']
-    r = page._driver.run('DOM.getSearchResults', searchId=sid, fromIndex=0, toIndex=1)['nodeIds'][0]
-    while True:
-        try:
-            r = page._driver.run('DOM.describeNode', nodeId=r)['node']['shadowRoots'][0]['backendNodeId']
-            break
-        except KeyError:
-            pass
-    page._driver.run('DOM.discardSearchResults', searchId=sid)
-    r = page._driver.run('DOM.resolveNode', backendNodeId=r)['object']['objectId']
-    r = page._driver.run('Runtime.callFunctionOn', objectId=r,
-                         functionDeclaration='function()'
-                                             '{return this.getElementById("ackButton");}')['result']['objectId']
-    page._driver.run('Runtime.callFunctionOn', objectId=r, functionDeclaration='function(){return this.click();}')
-    while True:
-        new_tid = page.browser.tabs[0]
-        if new_tid != tid:
-            break
-        sleep(.1)
-    return page.browser._get_driver(new_tid)
+    try:
+        driver = page.browser._get_driver(tid)
+        driver.run('Runtime.enable')
+        driver.run('DOM.enable')
+        driver.run('DOM.getDocument')
+        sid = driver.run('DOM.performSearch', query='//*[name()="privacy-sandbox-notice-dialog-app"]',
+                         includeUserAgentShadowDOM=True)['searchId']
+        r = driver.run('DOM.getSearchResults', searchId=sid, fromIndex=0, toIndex=1)['nodeIds'][0]
+        end_time = perf_counter() + 3
+        while perf_counter() < end_time:
+            try:
+                r = driver.run('DOM.describeNode', nodeId=r)['node']['shadowRoots'][0]['backendNodeId']
+                break
+            except KeyError:
+                pass
+        driver.run('DOM.discardSearchResults', searchId=sid)
+        r = driver.run('DOM.resolveNode', backendNodeId=r)['object']['objectId']
+        r = driver.run('Runtime.callFunctionOn', objectId=r,
+                       functionDeclaration='function(){return this.getElementById("ackButton");}')['result']['objectId']
+        driver.run('Runtime.callFunctionOn', objectId=r, functionDeclaration='function(){return this.click();}')
+        driver.close()
+
+    except:
+        pass
diff --git a/DrissionPage/_pages/chromium_frame.pyi b/DrissionPage/_pages/chromium_frame.pyi
index 6159831..12aff73 100644
--- a/DrissionPage/_pages/chromium_frame.pyi
+++ b/DrissionPage/_pages/chromium_frame.pyi
@@ -33,6 +33,7 @@ class ChromiumFrame(ChromiumBase):
         self.doc_ele: ChromiumElement = ...
         self._states: ElementStates = ...
         self._ids: FrameIds = ...
+        self._is_init_get_doc: bool = ...
 
     def __call__(self,
                  loc_or_str: Union[Tuple[str, str], str],
diff --git a/DrissionPage/_units/action_chains.py b/DrissionPage/_units/action_chains.py
index b5d9c2f..8b177d1 100644
--- a/DrissionPage/_units/action_chains.py
+++ b/DrissionPage/_units/action_chains.py
@@ -3,7 +3,7 @@
 @Author  :   g1879
 @Contact :   g1879@qq.com
 """
-from time import sleep
+from time import sleep, perf_counter
 
 from .._commons.keys import modifierBit, keyDescriptionForString
 from .._commons.web import location_in_viewport
@@ -22,12 +22,13 @@ class ActionChains:
         self.curr_x = 0  # 视口坐标
         self.curr_y = 0
 
-    def move_to(self, ele_or_loc, offset_x=0, offset_y=0):
+    def move_to(self, ele_or_loc, offset_x=0, offset_y=0, duration=.5):
         """鼠标移动到元素中点,或页面上的某个绝对坐标。可设置偏移量
         当带偏移量时,偏移量相对于元素左上角坐标
         :param ele_or_loc: 元素对象、绝对坐标或文本定位符,坐标为tuple(int, int)形式
         :param offset_x: 偏移量x
         :param offset_y: 偏移量y
+        :param duration: 拖动用时,传入0即瞬间到达
         :return: self
         """
         is_loc = False
@@ -50,7 +51,7 @@ class ActionChains:
             clientHeight = self.page.run_js('return document.body.clientHeight;')
             self.page.scroll.to_location(lx - clientWidth // 2, ly - clientHeight // 2)
 
-        # # 这样设计为了应付那些不随滚动条滚动的元素
+        # 这样设计为了应付那些不随滚动条滚动的元素
         if is_loc:
             cx, cy = location_to_client(self.page, lx, ly)
         else:
@@ -59,21 +60,35 @@ class ActionChains:
             cx = x + offset_x
             cy = y + offset_y
 
-        self._dr.run('Input.dispatchMouseEvent', type='mouseMoved', x=cx, y=cy, modifiers=self.modifier)
-        self.curr_x = cx
-        self.curr_y = cy
+        ox = cx - self.curr_x
+        oy = cy - self.curr_y
+        self.move(ox, oy, duration)
         return self
 
-    def move(self, offset_x=0, offset_y=0):
+    def move(self, offset_x=0, offset_y=0, duration=.5):
         """鼠标相对当前位置移动若干位置
         :param offset_x: 偏移量x
         :param offset_y: 偏移量y
+        :param duration: 拖动用时,传入0即瞬间到达
         :return: self
         """
-        self.curr_x += offset_x
-        self.curr_y += offset_y
-        self._dr.run('Input.dispatchMouseEvent', type='mouseMoved', x=self.curr_x, y=self.curr_y,
-                     modifiers=self.modifier)
+        duration = .02 if duration < .02 else duration
+        num = int(duration * 50)
+
+        points = [(self.curr_x + i * (offset_x / num),
+                   self.curr_y + i * (offset_y / num)) for i in range(1, num)]
+        points.append((self.curr_x + offset_x, self.curr_y + offset_y))
+
+        for x, y in points:
+            t = perf_counter()
+            self.curr_x = x
+            self.curr_y = y
+            self._dr.run('Input.dispatchMouseEvent', type='mouseMoved', x=self.curr_x, y=self.curr_y,
+                         modifiers=self.modifier)
+            ss = .02 - perf_counter() + t
+            if ss > 0:
+                sleep(ss)
+
         return self
 
     def click(self, on_ele=None):
@@ -122,7 +137,7 @@ class ActionChains:
         :return: self
         """
         if on_ele:
-            self.move_to(on_ele)
+            self.move_to(on_ele, duration=0)
         self._release('left')
         return self
 
@@ -140,7 +155,7 @@ class ActionChains:
         :return: self
         """
         if on_ele:
-            self.move_to(on_ele)
+            self.move_to(on_ele, duration=0)
         self._release('right')
         return self
 
@@ -158,7 +173,7 @@ class ActionChains:
         :return: self
         """
         if on_ele:
-            self.move_to(on_ele)
+            self.move_to(on_ele, duration=0)
         self._release('middle')
         return self
 
@@ -170,7 +185,7 @@ class ActionChains:
         :return: self
         """
         if on_ele:
-            self.move_to(on_ele)
+            self.move_to(on_ele, duration=0)
         self._dr.run('Input.dispatchMouseEvent', type='mousePressed', button=button, clickCount=count,
                      x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
         return self
@@ -192,7 +207,7 @@ class ActionChains:
         :return: self
         """
         if on_ele:
-            self.move_to(on_ele)
+            self.move_to(on_ele, duration=0)
         self._dr.run('Input.dispatchMouseEvent', type='mouseWheel', x=self.curr_x, y=self.curr_y,
                      deltaX=delta_x, deltaY=delta_y, modifiers=self.modifier)
         return self
diff --git a/DrissionPage/_units/action_chains.pyi b/DrissionPage/_units/action_chains.pyi
index 471c797..1c66af6 100644
--- a/DrissionPage/_units/action_chains.pyi
+++ b/DrissionPage/_units/action_chains.pyi
@@ -20,9 +20,9 @@ class ActionChains:
         self.curr_y: int = ...
 
     def move_to(self, ele_or_loc: Union[ChromiumElement, Tuple[int, int], str],
-                offset_x: int = 0, offset_y: int = 0) -> ActionChains: ...
+                offset_x: int = 0, offset_y: int = 0, duration: float = .5) -> ActionChains: ...
 
-    def move(self, offset_x: int = 0, offset_y: int = 0) -> ActionChains: ...
+    def move(self, offset_x: int = 0, offset_y: int = 0, duration: float = .5) -> ActionChains: ...
 
     def click(self, on_ele: Union[ChromiumElement, str] = None) -> ActionChains: ...
 
diff --git a/DrissionPage/_units/clicker.py b/DrissionPage/_units/clicker.py
index b71688d..a64ebb5 100644
--- a/DrissionPage/_units/clicker.py
+++ b/DrissionPage/_units/clicker.py
@@ -17,19 +17,21 @@ class Clicker(object):
         """
         self._ele = ele
 
-    def __call__(self, by_js=False, timeout=1):
+    def __call__(self, by_js=False, timeout=2, wait_stop=True):
         """点击元素
         如果遇到遮挡,可选择是否用js点击
         :param by_js: 是否用js点击,为None时先用模拟点击,遇到遮挡改用js,为True时直接用js点击,为False时只用模拟点击
-        :param timeout: 模拟点击的超时时间,等待元素可见、不被遮挡、进入视口
+        :param timeout: 模拟点击的超时时间,等待元素可见、可用、进入视口
+        :param wait_stop: 是否等待元素运动结束再执行点击
         :return: 是否点击成功
         """
-        return self.left(by_js, timeout)
+        return self.left(by_js, timeout, wait_stop)
 
-    def left(self, by_js=False, timeout=2):
+    def left(self, by_js=False, timeout=2, wait_stop=True):
         """点击元素,可选择是否用js点击
         :param by_js: 是否用js点击,为None时先用模拟点击,遇到遮挡改用js,为True时直接用js点击,为False时只用模拟点击
-        :param timeout: 模拟点击的超时时间,等待元素可见、不被遮挡、进入视口
+        :param timeout: 模拟点击的超时时间,等待元素可见、可用、进入视口
+        :param wait_stop: 是否等待元素运动结束再执行点击
         :return: 是否点击成功
         """
         if not by_js:  # 模拟点击
@@ -53,7 +55,8 @@ class Clicker(object):
                     rect = self._ele.states.has_rect
                     sleep(.001)
 
-                self._ele.wait.stop_moving(timeout=end_time - perf_counter())
+                if wait_stop:
+                    self._ele.wait.stop_moving(timeout=end_time - perf_counter())
                 if rect:
                     self._ele.scroll.to_see()
                     rect = self._ele.locations.rect
diff --git a/DrissionPage/_units/clicker.pyi b/DrissionPage/_units/clicker.pyi
index dbdcf58..04ec474 100644
--- a/DrissionPage/_units/clicker.pyi
+++ b/DrissionPage/_units/clicker.pyi
@@ -12,9 +12,9 @@ class Clicker(object):
     def __init__(self, ele: ChromiumElement):
         self._ele: ChromiumElement = ...
 
-    def __call__(self, by_js: Union[None, bool] = False, timeout: float = 1) -> bool: ...
+    def __call__(self, by_js: Union[None, bool] = False, timeout: float = 2, wait_stop: bool = True) -> bool: ...
 
-    def left(self, by_js: Union[None, bool] = False, timeout: float = 1) -> bool: ...
+    def left(self, by_js: Union[None, bool] = False, timeout: float = 2, wait_stop: bool = True) -> bool: ...
 
     def right(self) -> None: ...
 
diff --git a/DrissionPage/_units/select_element.py b/DrissionPage/_units/select_element.py
index cc1c29c..9399bb4 100644
--- a/DrissionPage/_units/select_element.py
+++ b/DrissionPage/_units/select_element.py
@@ -241,4 +241,4 @@ class SelectElement(object):
 
     def _dispatch_change(self):
         """触发修改动作"""
-        self._ele.run_js('this.dispatchEvent(new UIEvent("change"));')
+        self._ele.run_js('this.dispatchEvent(new Event("change", {bubbles: true}));')
diff --git a/setup.py b/setup.py
index e164891..35730d9 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh:
 
 setup(
     name="DrissionPage",
-    version="4.0.0b6",
+    version="4.0.0b7",
     author="g1879",
     author_email="g1879@qq.com",
     description="Python based web automation tool. It can control the browser and send and receive data packets.",