forked from didi/mpx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
15d22fd
commit bc4299d
Showing
7 changed files
with
372 additions
and
296 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
packages/api-proxy/src/platform/api/create-selector-query/index.android.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './index.ios' |
9 changes: 9 additions & 0 deletions
9
packages/api-proxy/src/platform/api/create-selector-query/index.ios.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import SelectorQuery from './rnSelectQuery' | ||
|
||
function createSelectorQuery () { | ||
return new SelectorQuery() | ||
} | ||
|
||
export { | ||
createSelectorQuery | ||
} |
262 changes: 262 additions & 0 deletions
262
packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
import { | ||
noop, | ||
isBoolean, | ||
dash2hump, | ||
collectDataset, | ||
hump2dash, | ||
isArray | ||
} from '@mpxjs/utils' | ||
import { StyleSheet } from 'react-native' | ||
|
||
const flushRefFns = (nodeInstances, fns, single) => { | ||
// wx的数据格式:对于具体方法接受到的回调传参,如果获取的 nodeRef 只有一个,那么只需要返回一条数据而不是数组,但是 exec 里面统一都是数组 | ||
const mountedNodeInstance = nodeInstances | ||
.map((instance) => instance.getNodeInstance()) | ||
.filter(({ nodeRef }) => nodeRef.current) // 如果有 nodeRef,表明目前组件处于挂载中 | ||
if (mountedNodeInstance.length) { | ||
return Promise.all( | ||
mountedNodeInstance.map((instance) => flushFns(instance, fns)) | ||
).then((result = []) => (single ? result[0] : result)) | ||
} else { | ||
return Promise.resolve(single ? null : []) | ||
} | ||
} | ||
|
||
const flushFns = (nodeInstance, fns) => { | ||
return Promise.all(fns.map((fn) => fn(nodeInstance))).then((res) => { | ||
return res.reduce((preVal, curVal) => { | ||
return Object.assign(preVal, curVal) | ||
}, {}) | ||
}) | ||
} | ||
|
||
const wrapFn = (fn) => { | ||
return (nodeRef) => { | ||
return new Promise((resolve) => { | ||
fn(nodeRef, resolve) | ||
}) | ||
} | ||
} | ||
|
||
const getMeasureProps = (measureProps = []) => { | ||
return wrapFn((nodeInstance, resolve) => { | ||
const nodeRef = nodeInstance.nodeRef.current | ||
setTimeout(() => { | ||
nodeRef.measure(function (x, y, width, height, pageX, pageY) { | ||
const rectAndSize = { | ||
width, | ||
height, | ||
left: pageX, | ||
top: pageY, | ||
right: pageX + width, | ||
bottom: pageY + height | ||
} | ||
const result = measureProps.reduce((preVal, key) => { | ||
return Object.assign(preVal, { [key]: rectAndSize[key] || 0 }) | ||
}, {}) | ||
resolve(result) | ||
}) | ||
}, 30) // 延迟,等待组件在rn视图上真正渲染出来 | ||
}) | ||
} | ||
|
||
const getDataset = (props) => { | ||
return wrapFn((nodeRef, resolve) => { | ||
props = nodeRef.props.current | ||
resolve({ | ||
dataset: collectDataset(props) | ||
}) | ||
}) | ||
} | ||
|
||
const getPlainProps = (config) => { | ||
return wrapFn((nodeRef, resolve) => { | ||
const res = {} | ||
const props = nodeRef.props.current | ||
config.forEach((key) => { | ||
// props 属性默认不转驼峰,用户写什么格式不会变化,取值做兼容 | ||
res[key] = props[key] || props[hump2dash(key)] || '' | ||
}) | ||
resolve(res) | ||
}) | ||
} | ||
|
||
const getComputedStyle = (config = []) => { | ||
return wrapFn((nodeRef, resolve) => { | ||
config = new Set(config) | ||
const res = {} | ||
const styles = nodeRef.props.current.style || [] | ||
const defaultStyle = nodeRef.instance.defaultStyle || {} | ||
const computedStyle = StyleSheet.flatten([defaultStyle, ...styles]) | ||
config.forEach((key) => { | ||
const humpKey = dash2hump(key) | ||
// 取 style 的 key 是根据传入的 key 来设置,传什么设置什么 key,只不过取值需要做兼容 | ||
res[key] = computedStyle[key] || computedStyle[humpKey] || '' | ||
}) | ||
|
||
resolve(res) | ||
}) | ||
} | ||
|
||
const getInstanceConfig = (config) => { | ||
return wrapFn((nodeRef, resolve) => { | ||
const instance = nodeRef.instance | ||
resolve({ [config]: instance[config] || {} }) | ||
}) | ||
} | ||
|
||
const defaultScrollOffset = { | ||
scrollLeft: 0, | ||
scrollTop: 0, | ||
scrollHeight: 0, | ||
scrollWidth: 0 | ||
} | ||
|
||
const getScrollOffset = () => { | ||
return wrapFn((nodeRef, resolve) => { | ||
const instance = nodeRef.instance | ||
resolve( | ||
(instance.scrollOffset && instance.scrollOffset.current) || | ||
defaultScrollOffset | ||
) | ||
}) | ||
} | ||
|
||
const RECT = ['left', 'top', 'right', 'bottom'] | ||
const SIZE = ['width', 'height'] | ||
|
||
class NodeRef { | ||
constructor (nodeRefs = [], selectorQuery, single) { | ||
if (!isArray(nodeRefs)) { | ||
nodeRefs = [nodeRefs] | ||
} | ||
this.nodeRefs = nodeRefs | ||
this.selectorQuery = selectorQuery | ||
this.single = single | ||
} | ||
|
||
fields (config, cb = noop) { | ||
const plainProps = [] | ||
const measureProps = [] | ||
const computedStyle = [] | ||
const fns = [] | ||
|
||
for (const key in config) { | ||
const value = config[key] | ||
if (Array.isArray(value) && value.length) { | ||
if (key === 'properties') { | ||
// wx 最终输出的 properties 字段都会转化为驼峰,所以在这里提前处理为最终的字段格式 | ||
plainProps.push(...value.map((v) => dash2hump(v))) | ||
} else if (key === 'computedStyle') { | ||
const _computedStyle = config.computedStyle | ||
for (let i = _computedStyle.length - 1; i >= 0; i--) { | ||
const style = _computedStyle[i] | ||
if (RECT.includes(style) || SIZE.includes(style)) { | ||
measureProps.push(style) | ||
_computedStyle.splice(i, 1) | ||
} | ||
} | ||
if (_computedStyle.length) { | ||
computedStyle.push(..._computedStyle) | ||
} | ||
} | ||
} else if (isBoolean(value) && value) { | ||
switch (key) { | ||
case 'rect': | ||
measureProps.push(...RECT) | ||
break | ||
case 'size': | ||
measureProps.push(...SIZE) | ||
break | ||
case 'scrollOffset': | ||
fns.push(getScrollOffset()) | ||
break | ||
case 'dataset': | ||
fns.push(getDataset()) | ||
break | ||
case 'node': | ||
case 'context': | ||
case 'ref': | ||
fns.push(getInstanceConfig(key)) | ||
break | ||
default: | ||
plainProps.push(key) | ||
break | ||
} | ||
} | ||
} | ||
|
||
if (plainProps.length) { | ||
fns.push(getPlainProps(plainProps)) | ||
} | ||
if (measureProps.length) { | ||
const nodeInstance = | ||
this.nodeRefs[0] && this.nodeRefs[0].getNodeInstance() | ||
const hasMeasureFn = | ||
nodeInstance && | ||
nodeInstance.nodeRef.current && | ||
nodeInstance.nodeRef.current.measure | ||
if (hasMeasureFn) { | ||
fns.push(getMeasureProps(measureProps)) | ||
} else { | ||
computedStyle.push(...measureProps) | ||
} | ||
} | ||
if (computedStyle.length) { | ||
fns.push(getComputedStyle(computedStyle)) | ||
} | ||
|
||
const runCb = () => { | ||
return flushRefFns(this.nodeRefs, fns, this.single).then((result) => { | ||
cb(result) | ||
return result | ||
}) | ||
} | ||
|
||
this.selectorQuery._queueCb.push(runCb) | ||
|
||
return this.selectorQuery | ||
} | ||
|
||
boundingClientRect (cb = noop) { | ||
const config = { | ||
id: true, | ||
dataset: true, | ||
rect: true, | ||
size: true | ||
} | ||
return this.fields(config, cb) | ||
} | ||
|
||
context (cb = noop) { | ||
const config = { | ||
context: true | ||
} | ||
return this.fields(config, cb) | ||
} | ||
|
||
node (cb = noop) { | ||
const config = { | ||
node: true | ||
} | ||
return this.fields(config, cb) | ||
} | ||
|
||
ref (cb = noop) { | ||
const config = { | ||
ref: true | ||
} | ||
return this.fields(config, cb) | ||
} | ||
|
||
scrollOffset (cb = noop) { | ||
const config = { | ||
id: true, | ||
dataset: true, | ||
scrollOffset: true | ||
} | ||
return this.fields(config, cb) | ||
} | ||
} | ||
|
||
export default NodeRef |
39 changes: 39 additions & 0 deletions
39
packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import NodeRef from './rnNodesRef' | ||
import { warn, noop } from '@mpxjs/utils' | ||
|
||
export default class SelectorQuery { | ||
constructor () { | ||
this._component = null | ||
this._queue = [] | ||
this._queueCb = [] | ||
} | ||
|
||
// wx 目前 exec 方法返回 undefined,文档上标注的是 NodeRef 类型,按实际的返回值来实现 | ||
exec (cb = noop) { | ||
Promise.all(this._queueCb.map((cb) => cb())).then((res) => cb(res)) | ||
} | ||
|
||
in (component) { | ||
this._component = component | ||
return this | ||
} | ||
|
||
// todo 元素选择规则:只支持单 selector 选择器:#id,.class | ||
select (selector, all) { | ||
if (!this._component) { | ||
warn('Please use SelectorQuery.in method to set context') | ||
} | ||
const refs = | ||
this._component && this._component.__selectRef(selector, 'node', all) | ||
return new NodeRef(refs, this, !all) | ||
} | ||
|
||
selectAll (selector) { | ||
return this.select(selector, true) | ||
} | ||
|
||
selectViewport () { | ||
// todo rn 这块实现不了 | ||
return this.select('') | ||
} | ||
} |
Oops, something went wrong.