微信小程序SelectorQuery

在开发小程序展开全文组件时需要用到节点查询API - wx.createSelectorQuery() 来查询全文内容的高度。

微信小程序之SelectorQuery

  • wx.createSelectorQuery() 返回一个 SelectorQuery 对象实例。
  • SelectorQuery 有五个方法(inselectselectAllselectViewportexec),第一个返回 SelectorQuery,后四个返回 NodesRef
  • NodesRef 有四个方法(fieldsboundingClientRectscrollOffsetcontext),第一个返回 NodesRef,后三个返回 SelectorQuery

对照官方提供的示例代码来看

const query = wx.createSelectorQuery() // query 是 SelectorQuery 对象

query.select('#the-id').boundingClientRect() // select 后是 NodesRef 对象,然后 boundingClientRect 返回 SelectorQuery 对象

query.selectViewport().scrollOffset() // selectViewport 后是 NodesRef 对象,然后 scrollOffset 返回 SelectorQuery 对象

query.exec(function(res){ // exec 返回 NodesRef 对象

res[0].top // #the-id节点的上边界坐标

res[1].scrollTop // 显示区域的竖直滚动位置

})

问题:每行执行返回的 SelectorQuery 对象是相同的吗?

答案:是的,都是同一个对象。

问题:直接执行 query.select('#the-id').boundingClientRect().exec 也可以吗?

答案:可以,boundingClientRect() 返回就是 query

问题:这样连写 query.select('#the-id').boundingClientRect().selectViewport().scrollOffset() 算两条查询请求吗?

答案:是两条请求。

问题:query.exec 执行后会清空前面的查询请求吗?再次执行还能拿到结果吗?

答案:可以,query 不会清空请求。

问题:boundingClientRectscrollOffset 可以接受 callback 参数,它与 query.exec 执行顺序是怎样,修改 res 结果会影响到后面的 callback 吗?

答案:先执行 boundingClientRectscrollOffsetcallback,再执行 query.execcallback;修改 res 结果会影响到后面 exec 的结果。

上面的问题通过小程序开发者工具中的 WAService.js 源码简单美化还原后可以了解 SelectorQuery 的代码逻辑

SelectorQuery.js

import NodesRef from'NodesRef';

import requestComponentInfo from'requestComponentInfo';

exportdefaultfunction(pluginId) {

returnclassSelectorQuery{

constructor(plugin) {

if (plugin && plugin.page) {

this._component = this._defaultComponent = plugin.page;

this._webviewId = this._defaultComponent.__wxWebviewId__;

} else {

var pages = __internalGlobal__.getCurrentPagesByDomain('');

this._defaultComponent = pages[pages.length - 1],

this._component = null;

this._webviewId = null;

}

this._queue = [];

this._queueCb = [];

}

in(component) {

if (!this._webviewId) {

this._webviewId = component.__wxWebviewId__;

this._component = component;

} elseif (this._webviewId !== component.__wxWebviewId__) {

console.error('A single SelectorQuery could not work in components in different pages. A SelectorQuery#in call has been ignored.');

} else {

this._component = component;

}

returnthis;

}

select(selector) {

returnnew NodesRef(this, this._component, selector, true);

}

selectAll(selector) {

returnnew NodesRef(this, this._component, selector, false);

}

selectViewport() {

returnnew NodesRef(this, 0, '', true);

}

_push(selector, component, single, fields, callback) {

if (!this._webviewId) {

this._webviewId = this._defaultComponent ? this._defaultComponent.__wxWebviewId__ : undefined;

}

const rootNodeId = pluginId ? '' : r.getRootNodeId(this._webviewId);

this._queue.push({

component: null != component ? (0 === component ? 0 : component.__wxExparserNodeId__) : rootNodeId,

selector,

single,

fields,

});

this._queueCb.push(callback || null);

}

exec(callback) {

requestComponentInfo(this._webviewId, {

pluginId,

queue: this._queue,

}, (results) => {

const queueCb = this._queueCb;

results.forEach((res, index) => {

if ('function' == typeof queueCb[index]) {

queueCb[index].call(this, res);

}

});

if ('function' == typeof callback) {

callback.call(this, results);

}

})

}

}

}

requestComponentInfo.js

const subscribe = function(eventType, callback) {

const _callback = function(event, webviewId, nativeInfo = {}) {

const { data = {}, options } = event;

const startTime = options && options.timestamp || 0;

const endTime = Date.now();

if ('function' == typeof callback) {

callback(data, webviewId);

Reporter.speedReport({

key: 'webview2AppService',

data,

timeMark: {

startTime,

endTime,

nativeTime: nativeInfo.nativeTime || 0,

}

});

}

};

__safeway__.bridge.subscribe(eventType, _callback);

}

const publish = function(eventType, data, webviewIds) {

const event = {

data,

options: {

timestamp: Date.now(),

}

};

__safeway__.bridge.publish(eventType, event, webviewIds);

}

const requestCb = {};

let requestId = 1;

subscribe('responseComponentInfo', function(data) {

const reqId = data.reqId;

const callback = requestCb[reqId];

if (callback) {

delete requestCb[reqId];

callback(data.res);

}

});

exportdefaultfunctionrequestComponentInfo(webviewId, reqs, callback) {

const reqId = requestId++;

if (!webviewId) {

console.warn('An SelectorQuery call is ignored because no proper page or component is found. Please considering using `SelectorQuery.in` to specify a proper one.');

return;

}

requestCb[reqId] = callback,

publish('requestComponentInfo',

{

reqId,

reqs,

},

[webviewId],

);

}

NodesRef.js

exportdefaultclassNodesRef{

constructor(selectorQuery, component, selector, single) {

this._selectorQuery = selectorQuery;

this._component = component;

this._selector = selector;

this._single = single;

}

fields(fields, callback) {

this._selectorQuery._push(this._selector, this._component, this._single,

fields,

callback,

);

returnthis._selectorQuery;

}

boundingClientRect(callback) {

this._selectorQuery._push( this._selector, this._component, this._single,

{

id: true,

dataset: true,

rect: true,

size: true,

},

callback,

);

returnthis._selectorQuery;

}

scrollOffset(callback) {

this._selectorQuery._push( this._selector, this._component, this._single,

{

id: true,

dataset: true,

scrollOffset: true,

},

callback,

);

returnthis._selectorQuery;

}

}

以上是 微信小程序SelectorQuery 的全部内容, 来源链接: utcz.com/a/115830.html

回到顶部