我正在尝试让我的浏览器将一些 DOM 事件发送到 React VR 组件中。
我得到的最接近的是使用"本机模块"的代码。
(客户端.js)
const windowEventsModule = new WindowEventsModule();
function init(bundle, parent, options) {
const vr = new VRInstance(bundle, 'WelcomeToVR', parent, {
...options,
nativeModules: [windowEventsModule]
});
windowEventsModule.init(vr.rootView.context);
vr.start();
return vr;
}
window.ReactVR = {init};
(窗口事件模块.js)
export default class WindowEventsModule extends Module {
constructor() {
super('WindowEventsModule');
this.listeners = {};
window.onmousewheel = event => {
this._emit('onmousewheel', event);
};
}
init(rnctx) {
this._rnctx = rnctx;
}
_emit(name, ob) {
if (!this._rnctx) {
return;
}
Object.keys(this.listeners).forEach(key => {
this._rnctx.invokeCallback(this.listeners[key], [ob]);
});
}
onMouseWheel(listener) {
const key = String(Math.random());
this.listeners[key] = listener;
return () => {
delete this.listeners[key];
};
}
}
所以我的组件现在可以调用WindowEvents.onMouseWheel(function() {})
,并从 DOM 世界获得回调。
不幸的是,这只有效一次。RN 显然会在调用后使我的回调无效。
我还研究了this._rnctx.callFunction()
,它可以在称为"可调用模块"的东西上调用任意函数。我不明白如何从那里到我的组件。
我错过了什么吗?将来自原生世界的任意消息馈送到 ReactVR 后台工作线程的模式是什么?
我想通了...有点。
诀窍是创建我自己的"BatchedBridge",然后我可以使用上下文中的callFunction()
访问它。
(索引.vr.js)
import React from 'react';
import {AppRegistry, asset, Pano, View} from 'react-vr';
import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
import lodash from 'lodash';
class BrowserBridge {
constructor() {
this._subscribers = {};
}
subscribe(handler) {
const key = String(Math.random());
this._subscribers[key] = handler;
return () => {
delete this._subscribers[key];
};
}
notifyEvent(name, event) {
lodash.forEach(this._subscribers, handler => {
handler(name, event);
});
}
}
const browserBridge = new BrowserBridge();
BatchedBridge.registerCallableModule(BrowserBridge.name, browserBridge);
export default class WelcomeToVR extends React.Component {
constructor(props) {
super(props);
this.onBrowserEvent = this.onBrowserEvent.bind(this);
}
componentWillMount() {
this.unsubscribe = browserBridge.subscribe(this.onBrowserEvent);
}
onBrowserEvent(name, event) {
// Do the thing here
}
componentWillUnmount() {
if (this.unsubscribe) {
this.unsubscribe();
delete this.unsubscribe;
}
}
render() {
//...
}
};
AppRegistry.registerComponent('WelcomeToVR', () => WelcomeToVR);
(窗口事件模块.js)
import {Module} from 'react-vr-web';
import lodash from 'lodash';
const eventToOb = (event) => {
const eventOb = {};
for (let key in event) {
const val = event[key];
if (!(lodash.isFunction(val) || lodash.isObject(val))) {
eventOb[key] = val;
}
}
return eventOb;
};
export default class WindowEventsModule extends Module {
constructor() {
super('WindowEventsModule');
this._bridgeName = 'BrowserBridge';
window.onmousewheel = event => {
this._emit('onmousewheel', event);
};
}
init(rnctx) {
this._rnctx = rnctx;
}
_emit(name, event) {
if (!this._rnctx) {
return;
}
const eventOb = eventToOb(event);
this._rnctx.callFunction(this._bridgeName, 'notifyEvent', [name, eventOb]);
}
}
这感觉非常笨拙,因为它似乎BatchedBridge
从未打算暴露给消费者。
但在有更好的选择之前,我想我会选择这个。