Element 对象

Element 对象是对JavaScript DOM对象的封装,它们在一些函数返回任意类型的DOM节点时被创建(节点、元素、HTML元素等等)。

splash:selectsplash:select_all 返回Element对象, splash:evaljs 也可能返回Element对象,但是目前它们不能被放到数组或其他对象 中一起返回。它们必须作为顶层节点或者节点的列表被返回。

方法

要修改或者检索有关元素的信息,您可以使用下列的方法

element:mouse_click

在元素上触发鼠标点击消息

原型: ok, reason = element:mouse_click{x=nil, y=nil}

参数:

  • x:可选值,相对于元素左上角的x的坐标
  • y:可选值,相对于元素左上角的y的坐标

返回值: ok, reason 元组,当函数在执行过程中发生错误的时候 ok 的值为nil. reason 包含了一个表示错误类型的字符串

是否异步:

如果没有指定x和y的值,默认为元素宽的一半和高的一半,点击事件将在元素的中间被触发。

这个坐标可以是负值,这意味着点击事件将在元素之外触发。

例1:在靠近元素左上角的位置触发点击事件

function main(splash)
    -- ...
    local element = splash:select('.element')
    local bounds = element:bounds()
    assert(element:mouse_click{x=bounds.width/3, y=bounds.height/3})
    -- ...
end

例2:在元素上方10个像素的位置触发点击事件

function main(splash)
    -- ...
    splash:set_viewport_full()
    local element = splash:select('.element')
    assert(element:mouse_click{y=-10})
    -- ...
end

splash:mouse_click 不同,element:mouse_click 会一直等待直到点击事件执行。所以如果要看点击事件执行之后在页面上产生的效果,您不需要调用 splash:wait 进行等待

如果当前元素不在视口范围之内,视口会被自动滚动到合适的位置,以便让元素可见,如果需要滚动页面,在点击事件被触发之后,页面不会自动滚回原来的位置.

您可以在 splash:mouse_click 中查阅更多与鼠标事件相关的内容

element:mouse_hover

在对应元素上触发鼠标悬停事件(JavaScript mouseover 事件)

原型: ok, reason = element:mouse_hover{x=0, y=0}

参数:

  • x:可选值,相对于元素左上角的x的坐标
  • y:可选值,相对于元素左上角的y的坐标

返回值: ok, reason 元组,当函数在执行过程中发生错误的时候 ok 的值为nil. reason 包含了一个表示错误类型的字符串

是否异步:

如果没有指定x和y的值,默认为元素宽的一半和高的一半,鼠标悬停事件将在元素的中间被触发。

这个坐标可以是负值,这意味着鼠标悬停事件将在元素之外触发。

例1:在靠近元素左上角的位置触鼠标悬停事件

function main(splash)
    -- ...
    local element = splash:select('.element')
    assert(element:mouse_hover{x=0, y=0})
    -- ...
end

例2:在元素上方10个像素的位置触发鼠标悬停事件

function main(splash)
    -- ...
    splash:set_viewport_full()
    local element = splash:select('.element')
    assert(element:mouse_hover{y=-10})
    -- ...
end

splash:mouse_hover 不同,element:mouse_hover 会一直等待直到点击事件执行。所以如果要看点击事件执行之后在页面上产生的效果,您不需要调用 splash:wait 进行等待

如果当前元素不在视口范围之内,视口会被自动滚动到合适的位置,以便让元素可见,如果需要滚动页面,在点击事件被触发之后,页面不会自动滚回原来的位置.

您可以在 splash:mouse_hover 中查阅更多与鼠标事件相关的内容

element:styles

获取元素的所有样式信息

原型: styles = element:styles()

返回值: style 是一个描述获取到的样式的table结构

是否异步:

这个方法返回在元素上调用 window.getComputedStyle() 获取到的结果

例子:获取元素所有的样式,并返回 font-size 属性

function main(splash)
    -- ...
    local element = splash:select('.element')
    return element:styles()['font-size']
end

element:bounds

返回元素bounding框的矩形

原型: bounds = element:bounds()

返回值: bounds 是一个table结构,里面包含了bounding框的 top , right , bottomleft . 同时它也包含了bounding 框的 widthheight

是否异步:

例子:获取元素的边界

function main(splash)
    -- ..
    local element = splash:select('.element')
    return element:bounds()
    -- e.g. bounds is { top = 10, right = 20, bottom = 20, left = 10, height = 10, width = 10 }
end

element:png

以png格式返回元素的截图

原型: shot = element:png{width=nil, scale_method='raster', pad=0}

参数:

  • width:可选值,截图的宽,以像素为单位
  • scale_method:可选值,缩放图片的方式, 可选的值有 'raster''vector'
  • pad: 可选值, 整型或者是 {left, top, right, bottom} 结构的padding 值

返回值:二进制对象 表示的PNG 截图的数据, 如果结果为空 (例如元素在DOM中不存在,或者不可见)会返回nil

是否异步:

pad 参数设置返回图片的 padding 值,如果是一个整数值,那么padding中 所有的边距都相同,如果值为正数,那么截图会在原来元素的 基础上扩充指定像素大小,如果未负值,截图会在原来元素的基础上压缩指定像素大小.

例子:返回一个填充指定大小的元素截图

function main(splash)
    -- ..
    local element = splash:select('.element')
    return element:png{pad=10}
end

如果元素不在视口中, 视口会暂时滚动以便让元素可见,然后再滚回到原来的位置

您可以参阅 splash:png

element:jpeg

以jpeg格式返回元素的截图

原型: shot = element:jpeg{width=nil, scale_method='raster', quality=75, region=nil, pad=0}

参数:

  • width:可选值,截图的宽,以像素为单位
  • scale_method:可选值,缩放图片的方式, 可选的值有 'raster''vector'
  • quality: 可选值,生成jpeg图片的质量,为 0100 的整数值
  • pad: 可选值, 整型或者是 {left, top, right, bottom} 结构的padding 值

返回值:二进制对象 表示的jpeg 截图的数据, 如果结果为空 (例如元素在DOM中不存在,或者不可见)会返回nil

是否异步:

pad 参数设置返回图片的 padding 值,如果是一个整数值,那么padding中 所有的边距都相同,如果值为正数,那么截图会在原来元素的 基础上扩充指定像素大小,如果未负值,截图会在原来元素的基础上压缩指定像素大小.

如果元素不在视口中, 视口会暂时滚动以便让元素可见,然后再滚回到原来的位置

您可以参阅 splash:jpeg

element:visible

判断元素是否可见

原型: visible = element:visible()

返回值: visible 表示元素是否可见

是否异步:

element:focused

检测元素是否获取到焦点

原型: focused = element:focused()

返回值: focused 表示元素是否获取到焦点

是否异步:

element:text

从元素中获取文本信息

原型: text = element:text()

返回值: text 表示元素的文本内容

是否异步:

它会尝试返回以下JavaScript节点的属性值:

  • textContent
  • innerText
  • value

如果这些值都为空,则会返回空值

element-info

获取元素的有用信息

原型: info = element:info()

返回值: info 表示元素的相关信息

是否异步:

info 是一个包含以下字段的table结构

  • nodeName - 以小写字母表示的节点的名称(比如 h1)
  • attributes - 以属性名和属性值为键值对的table结构
  • tag - 表示该元素的HTML的字符串
  • html - 元素内部的HTML代码
  • text - 元素内部的文本值
  • x - 元素的x坐标
  • y - 元素的y坐标
  • width - 元素的宽
  • height - 元素的高
  • visible - 元素是否可见的一个标志

element:field_value

获取元素字段的值(针对 input, select, textarea, button)

原型: ok, value = element:field_value()

返回值: ok, value 的元组,如果ok为 nil 表明在执行函数的过程中有错误发生, 此时 value 是一个包含错误类型信息的字符串。如果没有错误发生, oktrue value 为对应元素字段的值

是否异步:

这些方法按照以下方式工作:

  • 如果当前元素是 select :
    • 如果元素的 multiple 属性为 true 它会以table结构返回所有被选中的值
    • 否则返回被选中的一个值
  • 如果元素存在属性 type="radio" :
    • 如果它被选中,则返回选中的值
    • 否则返回 nil
  • 如果元素存在属性 type="checkbox" 则返回bool值
  • 否则会返回元素 value 属性的值,或者当 value 属性不存在的时候返回空字符串

element:form_values

如果元素类型为表单,它会以table结构的方式返回表单中每项的值

原型: form_values, reason = element:form_values{values='auto'}

参数:

  • values: 返回值的类型,可以是 'auto''list' 或者 'first' 中的一个

返回值: form_values, reason 元组,如果 form_values 为nil,则表明当前执行函数时发生错误,或者当前元素不是表单类型。 reason 返回错误类型信息, form_values 返回以表单元素名为键值,元素值为键值的table结构

是否异步:

函数的返回值取决于参数 values 的值,它的取值有下列三种

'auto'
返回值将是table或者是一个单一的值,这将取决于表单的类型
  • 如果元素类型为 <select multiple> 返回值将会是一个包含所有选中项的table结构, 如果属性值不存在则返回一个文本内容
  • 如果表单中多个元素都有相同的 name 属性, 则返回一个包含该元素所有值的table结构
  • 否则将会是一个字符串(针对text框或者单选按钮框)或者是一个bool类型(多选框), 或者返回 nil

如果您需要在lua中使用这个返回值,这种返回值类型将会很方便

'list'
返回值将一直是 table 结构(针对lists),即使在表单元素是一个单值的情况下。这一特性也可用于具有未知结构的表单。下面给出些许提示:
  • 如果元素是一个checkbox ,并且有value属性,那么table中将使用这个属性作为键值
  • 如果元素是一个 <select multiple> ,并且有一些还具有相同的名称,那么他们的值将于之前的值连接到一起
  • 在编写通用的表单处理代码时这个类型的返回值将会十分有用,与 'auto' 不同,您不需要考虑多种数据类型
'first'
返回的值都是单一值,即使表单元素可以选择多个值,如果表单元素可以选择多个值,它总会返回被选中的第一个值。

例1:返回下列登录表单的值

<form id="login">
    <input type="text" name="username" value="admin" />
    <input type="password" name="password" value="pass" />
    <input type="checkbox" name="remember" value="yes" checked />
</form>
function main(splash)
    -- ...
    local form = splash:select('#login')
    return assert(form:form_values())
end

-- returned values are
{ username = 'admin', password = 'pass', remember = true }

例2:当 values 的值为 'list'

function main(splash)
    -- ...
    local form = splash:select('#login')
    return assert(form:form_values{values='list'}))
end

-- returned values are
{ username = ['admin'], password = ['pass'], remember = ['checked'] }

例3:当 values 的值为 'first' 的时候返回下列表单的值

<form>
    <input type="text" name="foo[]" value="coffee"/>
    <input type="text" name="foo[]" value="milk"/>
    <input type="text" name="foo[]" value="eggs"/>
    <input type="text" name="baz" value="foo"/>
    <input type="radio" name="choice" value="yes"/>
    <input type="radio" name="choice" value="no" checked/>
    <input type="checkbox" name="check" checked/>

    <select multiple name="selection">
        <option value="1" selected>1</option>
        <option value="2">2</option>
        <option value="3" selected>2</option>
    </select>
</form>
function main(splash)
    -- ...
    local form = splash:select('form')
    return assert(form:form_values(false))
end

-- returned values are
{
    ['foo[]'] = 'coffee',
    baz = 'foo',
    choice = 'no',
    check = false,
    selection = '1'
}

element:fill

利用提供的值来填充表单

原型: ok, reason = element:fill(values)

参数:

  • values: 以表单项名称为键值,表单项的值作为键值的table结构

返回值: ok, reason 元组,如果 ok 为nil表明在函数执行过程中有错误发生, reason 返回错误类型的字符串信息

是否异步:

为了填充表单,您的输入框需要有 name 属性,而且需要事先选中表单

例1:获取表单的值,并修改password项

function main(splash)
    -- ...
    local form = splash:select('#login')
    local values = assert(form:form_values())
    values.password = "l33t"
    assert(form:fill(values))
end

例2:填充复杂的表单:

<form id="signup" action="/signup">
    <input type="text" name="name"/>
    <input type="radio" name="gender" value="male"/>
    <input type="radio" name="gender" value="female"/>

    <select multiple name="hobbies">
        <option value="sport">Sport</option>
        <option value="cars">Cars</option>
        <option value="games">Video Games</option>
    </select>

    <button type="submit">Sign Up</button>
</form>
function main(splash)
  assert(splash:go(splash.args.url))
  assert(splash:wait(0.1))

  local form = splash:select('#signup')
  local values = {
    name = 'user',
    gender = 'female',
    hobbies = {'sport', 'games'},
  }

  assert(form:fill(values))
  assert(form:submit())
  -- ...
end

element:send_keys

向元素发送键盘消息

原型: ok, reason = element:send_keys(keys)

参数:

  • keys:要作为键盘事件发送的多个字符组成的字符串

返回值: ok, reason 元组,如果 ok 为nil 则表明在调用函数期间发生错误, reason 提供错误类型信息

是否异步:

这个方法主要进行这样几个操作

  • 点击元素
  • 向元素发送对应的键盘事件

更多信息,您可以参阅: splash:send_keys

element:send_text

向元素发送键盘消息

原型: ok, reason = element:send_text(text)

参数:

  • text:将要被发送并作为元素输入的字符串

返回值: ok, reason 元组,如果 ok 为nil 则表明在调用函数期间发生错误, reason 提供错误类型信息

是否异步:

这个方法主要进行这样几个操作

  • 点击元素
  • 向元素发送指定的字符串,并作为元素的输入值

更多信息,您可以参阅: splash:send_text

element:submit

提交表单

原型: ok, reason = element:submit()

返回值: ok, reason 元组,如果 ok 为nil 则表明在调用函数期间发生错误(例如您尝试提交的元素不是表单), reason 提供错误类型信息

是否异步:

例:先获取表单的值,然后设置对应的值,最后提交

<form id="login" action="/login">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="checkbox" name="remember" />
    <button type="submit">Submit</button>
</form>
function main(splash)
    -- ...
    local form = splash:select('#login')
    assert(form:fill({ username='admin', password='pass', remember=true }))
    assert(form:submit())
    -- ...
end

element:exists

在DOM中检查对应元素是否存在。如果不存在,某些方法可能会执行失败,并返回对应的标志

原型: exists = element:exists()

返回值: exists 表明当前元素是否存在

是否异步:

注解

不要使用 splash:select(..):exists() 来检查元素是否存在,如果选择器没有选择任何值那么 splash:select 会返回 nil , 此时应该检查返回值是否为 nil

element:exists() 应该用于这样的情况:您之前确定有这么一个元素,但是不清楚后续它是否被从当前的DOM中移出。

下面将列举几种会将元素移出DOM的原因,其中一个理由是它可能被某些JavaScript代码给移除了

例1:元素被js代码移除

function main(splash)
    -- ...
    local element = splash:select('.element')
    assert(splash:runjs('document.write("<body></body>")'))
    assert(splash:wait(0.1))
    local exists = element:exists() -- exists will be `false`
    -- ...
end

另一个原因是元素是通过JavaScript代码创建的但是并没有加入到DOM中

例2:元素未被插入到DOM中

function main(splash)
    -- ...
    local element = splash:select('.element')
    local cloned = element.node:cloneNode() -- the cloned element isn't in DOM
    local exists = cloned:exists() -- exists will be `false`
    -- ...
end

DOM 方法

除了特定的Splash自定义的方法,DOM元素也支持许多常见的DOM HTMLElement类的方法

用法

您只需要在 element 对象上调用, 例如为了确定某个DOM元素是否具有某个特定的属性, 您可以调用 hasAttribute

function main(splash)
    -- ...
    if splash:select('.element'):hasAttribute('foo') then
        -- ...
    end
    -- ...
end

另一个例子:为了确保元素在视口中,您可以使用 scrollIntoViewIfNeeded 方法

function main(splash)
    -- ...
    splash:select('.element'):scrollIntoViewIfNeeded()
    -- ...
end

被支持的DOM方法

继承自 EventTarget 的方法:

  • addEventListener
  • removeEventListener

继承自 HTMLElement 的方法

  • blur
  • click
  • focus

继承自 Element 的方法:

  • getAttribute
  • getAttributeNS
  • getBoundingClientRect
  • getClientRects
  • getElementsByClassName
  • getElementsByTagName
  • getElementsByTagNameNS
  • hasAttribute
  • hasAttributeNS
  • hasAttributes
  • querySelector
  • querySelectorAll
  • releasePointerCapture
  • remove
  • removeAttribute
  • removeAttributeNS
  • requestFullscreen
  • requestPointerLock
  • scrollIntoView
  • scrollIntoViewIfNeeded
  • setAttribute
  • setAttributeNS
  • setPointerCapture

继承自 Node 的方法

  • appendChild
  • cloneNode
  • compareDocumentPosition
  • contains
  • hasChildNodes
  • insertBefore
  • isDefaultNamespace
  • isEqualNode
  • isSameNode
  • lookupPrefix
  • lookupNamespaceURI
  • normalize
  • removeChild
  • replaceChild

这些方法应该作为JS的对应物,在Lua中使用

例如,您可以通过 element:addEventListener(event, listener) 方法来为元素添加对应事件的响应程序

function main(splash)
    -- ...
    local element = splash:select('.element')
    local x, y = 0, 0

    local store_coordinates = function(event)
        x = event.clientX
        y = event.clientY
    end

    element:addEventListener('click', store_coordinates)
    assert(splash:wait(10))
    return x, y
end

属性

element.node

element.node 可以对外暴露DOM元素所有可公开的属性和方法,但是不包括Splash自定义的属性和方法。如果您想要更准确的使用它,请使用 只读的方式。在将来他可能会允许避免可能出现的命名冲突

例如,您需要获取元素的 innerHTML 值,您可以使用 .node.innerHTML

function main(splash)
    -- ...
    return {html=splash:select('.element').node.innerHTML}
end

element.inner_id

元素内部表示的ID。它对于相等的元素实例进行比较可能很有用

例如:

function main(splash)
    -- ...
    local same = element2.inner_id == element2.inner_id
    -- ...
end

DOM 属性

用法

Element 对象也提供了对几乎所有DOM元素属性的支持,例如您可以获取DOM元素的节点名称(p, div, a等等)

function main(splash)
    -- ...
    local tag_name = splash:select('.foo').nodeName
    -- ...
end

大部分元素属性不光是可读,它们也是可写的,例如您可以设置元素 innerHTML 属性的值

function main(splash)
    -- ...
    splash:select('.foo').innerHTML = "hello"
    -- ...
end

被支持的DOM属性

下面将列举被支持的DOM属性(某些是可读写的,某些是只读的)

继承自 HTMLElement 的属性

  • accessKey
  • accessKeyLabel (只读)
  • contentEditable
  • isContentEditable (只读)
  • dataset (只读)
  • dir
  • draggable
  • hidden
  • lang
  • offsetHeight (只读)
  • offsetLeft (只读)
  • offsetParent (只读)
  • offsetTop (只读)
  • spellcheck
  • style - 用一个table表示,table的值可以被修改
  • tabIndex
  • title
  • translate

继承自 Element 的属性

  • attributes (只读) - 一个 table 结构表示的元素的属性
  • classList (只读) - 一个 table 结构表示的元素类名
  • className
  • clientHeight (只读)
  • clientLeft (只读)
  • clientTop (只读)
  • clientWidth (只读)
  • id
  • innerHTML
  • localeName (只读)
  • namespaceURI (只读)
  • nextElementSibling (只读)
  • outerHTML
  • prefix (只读)
  • previousElementSibling (只读)
  • scrollHeight (只读)
  • scrollLeft
  • scrollTop
  • scrollWidth (只读)
  • tabStop
  • tagName (只读)

继承自 Node 的属性

  • baseURI (只读)
  • childNodes (只读)
  • firstChild (只读)
  • lastChild (只读)
  • nextSibling (只读)
  • nodeName (只读)
  • nodeType (只读)
  • nodeValue
  • ownerDocument (只读)
  • parentNode (只读)
  • parentElement (只读)
  • previousSibling (只读)
  • rootNode (只读)
  • textContent

当然您也可以通过属性在特殊的事件上添加指定的事件处理函数.当这个处理函数被调用时,他将会接收到一个 event 的table结构, 这个结构包含所有可用的方法和属性

function main(splash)
    -- ...
    local element = splash:select('.element')

    local x, y = 0, 0

    element.onclick = function(event)
        event:preventDefault()
        x = event.clientX
        y = event.clientY
    end

    assert(splash:wait(10))

    return x, y
end

如果您希望在一个事件上添加多个事件处理程序,请使用 element:addEventListener()