saven
Version:
165 lines (144 loc) • 4.17 kB
JavaScript
/**
* WXML节点信息API
* @return {Object} SelectorQuery 对象实例
*/
function queryBat (queue, cb) {
const res = []
queue.forEach(item => {
const { selector, single, fields } = item
let el = null
if (single) {
el = document.querySelector(selector)
res.push(filter(fields, el, selector))
} else {
el = Array.from(document.querySelectorAll(selector))
res.push(el.map(dom => filter(fields, dom)))
}
})
cb(res)
}
function filter (fields, dom, selector) {
if (!dom) return null
const { id, dataset, rect, size, scrollOffset, properties = [], computedStyle = [] } = fields
const { left, right, top, bottom, width, height } = dom.getBoundingClientRect()
const isViewport = selector === 'html'
const res = {}
if (id) res.id = dom.id
if (dataset) res.dataset = Object.assign({}, dom.dataset)
if (rect) {
if (!isViewport) {
res.left = left
res.right = right
res.top = top
res.bottom = bottom
} else {
res.left = res.right = res.top = res.bottom = 0
}
}
if (size) {
if (!isViewport) {
res.width = width
res.height = height
} else {
res.width = dom.clientWidth
res.height = dom.clientHeight
}
}
if (scrollOffset) {
res.scrollLeft = dom.scrollLeft
res.scrollTop = dom.scrollTop
}
if (properties.length) {
properties.forEach(prop => {
const attr = dom.getAttribute(prop)
if (attr) res[prop] = attr
})
}
if (computedStyle.length) {
const styles = window.getComputedStyle(dom)
computedStyle.forEach(key => {
const value = styles.getPropertyValue(key)
if (value) res[key] = value
})
}
return res
}
class Query {
constructor () {
this._defaultWebviewId = null
this._webviewId = null
this._queue = []
this._queueCb = []
this._component = null
}
in (component) {
this._component = component
return this
}
select (selector) {
// 小程序里跨自定义组件的后代选择器 '>>>' 在 h5 替换为普通后代选择器 '>'
if (typeof selector === 'string') selector = selector.replace('>>>', '>')
return new NodesRef(selector, this, true)
}
selectAll (selector) {
// 小程序里跨自定义组件的后代选择器 '>>>' 在 h5 替换为普通后代选择器 '>'
if (typeof selector === 'string') selector = selector.replace('>>>', '>')
return new NodesRef(selector, this, false)
}
selectViewport () {
return new NodesRef('html', this, true)
}
exec (cb) {
queryBat(this._queue, res => {
const _queueCb = this._queueCb
res.forEach((item, index) => {
typeof _queueCb[index] === 'function' && _queueCb[index].call(this, item)
})
typeof cb === 'function' && cb.call(this, res)
})
}
_push (selector, component, single, fields, callback = null) {
this._queue.push({
component,
selector,
single,
fields
})
this._queueCb.push(callback)
}
}
class NodesRef {
constructor (selector, querySelectorQuery, single) {
this._component = querySelectorQuery._component
this._selector = selector
this._selectorQuery = querySelectorQuery
this._single = single
}
boundingClientRect (cb) {
const { _selector, _component, _single, _selectorQuery } = this
_selectorQuery._push(_selector, _component, _single, {id: !0, dataset: !0, rect: !0, size: !0}, cb)
return _selectorQuery
}
scrollOffset (cb) {
const { _selector, _component, _single, _selectorQuery } = this
_selectorQuery._push(_selector, _component, _single, {id: !0, dataset: !0, scrollOffset: !0}, cb)
return _selectorQuery
}
fields (fields, cb) {
const { _selector, _component, _single, _selectorQuery } = this
const { id, dataset, rect, size, scrollOffset, properties = [], computedStyle = [] } = fields
_selectorQuery._push(_selector, _component, _single, {
id,
dataset,
rect,
size,
scrollOffset,
properties,
computedStyle
}, cb)
return _selectorQuery
}
}
export function createSelectorQuery () {
return new Query()
}