这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

Actions接口

用于向 Web 浏览器提供虚拟化设备输入操作的低级接口.

除了高级元素交互之外, Actions 接口 还提供了对指定输入设备 可以执行的确切操作的精细控制. Selenium为3种输入源提供了接口: 键盘设备的键输入, 鼠标, 笔或触摸设备的输入, 以及滚轮设备的滚轮输入 (在Selenium 4.2中引入). Selenium允许您构建分配给特定输入的独立操作命令, 会将他们链接在一起, 并调用关联的执行方法以一次执行它们.

Action构造器

在从遗留JSON Wire协议迁移到 新的W3C WebDriver协议的过程中, 低级的操作构建块变得特别详细. 它非常强大, 但每个输入设备都有多种使用方法, 如果您需要管理多个设备, 则负责确保他们之间的同步正确.

值得庆幸的是, 您可能不需要学习如何直接使用低级命令, 因为您可能要执行的几乎所有操作, 都已提供了相应的简便方法, 这些方法可以为您组合较低级别的命令. 请分别参阅相应的键盘, 鼠标, 滚轮 页面.

暂停

指针移动和滚轮滚动 允许用户设置操作的持续时间, 但有时您只需要在操作之间等待一下, 即可正常工作.

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .moveToElement(clickable)
                .pause(Duration.ofSeconds(1))
                .clickAndHold()
                .pause(Duration.ofSeconds(1))
                .sendKeys("abc")
                .perform();
    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver)\
        .move_to_element(clickable)\
        .pause(1)\
        .click_and_hold()\
        .pause(1)\
        .send_keys("abc")\
        .perform()

Selenium v4.2

            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .MoveToElement(clickable)
                .Pause(TimeSpan.FromSeconds(1))
                .ClickAndHold()
                .Pause(TimeSpan.FromSeconds(1))
                .SendKeys("abc")
                .Perform();

Selenium v4.2

    clickable = driver.find_element(id: 'clickable')
    driver.action
          .move_to(clickable)
          .pause(duration: 1)
          .click_and_hold
          .pause(duration: 1)
          .send_keys('abc')
          .perform
    const clickable = await driver.findElement(By.id('clickable'))
    await driver.actions()
      .move({ origin: clickable })
      .pause(1000)
      .press()
      .pause(1000)
      .sendKeys('abc')
      .perform()
        Actions(driver)
            .moveToElement(clickable)
            .pause(Duration.ofSeconds(1))
            .clickAndHold()
            .pause(Duration.ofSeconds(1))
            .sendKeys("abc")
            .perform() 

释放所有Actions

需要注意的重要一点是, 驱动程序会记住整个会话中所有输入项的状态. 即使创建actions类的新实例, 按下的键和指针的位置 也将处于以前执行的操作离开它们的任何状态.

有一种特殊的方法来释放所有当前按下的键和指针按钮. 此方法在每种语言中的实现方式不同, 因为它不会使用perform方法执行.

        ((RemoteWebDriver) driver).resetInputState();
    ActionBuilder(driver).clear_actions()
            ((WebDriver)driver).ResetInputState();
    driver.action.release_actions
    await driver.actions().clear()

1 - 键盘操作

一种适用于任何与网页交互的按键输入设备的表现形式.

只有 2 个操作可以使用键盘完成: 按下某个键,以及释放一个按下的键. 除了支持 ASCII 字符外,每个键盘按键还具有 可以按特定顺序按下或释放的表现形式.

按键

除了由常规unicode表示的按键, 其他键盘按键被分配了一些unicode值以用于操作Selenium 每种语言都有自己的方式来援引这些按键; 这里 可以找到完整列表

按下按键

        new Actions(driver)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform();
    ActionChains(driver)\
        .key_down(Keys.SHIFT)\
        .send_keys("abc")\
        .perform()
                .KeyDown(Keys.Shift)
                .SendKeys("a")
                .Perform();
    driver.action
          .key_down(:shift)
          .send_keys('a')
          .perform
    await driver.actions()
      .keyDown(Key.SHIFT)
      .sendKeys('a')
      .perform()
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .perform()

释放按键

        new Actions(driver)
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .keyUp(Keys.SHIFT)
                .sendKeys("b")
                .perform();
    ActionChains(driver)\
        .key_down(Keys.SHIFT)\
        .send_keys("a")\
        .key_up(Keys.SHIFT)\
        .send_keys("b")\
        .perform()
            new Actions(driver)
                .KeyDown(Keys.Shift)
                .SendKeys("a")
                .KeyUp(Keys.Shift)
                .SendKeys("b")
                .Perform();
    driver.action
          .key_down(:shift)
          .send_keys('a')
          .key_up(:shift)
          .send_keys('b')
          .perform
    await driver.actions()
      .keyDown(Key.SHIFT)
      .sendKeys('a')
      .keyUp(Key.SHIFT)
      .sendKeys('b')
      .perform()
                .keyDown(Keys.SHIFT)
                .sendKeys("a")
                .keyUp(Keys.SHIFT)
                .sendKeys("b")
                .perform()

键入

这是Actions API的一种便捷方法, 它将 keyDown 和 keyUp 命令组合在一个操作中. 执行此命令与使用 element 方法略有不同, 但这主要用于,需要在其他操作之间键入多个字符时使用.

活跃元素

        new Actions(driver)
                .sendKeys("abc")
                .perform();
    ActionChains(driver)\
        .send_keys("abc")\
        .perform()

            new Actions(driver)
                .SendKeys("abc")
    driver.action
          .send_keys('abc')
          .perform
    await driver.actions()
      .sendKeys('abc')
      .perform()
                .sendKeys("abc")
                .perform()

指定元素

        new Actions(driver)
                .sendKeys(textField, "Selenium!")
                .perform();
    text_input = driver.find_element(By.ID, "textInput")
    ActionChains(driver)\
        .send_keys_to_element(text_input, "abc")\
        .perform()
            driver.FindElement(By.TagName("body")).Click();
            
            IWebElement textField = driver.FindElement(By.Id("textInput"));
            new Actions(driver)
    text_field = driver.find_element(id: 'textInput')
    driver.action
          .send_keys(text_field, 'Selenium!')
          .perform

Selenium v4.5.0

    const textField = await driver.findElement(By.id('textInput'))

    await driver.actions()
      .sendKeys(textField, 'abc')
      .perform()
        Actions(driver)
                .sendKeys(textField, "Selenium!")
                .perform()

复制粘贴

下面是使用上述所有方法执行复制/粘贴操作的示例. 请注意, 用于此操作的键位会有所不同, 具体取决于它是否是 Mac OS. 此代码将以文本收尾: SeleniumSelenium!

        Keys cmdCtrl = Platform.getCurrent().is(Platform.MAC) ? Keys.COMMAND : Keys.CONTROL;

        WebElement textField = driver.findElement(By.id("textInput"));
        new Actions(driver)
                .sendKeys(textField, "Selenium!")
                .sendKeys(Keys.ARROW_LEFT)
                .keyDown(Keys.SHIFT)
                .sendKeys(Keys.ARROW_UP)
                .keyUp(Keys.SHIFT)
                .keyDown(cmdCtrl)
                .sendKeys("xvv")
                .keyUp(cmdCtrl)
                .perform();

        Assertions.assertEquals("SeleniumSelenium!", textField.getAttribute("value"));
    cmd_ctrl = Keys.COMMAND if sys.platform == 'darwin' else Keys.CONTROL

    ActionChains(driver)\
        .send_keys("Selenium!")\
        .send_keys(Keys.ARROW_LEFT)\
        .key_down(Keys.SHIFT)\
        .send_keys(Keys.ARROW_UP)\
        .key_up(Keys.SHIFT)\
        .key_down(cmd_ctrl)\
        .send_keys("xvv")\
        .key_up(cmd_ctrl)\
        .perform()

            var capabilities = ((WebDriver)driver).Capabilities;
            String platformName = (string)capabilities.GetCapability("platformName");

            String cmdCtrl = platformName.Contains("mac") ? Keys.Command : Keys.Control;

            new Actions(driver)
                .SendKeys("Selenium!")
                .SendKeys(Keys.ArrowLeft)
                .KeyDown(Keys.Shift)
                .SendKeys(Keys.ArrowUp)
    driver.action
          .send_keys('Selenium!')
          .send_keys(:arrow_left)
          .key_down(:shift)
          .send_keys(:arrow_up)
          .key_up(:shift)
          .key_down(cmd_ctrl)
          .send_keys('xvv')
          .key_up(cmd_ctrl)
          .perform
    const cmdCtrl = platform.includes('darwin') ? Key.COMMAND : Key.CONTROL

    await driver.actions()
      .click(textField)
      .sendKeys('Selenium!')
      .sendKeys(Key.ARROW_LEFT)
      .keyDown(Key.SHIFT)
      .sendKeys(Key.ARROW_UP)
      .keyUp(Key.SHIFT)
      .keyDown(cmdCtrl)
      .sendKeys('xvv')
      .keyUp(cmdCtrl)
      .perform()

        val textField = driver.findElement(By.id("textInput"))
        Actions(driver)
                .sendKeys(textField, "Selenium!")
                .sendKeys(Keys.ARROW_LEFT)
                .keyDown(Keys.SHIFT)
                .sendKeys(Keys.ARROW_UP)
                .keyUp(Keys.SHIFT)
                .keyDown(cmdCtrl)
                .sendKeys("xvv")
                .keyUp(cmdCtrl)
                .perform()

2 - 鼠标操作

任何用于与网页进行交互的指针设备的表示形式.

一个鼠标仅可以完成3个操作: 按住按钮,松开按钮,还有移动光标。 Selenium组合了常见的操作并提供了方便的方法。

按住鼠标左键

这个方法包含2个操作,首先将光标移动到被操作元素的正中心,然后按下鼠标左键不松开。 这对于聚焦一个特殊元素很有用:

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .clickAndHold(clickable)
                .perform();
    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver) \
        .click_and_hold(clickable) \
        .perform()
            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .ClickAndHold(clickable)
                .Perform();
    clickable = driver.find_element(id: 'clickable')
    driver.action
          .click_and_hold(clickable)
          .perform
    let clickable = driver.findElement(By.id("clickable"));
    const actions = driver.actions({async: true});
    await actions.move({origin: clickable}).press().perform();
                .clickAndHold(clickable)
                .perform()

        Assertions.assertEquals("focused", driver.findElement(By.id("click-status")).getText())

点击鼠标左键

这个方法包含2个操作,首先将光标移动到被操作元素的正中心,然后按下鼠标左键后再松开。 另一种叫法“点击”:

        WebElement clickable = driver.findElement(By.id("click"));
        new Actions(driver)
                .click(clickable)
                .perform();
    clickable = driver.find_element(By.ID, "click")
    ActionChains(driver) \
        .click(clickable) \
        .perform()
            IWebElement clickable = driver.FindElement(By.Id("click"));
            new Actions(driver)
                .Click(clickable)
                .Perform();
    clickable = driver.find_element(id: 'click')
    driver.action
          .click(clickable)
          .perform
    let click = driver.findElement(By.id("click"));
    const actions = driver.actions({async: true});
    await actions.move({origin: click}).click().perform();
                .click(clickable)
                .perform()

        Assertions.assertTrue(driver.getCurrentUrl()!!.contains("resultPage.html"))

点击鼠标备用按钮

鼠标一共有5个定义好的按钮:

  • 0 — 左键 (默认值)
  • 1 — 中间键 (当前不支持)
  • 2 — 右键
  • 3 — X1 (返回) 按钮
  • 4 — X2 (前进) 按钮

点击鼠标右键

这个方法包含2个操作,首先将光标移动到被操作元素的正中心,然后点击鼠标右键。 另一种叫法“点击右键”:

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .contextClick(clickable)
                .perform();
    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver) \
        .context_click(clickable) \
        .perform()
            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .ContextClick(clickable)
                .Perform();
      clickable = driver.find_element(id: 'clickable')
      driver.action
            .context_click(clickable)
            .perform
    const clickable = driver.findElement(By.id("clickable"));
    const actions = driver.actions({async: true});
    await actions.contextClick(clickable).perform();
                .contextClick(clickable)
                .perform()

        Assertions.assertEquals("context-clicked", driver.findElement(By.id("click-status")).getText())

点击鼠标回退键

除了这个没有更方便的方法,只是点击鼠标回退按钮

        PointerInput mouse = new PointerInput(PointerInput.Kind.MOUSE, "default mouse");

        Sequence actions = new Sequence(mouse, 0)
                .addAction(mouse.createPointerDown(PointerInput.MouseButton.BACK.asArg()))
                .addAction(mouse.createPointerUp(PointerInput.MouseButton.BACK.asArg()));

        ((RemoteWebDriver) driver).perform(Collections.singletonList(actions));

Selenium v4.2

    action = ActionBuilder(driver)
    action.pointer_action.pointer_down(MouseButton.BACK)
    action.pointer_action.pointer_up(MouseButton.BACK)
    action.perform()

Selenium v4.2

            ActionBuilder actionBuilder = new ActionBuilder();
            PointerInputDevice mouse = new PointerInputDevice(PointerKind.Mouse, "default mouse");
            actionBuilder.AddAction(mouse.CreatePointerDown(MouseButton.Back));
            actionBuilder.AddAction(mouse.CreatePointerUp(MouseButton.Back));
            ((IActionExecutor)driver).PerformActions(actionBuilder.ToActionSequenceList());

Selenium v4.2

      driver.action
            .pointer_down(:back)
            .pointer_up(:back)
            .perform

Selenium v4.5.0

    const actions = driver.actions({async: true});
    await actions.press(Button.BACK).release(Button.BACK).perform()
        val actions = Sequence(mouse, 0)
                .addAction(mouse.createPointerDown(PointerInput.MouseButton.BACK.asArg()))
                .addAction(mouse.createPointerUp(PointerInput.MouseButton.BACK.asArg()))

        (driver as RemoteWebDriver).perform(Collections.singletonList(actions))

        Assertions.assertEquals("BasicMouseInterfaceTest", driver.getTitle())

点击鼠标前进键

除了这个没有更方便的方法,只是点击鼠标前进按钮

        PointerInput mouse = new PointerInput(PointerInput.Kind.MOUSE, "default mouse");

        Sequence actions = new Sequence(mouse, 0)
                .addAction(mouse.createPointerDown(PointerInput.MouseButton.FORWARD.asArg()))
                .addAction(mouse.createPointerUp(PointerInput.MouseButton.FORWARD.asArg()));

        ((RemoteWebDriver) driver).perform(Collections.singletonList(actions));

Selenium v4.2

    action = ActionBuilder(driver)
    action.pointer_action.pointer_down(MouseButton.FORWARD)
    action.pointer_action.pointer_up(MouseButton.FORWARD)
    action.perform()

Selenium v4.2

            ActionBuilder actionBuilder = new ActionBuilder();
            PointerInputDevice mouse = new PointerInputDevice(PointerKind.Mouse, "default mouse");
            actionBuilder.AddAction(mouse.CreatePointerDown(MouseButton.Forward));
            actionBuilder.AddAction(mouse.CreatePointerUp(MouseButton.Forward));
            ((IActionExecutor)driver).PerformActions(actionBuilder.ToActionSequenceList());

Selenium v4.2

      driver.action
            .pointer_down(:forward)
            .pointer_up(:forward)
            .perform

Selenium v4.5.0

    const actions = driver.actions({async: true});
    await actions.press(Button.FORWARD).release(Button.FORWARD).perform()
        val actions = Sequence(mouse, 0)
                .addAction(mouse.createPointerDown(PointerInput.MouseButton.FORWARD.asArg()))
                .addAction(mouse.createPointerUp(PointerInput.MouseButton.FORWARD.asArg()))

        (driver as RemoteWebDriver).perform(Collections.singletonList(actions))

        Assertions.assertEquals("We Arrive Here", driver.getTitle())

双击鼠标左键

这个方法包含2个操作,首先将光标移动到被操作元素的正中心,然后双击鼠标左键。

        WebElement clickable = driver.findElement(By.id("clickable"));
        new Actions(driver)
                .doubleClick(clickable)
                .perform();
    clickable = driver.find_element(By.ID, "clickable")
    ActionChains(driver) \
        .double_click(clickable) \
        .perform()
            IWebElement clickable = driver.FindElement(By.Id("clickable"));
            new Actions(driver)
                .DoubleClick(clickable)
                .Perform();
    clickable = driver.find_element(id: 'clickable')
    driver.action
          .double_click(clickable)
          .perform
    const clickable = driver.findElement(By.id("clickable"));
    const actions = driver.actions({async: true});
    await actions.doubleClick(clickable).perform();
                .doubleClick(clickable)
                .perform()

        Assertions.assertEquals("double-clicked", driver.findElement(By.id("click-status")).getText())

移动光标到元素上

这个方法是将光标移动到元素的中心点。 另一种叫法“悬停”。 元素必须在可视窗口范围内否则这条命令将会报错。

        WebElement hoverable = driver.findElement(By.id("hover"));
        new Actions(driver)
                .moveToElement(hoverable)
                .perform();
    hoverable = driver.find_element(By.ID, "hover")
    ActionChains(driver) \
        .move_to_element(hoverable) \
        .perform()
            IWebElement hoverable = driver.FindElement(By.Id("hover"));
            new Actions(driver)
                .MoveToElement(hoverable)
                .Perform();
    hoverable = driver.find_element(id: 'hover')
    driver.action
          .move_to(hoverable)
          .perform
    const hoverable = driver.findElement(By.id("hover"));
    const actions = driver.actions({async: true});
    await actions.move({origin: hoverable}).perform();
                .moveToElement(hoverable)
                .perform()

        Assertions.assertEquals("hovered", driver.findElement(By.id("move-status")).getText())

通过偏移量移动动光标

这些方法让光标先移动到指定的坐标原点,然后通过单位为px的偏移量进行光标相对原点的偏移移动。 注意光标位置必须在可视窗口区域否则会报错。

从元素中心点(原点)偏移

这个方法是指先将光标移动到元素中心点(原点),然后通过偏移量进行光标相对原点的偏移。

        WebElement tracker = driver.findElement(By.id("mouse-tracker"));
        new Actions(driver)
                .moveToElement(tracker, 8, 0)
                .perform();
    mouse_tracker = driver.find_element(By.ID, "mouse-tracker")
    ActionChains(driver) \
        .move_to_element_with_offset(mouse_tracker, 8, 0) \
        .perform()
            IWebElement tracker = driver.FindElement(By.Id("mouse-tracker"));
            new Actions(driver)
                .MoveToElement(tracker, 8, 0)
                .Perform();
      mouse_tracker = driver.find_element(id: 'mouse-tracker')
      driver.action
            .move_to(mouse_tracker, 8, 11)
            .perform
    const mouseTracker = driver.findElement(By.id("mouse-tracker"));
    const actions = driver.actions({async: true});
    await actions.move({x: 8, y: 0, origin: mouseTracker}).perform();
                .moveToElement(tracker, 8, 0)
                .perform()

        val result = driver.findElement(By.id("relative-location")).getText().split(", ")

从视窗左上角(原点)偏移

这个方法是指先将光标移动到视窗左上角(原点),然后通过偏移量进行光标相对原点的偏移。

        PointerInput mouse = new PointerInput(PointerInput.Kind.MOUSE, "default mouse");

        Sequence actions = new Sequence(mouse, 0)
                .addAction(mouse.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), 8, 12));

        ((RemoteWebDriver) driver).perform(Collections.singletonList(actions));
    action = ActionBuilder(driver)
    action.pointer_action.move_to_location(8, 0)
    action.perform()
            ActionBuilder actionBuilder = new ActionBuilder();
            PointerInputDevice mouse = new PointerInputDevice(PointerKind.Mouse, "default mouse");
            actionBuilder.AddAction(mouse.CreatePointerMove(CoordinateOrigin.Viewport,
                8, 0, TimeSpan.Zero));
            ((IActionExecutor)driver).PerformActions(actionBuilder.ToActionSequenceList());
      driver.action
            .move_to_location(8, 12)
            .perform
    const actions = driver.actions({async: true});
    await actions.move({x: 8, y: 0}).perform();
        val actions = Sequence(mouse, 0)
                .addAction(mouse.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), 8, 12))

        (driver as RemoteWebDriver).perform(Collections.singletonList(actions))

        val result = driver.findElement(By.id("absolute-location")).getText().split(", ")

从当前光标位置(原点)偏移

这个方法是指光标位于当前位置(原点),然后通过偏移量进行光标相对原点的偏移。 如果之前没有移动过光标位置,则这个位置是视窗左上角(原点)。 注意当页面发生滚动后光标位置不会发生变化。

注意第一个参数指定为正数时向右移动,第二个参数指定为正数时向下移动。所以 moveByOffset(30, -10) 是指从当前光标位置向右移动30个像素位置和向上移动10个像素位置。

        new Actions(driver)
                .moveByOffset(13, 15)
                .perform();
    ActionChains(driver) \
        .move_by_offset(13, 15) \
        .perform()
            new Actions(driver)
                .MoveByOffset(13, 15)
                .Perform();
      driver.action
            .move_by(13, 15)
            .perform
    await actions.move({x: 13, y: 15, origin: Origin.POINTER}).perform()
                .perform()

        val result = driver.findElement(By.id("absolute-location")).getText().split(", ") 

拖放元素

这个方法首先在原元素上提交执行按下鼠标左键,移动到目标元素位置后是释放鼠标左键。

        WebElement draggable = driver.findElement(By.id("draggable"));
        WebElement droppable = driver.findElement(By.id("droppable"));
        new Actions(driver)
                .dragAndDrop(draggable, droppable)
                .perform();
    draggable = driver.find_element(By.ID, "draggable")
    droppable = driver.find_element(By.ID, "droppable")
    ActionChains(driver) \
        .drag_and_drop(draggable, droppable) \
        .perform()
            IWebElement draggable = driver.FindElement(By.Id("draggable"));
            IWebElement droppable = driver.FindElement(By.Id("droppable"));
            new Actions(driver)
                .DragAndDrop(draggable, droppable)
                .Perform();
    draggable = driver.find_element(id: 'draggable')
    droppable = driver.find_element(id: 'droppable')
    driver.action
          .drag_and_drop(draggable, droppable)
          .perform
    const draggable = driver.findElement(By.id("draggable"));
    const droppable = await driver.findElement(By.id("droppable"));
    const actions = driver.actions({async: true});
    await actions.dragAndDrop(draggable, droppable).perform();
        Actions(driver)
                .dragAndDrop(draggable, droppable)
                .perform()

        Assertions.assertEquals("dropped", driver.findElement(By.id("drop-status")).getText())

通过偏移量拖放元素

这个方法首先在原元素上提交执行按下鼠标左键,通过给出的偏移量移动元素后释放鼠标左键。

        WebElement draggable = driver.findElement(By.id("draggable"));
        Rectangle start = draggable.getRect();
        Rectangle finish = driver.findElement(By.id("droppable")).getRect();
        new Actions(driver)
                .dragAndDropBy(draggable, finish.getX() - start.getX(), finish.getY() - start.getY())
                .perform();
    draggable = driver.find_element(By.ID, "draggable")
    start = draggable.location
    finish = driver.find_element(By.ID, "droppable").location
    ActionChains(driver) \
        .drag_and_drop_by_offset(draggable, finish['x'] - start['x'], finish['y'] - start['y']) \
        .perform()
            IWebElement draggable = driver.FindElement(By.Id("draggable"));
            Point start = draggable.Location;
            Point finish = driver.FindElement(By.Id("droppable")).Location;
            new Actions(driver)
                .DragAndDropToOffset(draggable, finish.X - start.X, finish.Y - start.Y)
                .Perform();
    draggable = driver.find_element(id: 'draggable')
    start = draggable.rect
    finish = driver.find_element(id: 'droppable').rect
    driver.action
          .drag_and_drop_by(draggable, finish.x - start.x, finish.y - start.y)
          .perform
    const draggable = driver.findElement(By.id("draggable"));
    let start = await draggable.getRect();
    let finish = await driver.findElement(By.id("droppable")).getRect();
    const actions = driver.actions({async: true});
    await actions.dragAndDrop(draggable, {x: finish.x - start.x, y: finish.y - start.y}).perform();
        val finish = driver.findElement(By.id("droppable")).getRect()
        Actions(driver)
                .dragAndDropBy(draggable, finish.getX() - start.getX(), finish.getY() - start.getY())
                .perform()

        Assertions.assertEquals("dropped", driver.findElement(By.id("drop-status")).getText())

3 - 触控笔操作

一种用于与网页交互的类似笔尖的指针输入设备的表示.

Chromium Only

触控笔是一种指针输入设备,其行为大多与鼠标相同, 但也可以具有触控笔特有的事件属性。 此外,鼠标有 5 个按钮,而触控笔有 3 种等效的按钮状态:

  • 0 - 触摸接触(默认设置;相当于左键单击)
  • 2 - 桶形按钮/侧键(相当于右键点击)
  • 5 - 橡皮擦按钮(当前驱动程序不支持)

使用触控笔

Selenium v4.2

        WebElement pointerArea = driver.findElement(By.id("pointerArea"));
        new Actions(driver)
                .setActivePointer(PointerInput.Kind.PEN, "default pen")
                .moveToElement(pointerArea)
                .clickAndHold()
                .moveByOffset(2, 2)
                .release()
                .perform();

Selenium v4.2

    pointer_area = driver.find_element(By.ID, "pointerArea")
    pen_input = PointerInput(POINTER_PEN, "default pen")
    action = ActionBuilder(driver, mouse=pen_input)
    action.pointer_action\
        .move_to(pointer_area)\
        .pointer_down()\
        .move_by(2, 2)\
        .pointer_up()
    action.perform()
            IWebElement pointerArea = driver.FindElement(By.Id("pointerArea"));
            ActionBuilder actionBuilder = new ActionBuilder();
            PointerInputDevice pen = new PointerInputDevice(PointerKind.Pen, "default pen");
            
            actionBuilder.AddAction(pen.CreatePointerMove(pointerArea, 0, 0, TimeSpan.FromMilliseconds(800)));
            actionBuilder.AddAction(pen.CreatePointerDown(MouseButton.Left));
            actionBuilder.AddAction(pen.CreatePointerMove(CoordinateOrigin.Pointer,
                2, 2, TimeSpan.Zero));
            actionBuilder.AddAction(pen.CreatePointerUp(MouseButton.Left));
            ((IActionExecutor)driver).PerformActions(actionBuilder.ToActionSequenceList());

Selenium v4.2

    pointer_area = driver.find_element(id: 'pointerArea')
    driver.action(devices: :pen)
          .move_to(pointer_area)
          .pointer_down
          .move_by(2, 2)
          .pointer_up
          .perform
        Actions(driver)
                .setActivePointer(PointerInput.Kind.PEN, "default pen")
                .moveToElement(pointerArea)
                .clickAndHold()
                .moveByOffset(2, 2)
                .release()
                .perform()

添加指针事件属性

Selenium v4.2

        WebElement pointerArea = driver.findElement(By.id("pointerArea"));
        PointerInput pen = new PointerInput(PointerInput.Kind.PEN, "default pen");
        PointerInput.PointerEventProperties eventProperties = PointerInput.eventProperties()
                .setTiltX(-72)
                .setTiltY(9)
                .setTwist(86);
        PointerInput.Origin origin = PointerInput.Origin.fromElement(pointerArea);

        Sequence actionListPen = new Sequence(pen, 0)
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 0, 0))
                .addAction(pen.createPointerDown(0))
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 2, 2, eventProperties))
                .addAction(pen.createPointerUp(0));

        ((RemoteWebDriver) driver).perform(Collections.singletonList(actionListPen));
    pointer_area = driver.find_element(By.ID, "pointerArea")
    pen_input = PointerInput(POINTER_PEN, "default pen")
    action = ActionBuilder(driver, mouse=pen_input)
    action.pointer_action\
        .move_to(pointer_area)\
        .pointer_down()\
        .move_by(2, 2, tilt_x=-72, tilt_y=9, twist=86)\
        .pointer_up(0)
    action.perform()
            IWebElement pointerArea = driver.FindElement(By.Id("pointerArea"));
            ActionBuilder actionBuilder = new ActionBuilder();
            PointerInputDevice pen = new PointerInputDevice(PointerKind.Pen, "default pen");
            PointerInputDevice.PointerEventProperties properties = new PointerInputDevice.PointerEventProperties() {
                TiltX = -72,
                TiltY = 9,
                Twist = 86,
            };            
            actionBuilder.AddAction(pen.CreatePointerMove(pointerArea, 0, 0, TimeSpan.FromMilliseconds(800)));
            actionBuilder.AddAction(pen.CreatePointerDown(MouseButton.Left));
            actionBuilder.AddAction(pen.CreatePointerMove(CoordinateOrigin.Pointer,
                2, 2, TimeSpan.Zero, properties));
            actionBuilder.AddAction(pen.CreatePointerUp(MouseButton.Left));
            ((IActionExecutor)driver).PerformActions(actionBuilder.ToActionSequenceList());
    pointer_area = driver.find_element(id: 'pointerArea')
    driver.action(devices: :pen)
          .move_to(pointer_area)
          .pointer_down
          .move_by(2, 2, tilt_x: -72, tilt_y: 9, twist: 86)
          .pointer_up
          .perform
        val pen = PointerInput(PointerInput.Kind.PEN, "default pen")
        val eventProperties = PointerInput.eventProperties()
                .setTiltX(-72)
                .setTiltY(9)
                .setTwist(86)
        val origin = PointerInput.Origin.fromElement(pointerArea)
        
        val actionListPen = Sequence(pen, 0)
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 0, 0))
                .addAction(pen.createPointerDown(0))
                .addAction(pen.createPointerMove(Duration.ZERO, origin, 2, 2, eventProperties))
                .addAction(pen.createPointerUp(0))

        (driver as RemoteWebDriver).perform(listOf(actionListPen))
                    

4 - 滚轮操作

一种用于与网页交互的滚轮输入设备的示意.

Selenium v4.2

Chromium Only

在页面上滚动有 5 种情况.

滚动到元素

这是最常见的场景. 与传统的点击和发送按键的方法不同, 动作类不会自动将目标元素滚动到视图中, 因此如果元素不在视口内, 就需要使用此方法.

此方法仅将一个网页元素作为参数.

无论该元素是在当前视图屏幕的上方还是下方, 视口都会滚动, 使该元素的底部位于屏幕底部.

        WebElement iframe = driver.findElement(By.tagName("iframe"));
        new Actions(driver)
                .scrollToElement(iframe)
                .perform();
    iframe = driver.find_element(By.TAG_NAME, "iframe")
    ActionChains(driver)\
        .scroll_to_element(iframe)\
        .perform()
            IWebElement iframe = driver.FindElement(By.TagName("iframe"));
            new Actions(driver)
                .ScrollToElement(iframe)
                .Perform();
    iframe = driver.find_element(tag_name: 'iframe')
    driver.action
          .scroll_to(iframe)
          .perform
    const iframe = await driver.findElement(By.css("iframe"))
    await driver.actions()
      .scroll(0, 0, 0, 0, iframe)
      .perform()
        val iframe = driver.findElement(By.tagName("iframe"))
        Actions(driver)
                .scrollToElement(iframe)
                .perform()

按给定的量进行滚动

这是第二种最常见的滚动场景. 传入一个 x 方向的偏移量和一个 y 方向的偏移量, 表示向右和向下滚动的距离. 负值分别表示向左和向上滚动.

        WebElement footer = driver.findElement(By.tagName("footer"));
        int deltaY = footer.getRect().y;
        new Actions(driver)
                .scrollByAmount(0, deltaY)
                .perform();
    footer = driver.find_element(By.TAG_NAME, "footer")
    delta_y = footer.rect['y']
    ActionChains(driver)\
        .scroll_by_amount(0, delta_y)\
        .perform()
            IWebElement footer = driver.FindElement(By.TagName("footer"));
            int deltaY = footer.Location.Y;
            new Actions(driver)
                .ScrollByAmount(0, deltaY)
                .Perform();
    footer = driver.find_element(tag_name: 'footer')
    delta_y = footer.rect.y
    driver.action
          .scroll_by(0, delta_y)
          .perform
    const footer = await driver.findElement(By.css("footer"))
    const deltaY = (await footer.getRect()).y

    await driver.actions()
      .scroll(0, 0, 0, deltaY)
      .perform()
        val footer = driver.findElement(By.tagName("footer"))
        val deltaY = footer.getRect().y
        Actions(driver)
                .scrollByAmount(0, deltaY)
                .perform()

将元素按照给定的量进行滚动

这种情形实际上是上述两种方法的结合.

要执行此操作, 请使用“从…滚动”方法, 该方法需要 3 个参数.
第一个参数表示起始点, 我们将其指定为元素,
后两个参数分别是 x 偏移量和 y 偏移量的值.

如果元素不在视口内, 它将滚动到屏幕底部, 然后页面将根据提供的 x 和 y 偏移量进行滚动.

        WebElement iframe = driver.findElement(By.tagName("iframe"));
        WheelInput.ScrollOrigin scrollOrigin = WheelInput.ScrollOrigin.fromElement(iframe);
        new Actions(driver)
                .scrollFromOrigin(scrollOrigin, 0, 200)
                .perform();
    iframe = driver.find_element(By.TAG_NAME, "iframe")
    scroll_origin = ScrollOrigin.from_element(iframe)
    ActionChains(driver)\
        .scroll_from_origin(scroll_origin, 0, 200)\
        .perform()
            IWebElement iframe = driver.FindElement(By.TagName("iframe"));
            WheelInputDevice.ScrollOrigin scrollOrigin = new WheelInputDevice.ScrollOrigin
            {
                Element = iframe
            };
            new Actions(driver)
                .ScrollFromOrigin(scrollOrigin, 0, 200)
                .Perform();
    iframe = driver.find_element(tag_name: 'iframe')
    scroll_origin = Selenium::WebDriver::WheelActions::ScrollOrigin.element(iframe)
    driver.action
          .scroll_from(scroll_origin, 0, 200)
          .perform
    const iframe = await driver.findElement(By.css("iframe"))

    await driver.actions()
      .scroll(0, 0, 0, 200, iframe)
      .perform()
        val iframe = driver.findElement(By.tagName("iframe"))
        val scrollOrigin = WheelInput.ScrollOrigin.fromElement(iframe)
        Actions(driver)
                .scrollFromOrigin(scrollOrigin, 0, 200)
                .perform()

从具有偏移量的元素进行滚动

当您需要滚动屏幕的某一部分, 而该部分位于视口之外, 或者位于视口之内但必须滚动的屏幕部分与特定元素之间存在已知偏移量时, 会使用此场景.

这再次使用了“从…滚动”的方法, 并且除了指定元素之外, 还指定了一个偏移量来表明滚动的起始点. 该偏移量是从所提供的元素的中心计算得出的.

如果元素不在视口内, 它首先会被滚动到屏幕底部, 然后滚动的原点将通过将偏移量添加到元素中心的坐标来确定, 最后页面将根据提供的 x 和 y 偏移量值进行滚动.

请注意, 如果元素中心的偏移量超出视口范围, 将会导致异常.

        WebElement footer = driver.findElement(By.tagName("footer"));
        WheelInput.ScrollOrigin scrollOrigin = WheelInput.ScrollOrigin.fromElement(footer, 0, -50);
        new Actions(driver)
                .scrollFromOrigin(scrollOrigin,0, 200)
                .perform();
    footer = driver.find_element(By.TAG_NAME, "footer")
    scroll_origin = ScrollOrigin.from_element(footer, 0, -50)
    ActionChains(driver)\
        .scroll_from_origin(scroll_origin, 0, 200)\
        .perform()
            IWebElement footer = driver.FindElement(By.TagName("footer"));
            var scrollOrigin = new WheelInputDevice.ScrollOrigin
            {
                Element = footer,
                XOffset = 0,
                YOffset = -50
            };
            new Actions(driver)
                .ScrollFromOrigin(scrollOrigin, 0, 200)
                .Perform();
    expect(in_viewport?(checkbox)).to eq true
  end

  it 'scrolls by given amount with offset' do
    driver.get('https://selenium.dev/selenium/web/scrolling_tests/frame_with_nested_scrolling_frame.html')

    await driver.sleep(500)

    await driver.switchTo().frame(iframe)
    const checkbox = await driver.findElement(By.name('scroll_checkbox'))
        val footer = driver.findElement(By.tagName("footer"))
        val scrollOrigin = WheelInput.ScrollOrigin.fromElement(footer, 0, -50)
        Actions(driver)
                .scrollFromOrigin(scrollOrigin,0, 200)
                .perform()

从给定元素的原点偏移量处滚动指定的距离

最后一种情况适用于您需要滚动屏幕的某一部分, 而该部分已处于视口内的情况.

这再次使用了“从…滚动”的方法, 但这次指定的是视口而非某个元素. 从当前视口的左上角开始指定偏移量. 确定原点后, 页面将根据提供的 x 偏移量和 y 偏移量进行滚动.

请注意, 如果从视口左上角算起的偏移量超出屏幕范围, 将会导致异常.

        WheelInput.ScrollOrigin scrollOrigin = WheelInput.ScrollOrigin.fromViewport(10, 10);
        new Actions(driver)
                .scrollFromOrigin(scrollOrigin, 0, 200)
                .perform();
    scroll_origin = ScrollOrigin.from_viewport(10, 10)

    ActionChains(driver)\
        .scroll_from_origin(scroll_origin, 0, 200)\
        .perform()
            var scrollOrigin = new WheelInputDevice.ScrollOrigin
            {
                Viewport = true,
                XOffset = 10,
                YOffset = 10
            };
            new Actions(driver)
                .ScrollFromOrigin(scrollOrigin, 0, 200)
                .Perform();
    scroll_origin = Selenium::WebDriver::WheelActions::ScrollOrigin.viewport(10, 10)
    driver.action
          .scroll_from(scroll_origin, 0, 200)
          .perform
    await driver.actions()
      .scroll(10, 10, 0, 200)
      .perform()
        val scrollOrigin = WheelInput.ScrollOrigin.fromViewport(10, 10)
        Actions(driver)
                .scrollFromOrigin(scrollOrigin, 0, 200)
                .perform()