From bc4299d3184f8e98dd02813ec807afd61fc508fb Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Fri, 16 Aug 2024 12:01:19 +0800 Subject: [PATCH 01/10] [feat]react-createSelector --- .../create-selector-query/index.android.js | 1 + .../api/create-selector-query/index.ios.js | 9 + .../api/create-selector-query/rnNodesRef.js | 262 ++++++++++++++ .../create-selector-query/rnSelectQuery.js | 39 +++ .../platform/builtInMixins/refsMixin.ios.js | 323 ++---------------- .../patch/react/getDefaultOptions.ios.js | 11 +- .../lib/template-compiler/compiler.js | 23 +- 7 files changed, 372 insertions(+), 296 deletions(-) create mode 100644 packages/api-proxy/src/platform/api/create-selector-query/index.android.js create mode 100644 packages/api-proxy/src/platform/api/create-selector-query/index.ios.js create mode 100644 packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js create mode 100644 packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js diff --git a/packages/api-proxy/src/platform/api/create-selector-query/index.android.js b/packages/api-proxy/src/platform/api/create-selector-query/index.android.js new file mode 100644 index 0000000000..25aabdbcf9 --- /dev/null +++ b/packages/api-proxy/src/platform/api/create-selector-query/index.android.js @@ -0,0 +1 @@ +export * from './index.ios' diff --git a/packages/api-proxy/src/platform/api/create-selector-query/index.ios.js b/packages/api-proxy/src/platform/api/create-selector-query/index.ios.js new file mode 100644 index 0000000000..b587e308be --- /dev/null +++ b/packages/api-proxy/src/platform/api/create-selector-query/index.ios.js @@ -0,0 +1,9 @@ +import SelectorQuery from './rnSelectQuery' + +function createSelectorQuery () { + return new SelectorQuery() +} + +export { + createSelectorQuery +} diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js b/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js new file mode 100644 index 0000000000..87977e03fe --- /dev/null +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnNodesRef.js @@ -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 diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js new file mode 100644 index 0000000000..1a54f51cc6 --- /dev/null +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js @@ -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('') + } +} diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 3af4d7f7b4..8eefb651be 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -1,303 +1,37 @@ import { BEFORECREATE } from '../../core/innerLifecycle' -import { noop, isBoolean, dash2hump, warn, collectDataset, hump2dash } from '@mpxjs/utils' -import { StyleSheet } from 'react-native' - -const _createSelectorQuery = (runCb) => { - return { - exec: (cb = noop) => { - runCb().then(res => { - cb(res) - }) - }, - in: () => { - warn('please use wx:ref to get NodesRef') - }, - select: () => { - warn('please use wx:ref to get NodesRef') - }, - selectAll: () => { - warn('please use wx:ref to get NodesRef') - }, - selectViewport: () => { // 有点难实现,dimension 目前没有暴露相关 api - warn('please use wx:ref') - } - } -} - -const flushRefFns = (nodeInstances, fns) => { - const mountedNodeInstance = nodeInstances - .map(instance => instance.getNodeInstance()) - .filter(({ nodeRef }) => nodeRef.current) // 如果有 nodeRef,表明目前组件处于挂载中 - if (mountedNodeInstance.length) { - return Promise.all(mountedNodeInstance.map(instance => flushFns(instance, fns))) - } else { - return Promise.resolve(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 getScrollOffsetFallback = (cb) => { -// const res = { -// scrollLeft: 0, -// scrollTop: 0, -// scrollHeight: 0, -// scrollWidth: 0 -// } -// cb(res) -// } - -const RECT = ['left', 'top', 'right', 'bottom'] -const SIZE = ['width', 'height'] - -function _createNodesRef (nodeRefs = []) { - const 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 = nodeRefs[0] && 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(nodeRefs, fns).then((result) => { - // wx的数据格式:对于具体方法接受到的回调传参,如果获取的 nodeRef 只有一个,那么只需要返回一条数据而不是数组,但是 exec 里面统一都是数组 - cb(result && result.length === 1 ? result[0] : result) - return result - }) - } - - return _createSelectorQuery(runCb) - } - - const boundingClientRect = (cb = noop) => { - const config = { - id: true, - dataset: true, - rect: true, - size: true - } - return fields(config, cb) - } - - const context = (cb = noop) => { - const config = { - context: true - } - return fields(config, cb) - } - - const node = (cb = noop) => { - const config = { - node: true - } - return fields(config, cb) - } - - const ref = (cb = noop) => { - const config = { - ref: true - } - return fields(config, cb) - } - - const scrollOffset = (cb = noop) => { - const config = { - id: true, - dataset: true, - scrollOffset: true - } - return fields(config, cb) - } - - return { - fields, - boundingClientRect, - context, - node, - ref, - scrollOffset - } -} +import { createSelectorQuery } from '@mpxjs/api-proxy' export default function getRefsMixin () { return { [BEFORECREATE] () { this.__refs = {} this.$refs = {} + this.__selectorMap = {} this.__getRefs() }, methods: { __getRefs () { const refs = this.__getRefsData() || [] const target = this - refs.forEach(({ key, type, all }) => { - Object.defineProperty(this.$refs, key, { - enumerable: true, - configurable: true, - get () { - const refs = target.__refs[key] || [] - if (type === 'component') { - return all ? refs : refs[0] - } else { - return _createNodesRef(refs) - } - } + refs.forEach(({ key, type, all, refKey, selector }) => { + selector.forEach(item => { + this.__selectorMap[item] = this.__selectorMap[item] || [] + this.__selectorMap[item].push({ type, key }) }) + if (refKey) { + Object.defineProperty(this.$refs, refKey, { + enumerable: true, + configurable: true, + get () { + const refs = target.__refs[key] || [] + if (type === 'component') { + return all ? refs : refs[0] + } else { + return createSelectorQuery().in(target).select(refKey, all) + } + } + }) + } }) }, __getRefVal (key) { @@ -305,6 +39,23 @@ export default function getRefsMixin () { this.__refs[key] = [] } return (instance) => instance && this.__refs[key].push(instance) + }, + __selectRef (selector, refType, all = false) { + const selectorMap = this.__selectorMap[selector] || [] + if (all) { + const refs = [] + selectorMap.forEach(({ type, key }) => { + if (type === refType) { + const _refs = this.__refs[key] || [] + refs.push(..._refs) + } + }) + return refs + } else { + const { key } = selectorMap.find(({ type }) => type === refType) || {} + const _refs = this.__refs[key] || [] + return _refs[0] + } } } } diff --git a/packages/core/src/platform/patch/react/getDefaultOptions.ios.js b/packages/core/src/platform/patch/react/getDefaultOptions.ios.js index f11d7cfab9..4121254701 100644 --- a/packages/core/src/platform/patch/react/getDefaultOptions.ios.js +++ b/packages/core/src/platform/patch/react/getDefaultOptions.ios.js @@ -6,6 +6,7 @@ import MpxProxy from '../../../core/proxy' import { BEFOREUPDATE, UPDATED, ONLOAD } from '../../../core/innerLifecycle' import mergeOptions from '../../../core/mergeOptions' import { queueJob } from '../../../observer/scheduler' +import { createSelectorQuery } from '@mpxjs/api-proxy' function getRootProps (props) { const rootProps = {} @@ -134,14 +135,14 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps handler.call(this, eventObj) } }, - selectComponent () { - error('selectComponent is not supported in react native, please use ref instead') + selectComponent (selector) { + return this.__selectRef(selector, 'component') }, - selectAllComponents () { - error('selectAllComponents is not supported in react native, please use ref instead') + selectAllComponents (selector) { + return this.__selectRef(selector, 'component', true) }, createSelectorQuery () { - error('createSelectorQuery is not supported in react native, please use ref instead') + return createSelectorQuery().in(this) }, createIntersectionObserver () { error('createIntersectionObserver is not supported in react native, please use ref instead') diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index aa42311d77..fcf0c27afc 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1655,23 +1655,36 @@ function processFor (el) { } function processRefReact (el, meta) { - const val = getAndRemoveAttr(el, config[mode].directive.ref).val + const { val, has } = getAndRemoveAttr(el, config[mode].directive.ref) + // rn中只有内建组件能被作为node ref处理 const type = el.isBuiltIn ? 'node' : 'component' - if (val) { + if (val || has) { if (!meta.refs) { meta.refs = [] } const all = !!forScopes.length + const key = `ref_rn_${++refId}` + const classString = getAndRemoveAttr(el, 'class', false).val + const idString = getAndRemoveAttr(el, 'id', false).val + const ids = idString ? idString.split(' ').map(s => `#${s}`) : [] + const classNames = classString ? classString.split(' ').map(s => `.${s}`) : [] + const selector = [...ids, ...classNames] + if (val) { + selector.push(val) + } + meta.refs.push({ - key: val, + key, all, - type + type, + refKey: val, + selector }) addAttrs(el, [{ name: 'ref', - value: `{{ this.__getRefVal('${val}') }}` + value: `{{ this.__getRefVal('${key}') }}` }]) } } From 3633e2040b7f1319cc8ac2b12d5454a486e6abeb Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Mon, 19 Aug 2024 18:53:22 +0800 Subject: [PATCH 02/10] [optimize]multi selector --- .../api/create-selector-query/rnSelectQuery.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js index 1a54f51cc6..641bd5a9de 100644 --- a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js @@ -18,11 +18,21 @@ export default class SelectorQuery { return this } + /** + * 目前支持的 selector + * + * 1. #id + * 2. .class + * 3. .class1.class2 + */ // todo 元素选择规则:只支持单 selector 选择器:#id,.class - select (selector, all) { + select (selector = '', all) { + // todo class/id if (!this._component) { warn('Please use SelectorQuery.in method to set context') } + const splitedSelector = selector.match(/(#|\.)\w+/g) + // todo match 工作 const refs = this._component && this._component.__selectRef(selector, 'node', all) return new NodeRef(refs, this, !all) From 9fa1d585fd65cb11d8ffd10dc3fa500a534b76b3 Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Tue, 20 Aug 2024 20:31:31 +0800 Subject: [PATCH 03/10] [feat]support mulit selector --- .../create-selector-query/rnSelectQuery.js | 24 ++++++++++-------- .../platform/builtInMixins/refsMixin.ios.js | 25 +++++++++++-------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js index 641bd5a9de..f4ac3c2250 100644 --- a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js @@ -20,22 +20,24 @@ export default class SelectorQuery { /** * 目前支持的 selector - * - * 1. #id - * 2. .class - * 3. .class1.class2 + * + * 1. id 选择器:#the-id + * 2. class 选择器(可以连续指定多个):.a-class.another-class */ - // todo 元素选择规则:只支持单 selector 选择器:#id,.class select (selector = '', all) { - // todo class/id if (!this._component) { warn('Please use SelectorQuery.in method to set context') } - const splitedSelector = selector.match(/(#|\.)\w+/g) - // todo match 工作 - const refs = - this._component && this._component.__selectRef(selector, 'node', all) - return new NodeRef(refs, this, !all) + const splitedSelector = selector.match(/(#|\.)\w+/g) || [] + const refsArr = splitedSelector.map(selector => this._component && this._component.__selectRef(selector, 'node', true)) + const refs = refsArr.reduce((preRefs, curRefs, curIndex) => { + if (curIndex === 0) return curRefs + return preRefs.filter(p => { + const preNodeRef = p.getNodeInstance && p.getNodeInstance().nodeRef + return curRefs.find(r => r.getNodeInstance && r.getNodeInstance().nodeRef === preNodeRef) + }) + }, []) + return new NodeRef(all ? refs : refs[0], this, !all) } selectAll (selector) { diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 8eefb651be..7f87269f38 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -41,21 +41,26 @@ export default function getRefsMixin () { return (instance) => instance && this.__refs[key].push(instance) }, __selectRef (selector, refType, all = false) { - const selectorMap = this.__selectorMap[selector] || [] - if (all) { - const refs = [] + const splitedSelector = selector.match(/(#|\.)\w+/g) || [] + const refsArr = splitedSelector.map(selector => { + const selectorMap = this.__selectorMap[selector] || [] + const res = [] selectorMap.forEach(({ type, key }) => { if (type === refType) { const _refs = this.__refs[key] || [] - refs.push(..._refs) + res.push(..._refs) } }) - return refs - } else { - const { key } = selectorMap.find(({ type }) => type === refType) || {} - const _refs = this.__refs[key] || [] - return _refs[0] - } + return res + }) + + const refs = refsArr.reduce((preRefs, curRefs, curIndex) => { + if (curIndex === 0) return curRefs + curRefs = new Set(curRefs) + return preRefs.filter(p => curRefs.has(p)) + }, []) + + return all ? refs : refs[0] } } } From e5c3bbe073b44879d5d15523f485b1d75c80fa4d Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Wed, 21 Aug 2024 16:34:39 +0800 Subject: [PATCH 04/10] [feat]support dynamic id & class --- .../builtInMixins/classHelperMixin.android.js | 3 ++ .../builtInMixins/classHelperMixin.ios.js | 11 ++++++ .../builtInMixins/classHelperMixin.js | 3 ++ .../core/src/platform/builtInMixins/index.js | 4 ++- .../platform/builtInMixins/refsMixin.ios.js | 29 ++++++++++----- .../lib/template-compiler/compiler.js | 35 +++++++++++++------ 6 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.android.js create mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.ios.js create mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.js diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.android.js b/packages/core/src/platform/builtInMixins/classHelperMixin.android.js new file mode 100644 index 0000000000..6adad8d248 --- /dev/null +++ b/packages/core/src/platform/builtInMixins/classHelperMixin.android.js @@ -0,0 +1,3 @@ +export default function classHelperMixin () { + return {} +} diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js b/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js new file mode 100644 index 0000000000..ed322fe150 --- /dev/null +++ b/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js @@ -0,0 +1,11 @@ +import stringify from '@mpxjs/webpack-plugin/lib/runtime/stringify.wxs' + +export default function classHelperMixin () { + return { + methods: { + __getClass (...args) { + return stringify.stringifyClass(...args) + } + } + } +} diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.js b/packages/core/src/platform/builtInMixins/classHelperMixin.js new file mode 100644 index 0000000000..6adad8d248 --- /dev/null +++ b/packages/core/src/platform/builtInMixins/classHelperMixin.js @@ -0,0 +1,3 @@ +export default function classHelperMixin () { + return {} +} diff --git a/packages/core/src/platform/builtInMixins/index.js b/packages/core/src/platform/builtInMixins/index.js index 2e6aa6d714..1906f2d94b 100644 --- a/packages/core/src/platform/builtInMixins/index.js +++ b/packages/core/src/platform/builtInMixins/index.js @@ -12,6 +12,7 @@ import getTabBarMixin from './getTabBarMixin' import pageRouteMixin from './pageRouteMixin' import { dynamicRefsMixin, dynamicRenderHelperMixin, dynamicSlotMixin } from '../../dynamic/dynamicRenderMixin.empty' import styleHelperMixin from './styleHelperMixin' +import classHelperMixin from './classHelperMixin' import directiveHelperMixin from './directiveHelperMixin' export default function getBuiltInMixins (options, type) { @@ -22,7 +23,8 @@ export default function getBuiltInMixins (options, type) { directiveHelperMixin(), styleHelperMixin(type), refsMixin(), - i18nMixin() + i18nMixin(), + classHelperMixin() ] } else if (__mpx_mode__ === 'web') { bulitInMixins = [ diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 7f87269f38..a8980e3029 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -1,9 +1,10 @@ -import { BEFORECREATE } from '../../core/innerLifecycle' +import { CREATED } from '../../core/innerLifecycle' import { createSelectorQuery } from '@mpxjs/api-proxy' +import { watch } from '../../observer/watch' export default function getRefsMixin () { return { - [BEFORECREATE] () { + [CREATED] () { this.__refs = {} this.$refs = {} this.__selectorMap = {} @@ -13,12 +14,24 @@ export default function getRefsMixin () { __getRefs () { const refs = this.__getRefsData() || [] const target = this - refs.forEach(({ key, type, all, refKey, selector }) => { - selector.forEach(item => { - this.__selectorMap[item] = this.__selectorMap[item] || [] - this.__selectorMap[item].push({ type, key }) - }) + refs.forEach(({ key, type, all, refKey, computedSelectorKeys }) => { + if (computedSelectorKeys.length) { + computedSelectorKeys.forEach((item) => { + const computedKey = item.key + const prefix = item.prefix + watch(() => this[computedKey], (selectors = '') => { + selectors.trim().split(/\s+/).forEach(item => { + const selector = prefix + item + this.__selectorMap[selector] = this.__selectorMap[selector] || [] + this.__selectorMap[selector].push({ type, key }) + }) + }, { immediate: true }) + }) + } if (refKey) { + this.__selectorMap[refKey] = this.__selectorMap[refKey] || [] + this.__selectorMap[refKey].push({ type, key }) + Object.defineProperty(this.$refs, refKey, { enumerable: true, configurable: true, @@ -41,7 +54,7 @@ export default function getRefsMixin () { return (instance) => instance && this.__refs[key].push(instance) }, __selectRef (selector, refType, all = false) { - const splitedSelector = selector.match(/(#|\.)\w+/g) || [] + const splitedSelector = selector.match(/(#|\.)?\w+/g) || [] const refsArr = splitedSelector.map(selector => { const selectorMap = this.__selectorMap[selector] || [] const res = [] diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index fcf0c27afc..2271209a8e 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1665,22 +1665,37 @@ function processRefReact (el, meta) { } const all = !!forScopes.length const key = `ref_rn_${++refId}` - const classString = getAndRemoveAttr(el, 'class', false).val const idString = getAndRemoveAttr(el, 'id', false).val - const ids = idString ? idString.split(' ').map(s => `#${s}`) : [] - const classNames = classString ? classString.split(' ').map(s => `.${s}`) : [] - const selector = [...ids, ...classNames] - if (val) { - selector.push(val) - } + const classString = getAndRemoveAttr(el, 'class', false).val + const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val - meta.refs.push({ + const staticId = parseMustacheWithContext(idString).result + const staticClass = parseMustacheWithContext(classString).result + const dynamicClass = parseMustacheWithContext(dynamicClassString).result + + const refConf = { key, all, type, refKey: val, - selector - }) + computedSelectorKeys: [] + } + + meta.computed = meta.computed || [] + + if (idString) { + const computedIdKey = `ref_computed_id_${++refId}` + refConf.computedSelectorKeys.push({ key: computedIdKey, prefix: '#' }) + meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) + } + + if (classString || dynamicClassString) { + const computedClassKey = `ref_computed_class_${++refId}` + refConf.computedSelectorKeys.push({ key: computedClassKey, prefix: '.' }) + meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`) + } + + meta.refs.push(refConf) addAttrs(el, [{ name: 'ref', From 61dfaab6ef28023177d0438fb99d83d1a861a593 Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Thu, 22 Aug 2024 18:16:54 +0800 Subject: [PATCH 05/10] =?UTF-8?q?[update]=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builtInMixins/classHelperMixin.android.js | 3 -- .../builtInMixins/classHelperMixin.ios.js | 11 ----- .../builtInMixins/classHelperMixin.js | 3 -- .../core/src/platform/builtInMixins/index.js | 4 +- .../platform/builtInMixins/refsMixin.ios.js | 1 + .../builtInMixins/styleHelperMixin.ios.js | 3 ++ .../lib/template-compiler/compiler.js | 44 ++++++++++--------- 7 files changed, 29 insertions(+), 40 deletions(-) delete mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.android.js delete mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.ios.js delete mode 100644 packages/core/src/platform/builtInMixins/classHelperMixin.js diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.android.js b/packages/core/src/platform/builtInMixins/classHelperMixin.android.js deleted file mode 100644 index 6adad8d248..0000000000 --- a/packages/core/src/platform/builtInMixins/classHelperMixin.android.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function classHelperMixin () { - return {} -} diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js b/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js deleted file mode 100644 index ed322fe150..0000000000 --- a/packages/core/src/platform/builtInMixins/classHelperMixin.ios.js +++ /dev/null @@ -1,11 +0,0 @@ -import stringify from '@mpxjs/webpack-plugin/lib/runtime/stringify.wxs' - -export default function classHelperMixin () { - return { - methods: { - __getClass (...args) { - return stringify.stringifyClass(...args) - } - } - } -} diff --git a/packages/core/src/platform/builtInMixins/classHelperMixin.js b/packages/core/src/platform/builtInMixins/classHelperMixin.js deleted file mode 100644 index 6adad8d248..0000000000 --- a/packages/core/src/platform/builtInMixins/classHelperMixin.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function classHelperMixin () { - return {} -} diff --git a/packages/core/src/platform/builtInMixins/index.js b/packages/core/src/platform/builtInMixins/index.js index 1906f2d94b..2e6aa6d714 100644 --- a/packages/core/src/platform/builtInMixins/index.js +++ b/packages/core/src/platform/builtInMixins/index.js @@ -12,7 +12,6 @@ import getTabBarMixin from './getTabBarMixin' import pageRouteMixin from './pageRouteMixin' import { dynamicRefsMixin, dynamicRenderHelperMixin, dynamicSlotMixin } from '../../dynamic/dynamicRenderMixin.empty' import styleHelperMixin from './styleHelperMixin' -import classHelperMixin from './classHelperMixin' import directiveHelperMixin from './directiveHelperMixin' export default function getBuiltInMixins (options, type) { @@ -23,8 +22,7 @@ export default function getBuiltInMixins (options, type) { directiveHelperMixin(), styleHelperMixin(type), refsMixin(), - i18nMixin(), - classHelperMixin() + i18nMixin() ] } else if (__mpx_mode__ === 'web') { bulitInMixins = [ diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index a8980e3029..32f0435f40 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -4,6 +4,7 @@ import { watch } from '../../observer/watch' export default function getRefsMixin () { return { + // 强依赖 CREATED 生命周期,确保响应式数据初始化完成 [CREATED] () { this.__refs = {} this.$refs = {} diff --git a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js index 438bad6bb7..2251f6a2c4 100644 --- a/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/styleHelperMixin.ios.js @@ -106,6 +106,9 @@ export default function styleHelperMixin (type) { // px = rpx * (750 / 屏幕宽度) return value * width / 750 }, + __getClass (staticClass, dynamicClass) { + return concat(staticClass, stringifyDynamicClass(dynamicClass)) + }, __getStyle (staticClass, dynamicClass, staticStyle, dynamicStyle, show) { const result = [] const classMap = {} diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index 2271209a8e..87067318f6 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1659,19 +1659,12 @@ function processRefReact (el, meta) { // rn中只有内建组件能被作为node ref处理 const type = el.isBuiltIn ? 'node' : 'component' - if (val || has) { + if (has) { if (!meta.refs) { meta.refs = [] } const all = !!forScopes.length const key = `ref_rn_${++refId}` - const idString = getAndRemoveAttr(el, 'id', false).val - const classString = getAndRemoveAttr(el, 'class', false).val - const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val - - const staticId = parseMustacheWithContext(idString).result - const staticClass = parseMustacheWithContext(classString).result - const dynamicClass = parseMustacheWithContext(dynamicClassString).result const refConf = { key, @@ -1681,18 +1674,29 @@ function processRefReact (el, meta) { computedSelectorKeys: [] } - meta.computed = meta.computed || [] - - if (idString) { - const computedIdKey = `ref_computed_id_${++refId}` - refConf.computedSelectorKeys.push({ key: computedIdKey, prefix: '#' }) - meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) - } - - if (classString || dynamicClassString) { - const computedClassKey = `ref_computed_class_${++refId}` - refConf.computedSelectorKeys.push({ key: computedClassKey, prefix: '.' }) - meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`) + if (!val) { + const idString = getAndRemoveAttr(el, 'id', false).val + const classString = getAndRemoveAttr(el, 'class', false).val + const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val + + const staticId = parseMustacheWithContext(idString).result + const staticClass = parseMustacheWithContext(classString).result + const dynamicClass = parseMustacheWithContext(dynamicClassString).result + + + meta.computed = meta.computed || [] + + if (idString) { + const computedIdKey = `ref_computed_id_${++refId}` + refConf.computedSelectorKeys.push({ key: computedIdKey, prefix: '#' }) + meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) + } + + if (classString || dynamicClassString) { + const computedClassKey = `ref_computed_class_${++refId}` + refConf.computedSelectorKeys.push({ key: computedClassKey, prefix: '.' }) + meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`) + } } meta.refs.push(refConf) From df363258504a054db7c50e2862ccc88e6edae27b Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Thu, 22 Aug 2024 20:18:12 +0800 Subject: [PATCH 06/10] [optimize]optimize selectorMap computed val --- .../platform/builtInMixins/refsMixin.ios.js | 38 ++++++++++--------- .../lib/template-compiler/compiler.js | 5 --- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 32f0435f40..87f52c419b 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -1,6 +1,6 @@ import { CREATED } from '../../core/innerLifecycle' import { createSelectorQuery } from '@mpxjs/api-proxy' -import { watch } from '../../observer/watch' +import { computed } from '../../observer/computed' export default function getRefsMixin () { return { @@ -8,31 +8,35 @@ export default function getRefsMixin () { [CREATED] () { this.__refs = {} this.$refs = {} - this.__selectorMap = {} + this.__selectorMap = null this.__getRefs() }, methods: { __getRefs () { const refs = this.__getRefsData() || [] const target = this - refs.forEach(({ key, type, all, refKey, computedSelectorKeys }) => { - if (computedSelectorKeys.length) { - computedSelectorKeys.forEach((item) => { + this.__selectorMap = computed(() => { + const selectorMap = {} + refs.forEach(({ key, type, refKey, computedSelectorKeys = [] }) => { + if (refKey) { + selectorMap[refKey] = selectorMap[refKey] || [] + selectorMap[refKey].push({ type, key }) + } + computedSelectorKeys.forEach((item = {}) => { const computedKey = item.key const prefix = item.prefix - watch(() => this[computedKey], (selectors = '') => { - selectors.trim().split(/\s+/).forEach(item => { - const selector = prefix + item - this.__selectorMap[selector] = this.__selectorMap[selector] || [] - this.__selectorMap[selector].push({ type, key }) - }) - }, { immediate: true }) + const selectors = this[computedKey] || '' + selectors.trim().split(/\s+/).forEach(item => { + const selector = prefix + item + selectorMap[selector] = selectorMap[selector] || [] + selectorMap[selector].push({ type, key }) + }) }) - } + }) + return selectorMap + }) + refs.forEach(({ key, type, all, refKey }) => { if (refKey) { - this.__selectorMap[refKey] = this.__selectorMap[refKey] || [] - this.__selectorMap[refKey].push({ type, key }) - Object.defineProperty(this.$refs, refKey, { enumerable: true, configurable: true, @@ -57,7 +61,7 @@ export default function getRefsMixin () { __selectRef (selector, refType, all = false) { const splitedSelector = selector.match(/(#|\.)?\w+/g) || [] const refsArr = splitedSelector.map(selector => { - const selectorMap = this.__selectorMap[selector] || [] + const selectorMap = this.__selectorMap.value[selector] || [] const res = [] selectorMap.forEach(({ type, key }) => { if (type === refType) { diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index 87067318f6..a09d0fb2d7 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1678,20 +1678,15 @@ function processRefReact (el, meta) { const idString = getAndRemoveAttr(el, 'id', false).val const classString = getAndRemoveAttr(el, 'class', false).val const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val - const staticId = parseMustacheWithContext(idString).result const staticClass = parseMustacheWithContext(classString).result const dynamicClass = parseMustacheWithContext(dynamicClassString).result - - meta.computed = meta.computed || [] - if (idString) { const computedIdKey = `ref_computed_id_${++refId}` refConf.computedSelectorKeys.push({ key: computedIdKey, prefix: '#' }) meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) } - if (classString || dynamicClassString) { const computedClassKey = `ref_computed_class_${++refId}` refConf.computedSelectorKeys.push({ key: computedClassKey, prefix: '.' }) From c8e8c4f4c7a23b3d87773e3fc97bbd210e7794c3 Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Fri, 23 Aug 2024 15:19:57 +0800 Subject: [PATCH 07/10] [optimize]createSelecotr --- .../api/create-selector-query/rnSelectQuery.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js index f4ac3c2250..c076409869 100644 --- a/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js +++ b/packages/api-proxy/src/platform/api/create-selector-query/rnSelectQuery.js @@ -28,16 +28,8 @@ export default class SelectorQuery { if (!this._component) { warn('Please use SelectorQuery.in method to set context') } - const splitedSelector = selector.match(/(#|\.)\w+/g) || [] - const refsArr = splitedSelector.map(selector => this._component && this._component.__selectRef(selector, 'node', true)) - const refs = refsArr.reduce((preRefs, curRefs, curIndex) => { - if (curIndex === 0) return curRefs - return preRefs.filter(p => { - const preNodeRef = p.getNodeInstance && p.getNodeInstance().nodeRef - return curRefs.find(r => r.getNodeInstance && r.getNodeInstance().nodeRef === preNodeRef) - }) - }, []) - return new NodeRef(all ? refs : refs[0], this, !all) + const refs = this._component && this._component.__selectRef(selector, 'node', all) + return new NodeRef(refs, this, !all) } selectAll (selector) { From d5b840dc1a84d4e7d18b9335535c97065a0e42c2 Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Fri, 23 Aug 2024 17:03:14 +0800 Subject: [PATCH 08/10] =?UTF-8?q?[optimize]=E5=AD=97=E6=AE=B5=E4=BD=93?= =?UTF-8?q?=E7=A7=AF=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/builtInMixins/refsMixin.ios.js | 58 +++++++++---------- .../lib/template-compiler/compiler.js | 15 +++-- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 87f52c419b..c6671508e5 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -17,40 +17,38 @@ export default function getRefsMixin () { const target = this this.__selectorMap = computed(() => { const selectorMap = {} - refs.forEach(({ key, type, refKey, computedSelectorKeys = [] }) => { - if (refKey) { - selectorMap[refKey] = selectorMap[refKey] || [] - selectorMap[refKey].push({ type, key }) - } - computedSelectorKeys.forEach((item = {}) => { - const computedKey = item.key - const prefix = item.prefix - const selectors = this[computedKey] || '' - selectors.trim().split(/\s+/).forEach(item => { - const selector = prefix + item - selectorMap[selector] = selectorMap[selector] || [] - selectorMap[selector].push({ type, key }) + refs.forEach(({ key, type, all, sKeys }) => { + // sKeys 是使用 wx:ref 没有值的标记场景,支持运行时的 createSelectorQuery 的使用 + if (sKeys) { + sKeys.forEach((item = {}) => { + const computedKey = item.key + const prefix = item.prefix + const selectors = this[computedKey] || '' + selectors.trim().split(/\s+/).forEach(item => { + const selector = prefix + item + selectorMap[selector] = selectorMap[selector] || [] + selectorMap[selector].push({ type, key }) + }) + }) + } else { + selectorMap[key] = selectorMap[key] || [] + selectorMap[key].push({ type, key }) + Object.defineProperty(this.$refs, key, { + enumerable: true, + configurable: true, + get() { + const refs = target.__refs[key] || [] + if (type === 'component') { + return all ? refs : refs[0] + } else { + return createSelectorQuery().in(target).select(key, all) + } + } }) - }) + } }) return selectorMap }) - refs.forEach(({ key, type, all, refKey }) => { - if (refKey) { - Object.defineProperty(this.$refs, refKey, { - enumerable: true, - configurable: true, - get () { - const refs = target.__refs[key] || [] - if (type === 'component') { - return all ? refs : refs[0] - } else { - return createSelectorQuery().in(target).select(refKey, all) - } - } - }) - } - }) }, __getRefVal (key) { if (!this.__refs[key]) { diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index 4d9d4129da..bc46b0e4b0 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1700,17 +1700,16 @@ function processRefReact (el, meta) { meta.refs = [] } const all = !!forScopes.length - const key = `ref_rn_${++refId}` + const key = val || `ref_rn_${++refId}` const refConf = { key, all, - type, - refKey: val, - computedSelectorKeys: [] + type } if (!val) { + refConf.sKeys = [] const idString = getAndRemoveAttr(el, 'id', false).val const classString = getAndRemoveAttr(el, 'class', false).val const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val @@ -1719,13 +1718,13 @@ function processRefReact (el, meta) { const dynamicClass = parseMustacheWithContext(dynamicClassString).result meta.computed = meta.computed || [] if (idString) { - const computedIdKey = `ref_computed_id_${++refId}` - refConf.computedSelectorKeys.push({ key: computedIdKey, prefix: '#' }) + const computedIdKey = `_ri${++refId}` + refConf.sKeys.push({ key: computedIdKey, prefix: '#' }) meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) } if (classString || dynamicClassString) { - const computedClassKey = `ref_computed_class_${++refId}` - refConf.computedSelectorKeys.push({ key: computedClassKey, prefix: '.' }) + const computedClassKey = `_rc${++refId}` + refConf.sKeys.push({ key: computedClassKey, prefix: '.' }) meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`) } } From 788c83bac80836a6b4d5e3156829aff90800ca3e Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Fri, 23 Aug 2024 17:06:57 +0800 Subject: [PATCH 09/10] [lint]fix --- packages/core/src/platform/builtInMixins/refsMixin.ios.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index c6671508e5..04667c3e5b 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -36,7 +36,7 @@ export default function getRefsMixin () { Object.defineProperty(this.$refs, key, { enumerable: true, configurable: true, - get() { + get () { const refs = target.__refs[key] || [] if (type === 'component') { return all ? refs : refs[0] From 1460dc2ede4826a0f28e1cfb06a29d4952b2678a Mon Sep 17 00:00:00 2001 From: xiaolei <1017653702@qq.com> Date: Fri, 23 Aug 2024 19:32:41 +0800 Subject: [PATCH 10/10] =?UTF-8?q?[fix]ref=E7=BC=96=E8=AF=91=E5=8F=96?= =?UTF-8?q?=E5=80=BC=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/builtInMixins/refsMixin.ios.js | 31 +++++++++++-------- .../lib/template-compiler/compiler.js | 25 ++++++++++----- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/core/src/platform/builtInMixins/refsMixin.ios.js b/packages/core/src/platform/builtInMixins/refsMixin.ios.js index 04667c3e5b..dd74adb28a 100644 --- a/packages/core/src/platform/builtInMixins/refsMixin.ios.js +++ b/packages/core/src/platform/builtInMixins/refsMixin.ios.js @@ -17,7 +17,7 @@ export default function getRefsMixin () { const target = this this.__selectorMap = computed(() => { const selectorMap = {} - refs.forEach(({ key, type, all, sKeys }) => { + refs.forEach(({ key, type, sKeys }) => { // sKeys 是使用 wx:ref 没有值的标记场景,支持运行时的 createSelectorQuery 的使用 if (sKeys) { sKeys.forEach((item = {}) => { @@ -33,22 +33,27 @@ export default function getRefsMixin () { } else { selectorMap[key] = selectorMap[key] || [] selectorMap[key].push({ type, key }) - Object.defineProperty(this.$refs, key, { - enumerable: true, - configurable: true, - get () { - const refs = target.__refs[key] || [] - if (type === 'component') { - return all ? refs : refs[0] - } else { - return createSelectorQuery().in(target).select(key, all) - } - } - }) } }) return selectorMap }) + refs.forEach(({ key, type, all, sKeys }) => { + // 如果没有 sKey 说明使用的是 wx:ref="xxx" 的场景 + if (!sKeys) { + Object.defineProperty(this.$refs, key, { + enumerable: true, + configurable: true, + get () { + const refs = target.__refs[key] || [] + if (type === 'component') { + return all ? refs : refs[0] + } else { + return createSelectorQuery().in(target).select(key, all) + } + } + }) + } + }) }, __getRefVal (key) { if (!this.__refs[key]) { diff --git a/packages/webpack-plugin/lib/template-compiler/compiler.js b/packages/webpack-plugin/lib/template-compiler/compiler.js index bc46b0e4b0..505407c110 100644 --- a/packages/webpack-plugin/lib/template-compiler/compiler.js +++ b/packages/webpack-plugin/lib/template-compiler/compiler.js @@ -1710,19 +1710,28 @@ function processRefReact (el, meta) { if (!val) { refConf.sKeys = [] - const idString = getAndRemoveAttr(el, 'id', false).val - const classString = getAndRemoveAttr(el, 'class', false).val - const dynamicClassString = getAndRemoveAttr(el, config[mode].directive.dynamicClass, false).val - const staticId = parseMustacheWithContext(idString).result - const staticClass = parseMustacheWithContext(classString).result - const dynamicClass = parseMustacheWithContext(dynamicClassString).result + let rawId + let rawClass + let rawDynamicClass + el.attrsList.forEach(({ name, value }) => { + if (name === 'id') { + rawId = value + } else if (name === 'class') { + rawClass = value + } else if (name === config[mode].directive.dynamicClass) { + rawDynamicClass = value + } + }) meta.computed = meta.computed || [] - if (idString) { + if (rawId) { + const staticId = parseMustacheWithContext(rawId).result const computedIdKey = `_ri${++refId}` refConf.sKeys.push({ key: computedIdKey, prefix: '#' }) meta.computed.push(`${computedIdKey}() {\n return ${staticId}}`) } - if (classString || dynamicClassString) { + if (rawClass || rawDynamicClass) { + const staticClass = parseMustacheWithContext(rawClass).result + const dynamicClass = parseMustacheWithContext(rawDynamicClass).result const computedClassKey = `_rc${++refId}` refConf.sKeys.push({ key: computedClassKey, prefix: '.' }) meta.computed.push(`${computedClassKey}() {\n return this.__getClass(${staticClass}, ${dynamicClass})}`)