提交 a5d93f2d 编写于 作者: Q qiang

feat(h5): createSelectorQuery

上级 fddf0e35
......@@ -38,7 +38,7 @@
"node": ">=10.0.0"
},
"devDependencies": {
"@dcloudio/types": "^2.2.4",
"@dcloudio/types": "^2.2.5",
"@microsoft/api-extractor": "^7.13.2",
"@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-commonjs": "^17.0.0",
......
export const createSelectorQuery = () => {}
import { ComponentPublicInstance } from 'vue'
import { getCurrentPageVm, getPageIdByVm } from '@dcloudio/uni-core'
import { defineSyncApi } from '../../helpers/api'
import { CanvasContext } from '../context/canvas'
import { EditorContext } from '../context/editor'
import { MapContext } from '../context/createMapContext'
import { VideoContext } from '../context/createVideoContext'
import { requestComponentInfo } from '@dcloudio/uni-platform'
type NodeField = UniApp.NodeField
type ContextType = 'canvas' | 'map' | 'video' | 'editor'
interface NodeInfo extends UniApp.NodeInfo {
contextInfo?: {
id: string
type: ContextType
page: number
}
}
const ContextClasss = {
canvas: CanvasContext,
map: MapContext,
video: VideoContext,
editor: EditorContext,
}
function convertContext(result: NodeInfo | null) {
if (result && result.contextInfo) {
const { id, type, page } = (result as NodeInfo).contextInfo!
const ContextClass = ContextClasss[type]
result.context = new ContextClass(id, page)
delete result.contextInfo
}
}
class NodesRef implements UniApp.NodesRef {
private _selectorQuery: SelectorQuery
private _component: ComponentPublicInstance | null | undefined
private _selector: string
private _single: boolean
constructor(
selectorQuery: SelectorQuery,
component: ComponentPublicInstance | null | undefined,
selector: string,
single: boolean
) {
this._selectorQuery = selectorQuery
this._component = component
this._selector = selector
this._single = single
}
boundingClientRect(callback: (result: NodeInfo) => void) {
this._selectorQuery._push(
this._selector,
this._component,
this._single,
{
id: true,
dataset: true,
rect: true,
size: true,
},
callback
)
return this._selectorQuery
}
fields(fields: NodeField, callback: (result: NodeInfo) => void) {
this._selectorQuery._push(
this._selector,
this._component,
this._single,
fields,
callback
)
return this._selectorQuery
}
scrollOffset(callback: (result: NodeInfo) => void) {
this._selectorQuery._push(
this._selector,
this._component,
this._single,
{
id: true,
dataset: true,
scrollOffset: true,
},
callback
)
return this._selectorQuery
}
context(callback: (result: NodeInfo) => void) {
this._selectorQuery._push(
this._selector,
this._component,
this._single,
{
context: true,
},
callback
)
return this._selectorQuery
}
}
class SelectorQuery implements UniApp.SelectorQuery {
private _page: ComponentPublicInstance
private _queue: Array<{
component: ComponentPublicInstance | undefined | null
selector: string
single: boolean
fields: NodeField
}>
private _component?: ComponentPublicInstance = undefined
private _queueCb: any[]
private _nodesRef?: NodesRef
constructor(page: ComponentPublicInstance) {
this._page = page
this._queue = []
this._queueCb = []
}
exec(callback?: (result: any) => void) {
requestComponentInfo(
this._page,
this._queue,
(res: Array<NodeInfo | null>) => {
const queueCbs = this._queueCb
res.forEach((result, index) => {
if (Array.isArray(result)) {
result.forEach(convertContext)
} else {
convertContext(result)
}
const queueCb = queueCbs[index]
if (typeof queueCb === 'function') {
queueCb.call(this, result)
}
})
// isFn(callback) &&
if (typeof callback === 'function') {
callback.call(this, res)
}
}
)
// TODO
return this._nodesRef as NodesRef
}
in(component?: ComponentPublicInstance) {
this._component = component || undefined
return this
}
select(selector: string) {
return (this._nodesRef = new NodesRef(
this,
this._component,
selector,
true
))
}
selectAll(selector: string) {
return (this._nodesRef = new NodesRef(
this,
this._component,
selector,
false
))
}
selectViewport() {
return (this._nodesRef = new NodesRef(this, null, '', true))
}
_push(
selector: string,
component: ComponentPublicInstance | undefined | null,
single: boolean,
fields: NodeField,
callback: (result: NodeInfo) => void
) {
this._queue.push({
component,
selector,
single,
fields,
})
this._queueCb.push(callback)
}
}
export const createSelectorQuery = <typeof uni.createSelectorQuery>(
defineSyncApi('createSelectorQuery', (context?: any) => {
if (context && !getPageIdByVm(context)) {
context = null
}
return new SelectorQuery(context || getCurrentPageVm()!)
})
)
此差异已折叠。
此差异已折叠。
......@@ -2,6 +2,7 @@ export * from './dom'
export { getBaseSystemInfo } from '../service/api/base/getBaseSystemInfo'
export { operateVideoPlayer } from '../service/api/context/operateVideoPlayer'
export { operateMap } from '../service/api/context/operateMap'
export { requestComponentInfo } from '../service/api/ui/requestComponentInfo'
export {
addIntersectionObserver,
removeIntersectionObserver,
......
import { ComponentPublicInstance } from 'vue'
import { getWindowOffset, getCostomDataset } from '@dcloudio/uni-core'
import { getContextInfo } from '@dcloudio/uni-components'
type NodeField = UniApp.NodeField
interface NodeInfo
extends UniApp.NodeInfo,
Omit<
Partial<Record<keyof CSSStyleDeclaration, any>>,
'top' | 'bottom' | 'left' | 'right' | 'height' | 'width'
> {
contextInfo?: ReturnType<typeof getContextInfo>
}
export interface Request {
component: ComponentPublicInstance | undefined | null
selector: string
single: boolean
fields: NodeField
}
function getRootInfo(fields: NodeField) {
const info: NodeInfo = {}
if (fields.id) {
info.id = ''
}
if (fields.dataset) {
info.dataset = {}
}
if (fields.rect) {
info.left = 0
info.right = 0
info.top = 0
info.bottom = 0
}
if (fields.size) {
info.width = document.documentElement.clientWidth
info.height = document.documentElement.clientHeight
}
if (fields.scrollOffset) {
const documentElement = document.documentElement
const body = document.body
info.scrollLeft = documentElement.scrollLeft || body.scrollLeft || 0
info.scrollTop = documentElement.scrollTop || body.scrollTop || 0
info.scrollHeight = documentElement.scrollHeight || body.scrollHeight || 0
info.scrollWidth = documentElement.scrollWidth || body.scrollWidth || 0
}
return info
}
function getNodeInfo(el: HTMLElement, fields: NodeField): NodeInfo {
const info: NodeInfo = {}
const { top } = getWindowOffset()
if (fields.id) {
info.id = el.id
}
if (fields.dataset) {
info.dataset = getCostomDataset(el)
}
if (fields.rect || fields.size) {
const rect = el.getBoundingClientRect()
if (fields.rect) {
info.left = rect.left
info.right = rect.right
info.top = rect.top - top
info.bottom = rect.bottom - top
}
if (fields.size) {
info.width = rect.width
info.height = rect.height
}
}
// TODO 组件 props
if (Array.isArray(fields.properties)) {
fields.properties.forEach((prop) => {
prop = prop.replace(/-([a-z])/g, function (e, t) {
return t.toUpperCase()
})
// props
})
}
if (fields.scrollOffset) {
if (el.tagName === 'UNI-SCROLL-VIEW') {
const scroll = el.children[0].children[0]
info.scrollLeft = scroll.scrollLeft
info.scrollTop = scroll.scrollTop
info.scrollHeight = scroll.scrollHeight
info.scrollWidth = scroll.scrollWidth
} else {
info.scrollLeft = 0
info.scrollTop = 0
info.scrollHeight = 0
info.scrollWidth = 0
}
}
if (Array.isArray(fields.computedStyle)) {
const sytle = getComputedStyle(el)
fields.computedStyle.forEach((name) => {
info[name as keyof CSSStyleDeclaration] =
sytle[name as keyof CSSStyleDeclaration]
})
}
if (fields.context) {
info.contextInfo = getContextInfo(el)
}
return info
}
export function findElm(
component: ComponentPublicInstance | undefined | null,
pageVm: ComponentPublicInstance
): HTMLElement {
return component ? component.$el : pageVm.$el
}
function getNodesInfo(
pageVm: ComponentPublicInstance,
component: ComponentPublicInstance | undefined | null,
selector: string,
single: boolean,
fields: NodeField
): NodeInfo | NodeInfo[] | null {
const parentElement = findElm(component, pageVm).parentElement
if (!parentElement) {
return single ? null : []
}
if (single) {
const node = parentElement.querySelector(selector) as HTMLElement
if (node) {
return getNodeInfo(node, fields)
}
return null
} else {
let infos: NodeInfo[] = []
const nodeList = parentElement.querySelectorAll(selector)
if (nodeList && nodeList.length) {
;[].forEach.call(nodeList, (node) => {
infos.push(getNodeInfo(node, fields))
})
}
return infos
}
}
export function requestComponentInfo(
page: ComponentPublicInstance,
reqs: Array<Request>,
callback: (result: Array<NodeInfo | null>) => void
) {
const result: Array<NodeInfo | null> = []
reqs.forEach(({ component, selector, single, fields }) => {
if (component === null) {
result.push(getRootInfo(fields))
} else {
result.push(getNodesInfo(page, component, selector, single, fields))
}
})
callback(result)
}
export function getRealPath() {}
export function operateVideoPlayer() {}
export function operateMap() {}
export function requestComponentInfo() {}
export function addIntersectionObserver() {}
export function removeIntersectionObserver() {}
export function saveImage() {}
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册