如何使用 React Native 创建事件
How to create events using React Native
我正在使用 React VR 制作应用程序。 如果你不知道 React VR,那么它基于 React Native 和一些其他组件,包括 Three.js 和其他东西,特定于使用 WebVR。
我制作了一个名为 NavigateButton
的组件。下面是我的代码:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
export class NavigateButton extends React.Component {
render() {
return (
<VrButton onClick={() => this.onNavigating()}>
<Sphere radius={0.5} widthSegments={10} heightSegments={10} style={{ color: "red" }} />
</VrButton>
);
}
onNavigating() { // This method must throw an event
console.log(this.props.to);
}
};
如果用户点击 VrButton
(这类似于 HTML 5 button
-标签,但对于内部有 VR 的来说,是一个球体),必须在我调用NavigateButton
组件的地方引发一个事件。这是下面的代码:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
import { NavigateButton } from './components/nativateButton.js';
let room = asset('360 LR/inkom_hal.jpg');
export default class MainComp extends React.Component {
render() {
return (
<View>
<Pano source={asset('360 LR/inkom_hal.jpg')} />
<View style={{ transform: [{ translate: [20, 0, 0] }] }}>
<NavigateButton to="garage"></NavigateButton>
<!-- and must been catch here -->
</View>
<View style={{ transform: [{ translate: [-7, 0, -20] }] }}>
<NavigateButton to="woonkamer"></NavigateButton>
<!-- or here -->
</View>
</View>
);
}
}
AppRegistry.registerComponent('MainComp', () => MainComp);
可以吗?我想要类似下面的代码来捕捉事件:
<NavigateButton to="woonkamer" onNavigate={() => this.change()}></NavigateButton>
我在 Internet 上搜索过,但没有找到可以帮助我的东西。
以下是我和我的团队准备的如何使用 React VR 创建示例 VR 应用程序的说明:
正在为网络创建 VR 导览
未来app的目录结构如下:
+-node_modules
+-static_assets
+-vr
\-.gitignore
\-.watchmanconfig
\-index.vr.js
\-package.json
\-postinstall.js
\-rn-cli-config.js
Web 应用程序的代码将在 index.vr.js 文件中,而 static_assets 目录存放外部资源(图像、3D 模型)。您可以在此处了解有关如何开始使用 React VR 项目的更多信息。 index.vr.js 文件包含以下内容:
import React from 'react';
import {
AppRegistry,
asset,
StyleSheet,
Pano,
Text,
View,
}
from 'react-vr';
class TMExample extends React.Component {
render() {
return (
<View>
<Pano source={asset('chess-world.jpg')}/>
<Text
style={{
backgroundColor:'blue',
padding: 0.02,
textAlign:'center',
textAlignVertical:'center',
fontSize: 0.8,
layoutOrigin: [0.5, 0.5],
transform: [{translate: [0, 0, -3]}],
}}>
hello
</Text>
</View>
);
}
};
AppRegistry.registerComponent('TMExample', () => TMExample);
正在使用 VR 组件
我们使用 React Native packager 进行代码预处理、编译、打包和资产加载。在渲染功能中有视图、全景和文本组件。这些 React VR 组件中的每一个都带有一个样式属性来帮助控制布局。
最后,检查根组件是否已在 AppRegistry.registerComponent 上注册,这会捆绑应用程序并准备好 运行。在我们的 React VR 项目中要强调的下一步是编译 2 个主要文件。
Index.vr.js 文件
在构造函数中,我们已经指明了 VR 旅游应用程序的数据。这些是场景图像、用于在具有 X-Y-Z 坐标的场景之间切换的按钮、动画值。我们包含在 static_assets 文件夹中的所有图像。
constructor (props) {
super(props);
this.state = {
scenes: [{scene_image: 'initial.jpg', step: 1, navigations: [{step:2, translate: [0.73,-0.15,0.66], rotation: [0,36,0] }] },
{scene_image: 'step1.jpg', step: 2, navigations: [{step:3, translate: [-0.43,-0.01,0.9], rotation: [0,140,0] }]},
{scene_image: 'step2.jpg', step: 3, navigations: [{step:4, translate: [-0.4,0.05,-0.9], rotation: [0,0,0] }]},
{scene_image: 'step3.jpg', step: 4, navigations: [{step:5, translate: [-0.55,-0.03,-0.8], rotation: [0,32,0] }]},
{scene_image: 'step4.jpg', step: 5, navigations: [{step:1, translate: [0.2,-0.03,-1], rotation: [0,20,0] }]}],
current_scene:{},
animationWidth: 0.05,
animationRadius: 50
};
}
然后我们将图像的输出 link 更改为状态,之前在构造函数中指示。
<View>
<Pano source={asset(this.state.current_scene['scene_image'])}
style={{
transform: [{translate: [0, 0, 0]}]
}}/>
</View>
导航按钮
在每个场景中,我们都放置了用于在游览中导航的过渡按钮,从状态中获取数据。订阅 onInput 事件以传达场景之间的切换,并将其绑定到它。
<View>
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
onLoad={this.sceneOnLoad} onLoadEnd={this.sceneOnLoadEnd}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
{this.state.current_scene['navigations'].map(function(item,i){
return <Mesh key={i}
style={{
layoutOrigin: [0.5, 0.5],
transform: [{translate: item['translate']},
{rotateX: item['rotation'][0]},
{rotateY: item['rotation'][1]},
{rotateZ: item['rotation'][2]}]
}}
onInput={ e => that.onNavigationClick(item,e)}>
<VrButton
style={{ width: 0.15,
height:0.15,
borderRadius: 50,
justifyContent: 'center',
alignItems: 'center',
borderStyle: 'solid',
borderColor: '#FFFFFF80',
borderWidth: 0.01
}}>
<VrButton
style={{ width: that.state.animationWidth,
height:that.state.animationWidth,
borderRadius: that.state.animationRadius,
backgroundColor: '#FFFFFFD9'
}}>
</VrButton>
</VrButton>
</Mesh>
})}
</View>
onNavigationClick(item,e){
if(e.nativeEvent.inputEvent.eventType === "mousedown" && e.nativeEvent.inputEvent.button === 0){
var new_scene = this.state.scenes.find(i => i['step'] === item.step);
this.setState({current_scene: new_scene});
postMessage({ type: "sceneChanged"})
}
}
sceneOnLoad(){
postMessage({ type: "sceneLoadStart"})
}
sceneOnLoadEnd(){
postMessage({ type: "sceneLoadEnd"})
}
this.sceneOnLoad = this.sceneOnLoad.bind(this);
this.sceneOnLoadEnd = this.sceneOnLoadEnd.bind(this);
this.onNavigationClick = this.onNavigationClick.bind(this);
按钮动画
下面,我们将展示导航按钮动画的代码。我们根据按钮增加原理构建动画,应用常规的 requestAnimationFrame。
this.animatePointer = this.animatePointer.bind(this);
animatePointer(){
var delta = this.state.animationWidth + 0.002;
var radius = this.state.animationRadius + 10;
if(delta >= 0.13){
delta = 0.05;
radius = 50;
}
this.setState({animationWidth: delta, animationRadius: radius})
this.frameHandle = requestAnimationFrame(this.animatePointer);
}
componentDidMount(){
this.animatePointer();
}
componentWillUnmount(){
if (this.frameHandle) {
cancelAnimationFrame(this.frameHandle);
this.frameHandle = null;
}
}
在 componentWillMount 函数中我们已经指明了当前场景。然后我们还订阅了消息事件,用于与主线程进行数据交换。我们这样做是因为需要在单独的线程中制定 React VR 组件。
在 onMainWindowMessage 函数中,我们只处理一条带有 newCoordinates 键的消息。我们稍后会详细说明我们为什么这样做。同样,我们订阅了 onInput 事件来传达箭头的转动。
componentWillMount(){
window.addEventListener('message', this.onMainWindowMessage);
this.setState({current_scene: this.state.scenes[0]})
}
onMainWindowMessage(e){
switch (e.data.type) {
case 'newCoordinates':
var scene_navigation = this.state.current_scene.navigations[0];
this.state.current_scene.navigations[0]['translate'] = [e.data.coordinates.x,e.data.coordinates.y,e.data.coordinates.z]
this.forceUpdate();
break;
default:
return;
}
}
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
rotatePointer(nativeEvent){
switch (nativeEvent.keyCode) {
case 38:
this.state.current_scene.navigations[0]['rotation'][1] += 4;
break;
case 39:
this.state.current_scene.navigations[0]['rotation'][0] += 4;
break;
case 40:
this.state.current_scene.navigations[0]['rotation'][2] += 4;
break;
default:
return;
}
this.forceUpdate();
}
分别针对 Y-X-Z 轴使用 ↑→↓ alt 键完成箭头转动。
在 Github 此处查看并下载整个 index.vr.js 文件。
Client.js 文件
进一步进入虚拟现实 Web 应用程序的 React VR 示例,我们将以下代码添加到 init 函数中。目标是处理 ondblclick、onmousewheel 和消息事件,其中后者在渲染线程中进行消息交换。此外,我们为 vr 和 vr.player._camera 对象保留了 link。
window.playerCamera = vr.player._camera;
window.vr = vr;
window.ondblclick= onRendererDoubleClick;
window.onmousewheel = onRendererMouseWheel;
vr.rootView.context.worker.addEventListener('message', onVRMessage);
我们引入了onVRMessage函数,用于在场景变化时返回默认缩放。此外,我们还添加了场景更改时的加载器。
function onVRMessage(e) {
switch (e.data.type) {
case 'sceneChanged':
if (window.playerCamera.zoom != 1) {
window.playerCamera.zoom = 1;
window.playerCamera.updateProjectionMatrix();
}
break;
case 'sceneLoadStart':
document.getElementById('loader').style.display = 'block';
break;
case 'sceneLoadEnd':
document.getElementById('loader').style.display = 'none';
break;
default:
return;
}
}
onRendererDoubleClick
函数,用于计算 3D 坐标并向 vr 组件发送消息以更改箭头坐标。 get3DPoint
函数是我们的 web VR 应用程序自定义的,如下所示:
function onRendererDoubleClick(){
var x = 2 * (event.x / window.innerWidth) - 1;
var y = 1 - 2 * ( event.y / window.innerHeight );
var coordinates = get3DPoint(window.playerCamera, x, y);
vr.rootView.context.worker.postMessage({ type: "newCoordinates", coordinates: coordinates });
}
切换到鼠标滚轮
我们使用 onRendererMouseWheel
功能将缩放切换为鼠标滚轮。
function onRendererMouseWheel(){
if (event.deltaY > 0 ){
if(window.playerCamera.zoom > 1) {
window.playerCamera.zoom -= 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
else {
if(window.playerCamera.zoom < 3) {
window.playerCamera.zoom += 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
}
导出坐标
然后我们利用 Three.js 处理 3D 图形。在这个文件中,我们只传达了一个功能,将屏幕坐标导出到世界坐标。
import * as THREE from 'three';
export function get3DPoint(camera,x,y){
var mousePosition = new THREE.Vector3(x, y, 0.5);
mousePosition.unproject(camera);
var dir = mousePosition.sub(camera.position).normalize();
return dir;
}
在 Github 此处查看并下载整个 client.js 文件。 cameraHelper.js 文件的工作原理可能不需要解释,因为它非常简单,您也可以下载它。
此外,如果您对类似的项目估算或有关 ReactVR 开发的相同附加技术细节感兴趣 - 您可以找到一些信息 here:
我正在使用 React VR 制作应用程序。 如果你不知道 React VR,那么它基于 React Native 和一些其他组件,包括 Three.js 和其他东西,特定于使用 WebVR。
我制作了一个名为 NavigateButton
的组件。下面是我的代码:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
export class NavigateButton extends React.Component {
render() {
return (
<VrButton onClick={() => this.onNavigating()}>
<Sphere radius={0.5} widthSegments={10} heightSegments={10} style={{ color: "red" }} />
</VrButton>
);
}
onNavigating() { // This method must throw an event
console.log(this.props.to);
}
};
如果用户点击 VrButton
(这类似于 HTML 5 button
-标签,但对于内部有 VR 的来说,是一个球体),必须在我调用NavigateButton
组件的地方引发一个事件。这是下面的代码:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
import { NavigateButton } from './components/nativateButton.js';
let room = asset('360 LR/inkom_hal.jpg');
export default class MainComp extends React.Component {
render() {
return (
<View>
<Pano source={asset('360 LR/inkom_hal.jpg')} />
<View style={{ transform: [{ translate: [20, 0, 0] }] }}>
<NavigateButton to="garage"></NavigateButton>
<!-- and must been catch here -->
</View>
<View style={{ transform: [{ translate: [-7, 0, -20] }] }}>
<NavigateButton to="woonkamer"></NavigateButton>
<!-- or here -->
</View>
</View>
);
}
}
AppRegistry.registerComponent('MainComp', () => MainComp);
可以吗?我想要类似下面的代码来捕捉事件:
<NavigateButton to="woonkamer" onNavigate={() => this.change()}></NavigateButton>
我在 Internet 上搜索过,但没有找到可以帮助我的东西。
以下是我和我的团队准备的如何使用 React VR 创建示例 VR 应用程序的说明:
正在为网络创建 VR 导览 未来app的目录结构如下:
+-node_modules
+-static_assets
+-vr
\-.gitignore
\-.watchmanconfig
\-index.vr.js
\-package.json
\-postinstall.js
\-rn-cli-config.js
Web 应用程序的代码将在 index.vr.js 文件中,而 static_assets 目录存放外部资源(图像、3D 模型)。您可以在此处了解有关如何开始使用 React VR 项目的更多信息。 index.vr.js 文件包含以下内容:
import React from 'react';
import {
AppRegistry,
asset,
StyleSheet,
Pano,
Text,
View,
}
from 'react-vr';
class TMExample extends React.Component {
render() {
return (
<View>
<Pano source={asset('chess-world.jpg')}/>
<Text
style={{
backgroundColor:'blue',
padding: 0.02,
textAlign:'center',
textAlignVertical:'center',
fontSize: 0.8,
layoutOrigin: [0.5, 0.5],
transform: [{translate: [0, 0, -3]}],
}}>
hello
</Text>
</View>
);
}
};
AppRegistry.registerComponent('TMExample', () => TMExample);
正在使用 VR 组件
我们使用 React Native packager 进行代码预处理、编译、打包和资产加载。在渲染功能中有视图、全景和文本组件。这些 React VR 组件中的每一个都带有一个样式属性来帮助控制布局。
最后,检查根组件是否已在 AppRegistry.registerComponent 上注册,这会捆绑应用程序并准备好 运行。在我们的 React VR 项目中要强调的下一步是编译 2 个主要文件。
Index.vr.js 文件
在构造函数中,我们已经指明了 VR 旅游应用程序的数据。这些是场景图像、用于在具有 X-Y-Z 坐标的场景之间切换的按钮、动画值。我们包含在 static_assets 文件夹中的所有图像。
constructor (props) {
super(props);
this.state = {
scenes: [{scene_image: 'initial.jpg', step: 1, navigations: [{step:2, translate: [0.73,-0.15,0.66], rotation: [0,36,0] }] },
{scene_image: 'step1.jpg', step: 2, navigations: [{step:3, translate: [-0.43,-0.01,0.9], rotation: [0,140,0] }]},
{scene_image: 'step2.jpg', step: 3, navigations: [{step:4, translate: [-0.4,0.05,-0.9], rotation: [0,0,0] }]},
{scene_image: 'step3.jpg', step: 4, navigations: [{step:5, translate: [-0.55,-0.03,-0.8], rotation: [0,32,0] }]},
{scene_image: 'step4.jpg', step: 5, navigations: [{step:1, translate: [0.2,-0.03,-1], rotation: [0,20,0] }]}],
current_scene:{},
animationWidth: 0.05,
animationRadius: 50
};
}
然后我们将图像的输出 link 更改为状态,之前在构造函数中指示。
<View>
<Pano source={asset(this.state.current_scene['scene_image'])}
style={{
transform: [{translate: [0, 0, 0]}]
}}/>
</View>
导航按钮 在每个场景中,我们都放置了用于在游览中导航的过渡按钮,从状态中获取数据。订阅 onInput 事件以传达场景之间的切换,并将其绑定到它。
<View>
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
onLoad={this.sceneOnLoad} onLoadEnd={this.sceneOnLoadEnd}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
{this.state.current_scene['navigations'].map(function(item,i){
return <Mesh key={i}
style={{
layoutOrigin: [0.5, 0.5],
transform: [{translate: item['translate']},
{rotateX: item['rotation'][0]},
{rotateY: item['rotation'][1]},
{rotateZ: item['rotation'][2]}]
}}
onInput={ e => that.onNavigationClick(item,e)}>
<VrButton
style={{ width: 0.15,
height:0.15,
borderRadius: 50,
justifyContent: 'center',
alignItems: 'center',
borderStyle: 'solid',
borderColor: '#FFFFFF80',
borderWidth: 0.01
}}>
<VrButton
style={{ width: that.state.animationWidth,
height:that.state.animationWidth,
borderRadius: that.state.animationRadius,
backgroundColor: '#FFFFFFD9'
}}>
</VrButton>
</VrButton>
</Mesh>
})}
</View>
onNavigationClick(item,e){
if(e.nativeEvent.inputEvent.eventType === "mousedown" && e.nativeEvent.inputEvent.button === 0){
var new_scene = this.state.scenes.find(i => i['step'] === item.step);
this.setState({current_scene: new_scene});
postMessage({ type: "sceneChanged"})
}
}
sceneOnLoad(){
postMessage({ type: "sceneLoadStart"})
}
sceneOnLoadEnd(){
postMessage({ type: "sceneLoadEnd"})
}
this.sceneOnLoad = this.sceneOnLoad.bind(this);
this.sceneOnLoadEnd = this.sceneOnLoadEnd.bind(this);
this.onNavigationClick = this.onNavigationClick.bind(this);
按钮动画
下面,我们将展示导航按钮动画的代码。我们根据按钮增加原理构建动画,应用常规的 requestAnimationFrame。
this.animatePointer = this.animatePointer.bind(this);
animatePointer(){
var delta = this.state.animationWidth + 0.002;
var radius = this.state.animationRadius + 10;
if(delta >= 0.13){
delta = 0.05;
radius = 50;
}
this.setState({animationWidth: delta, animationRadius: radius})
this.frameHandle = requestAnimationFrame(this.animatePointer);
}
componentDidMount(){
this.animatePointer();
}
componentWillUnmount(){
if (this.frameHandle) {
cancelAnimationFrame(this.frameHandle);
this.frameHandle = null;
}
}
在 componentWillMount 函数中我们已经指明了当前场景。然后我们还订阅了消息事件,用于与主线程进行数据交换。我们这样做是因为需要在单独的线程中制定 React VR 组件。
在 onMainWindowMessage 函数中,我们只处理一条带有 newCoordinates 键的消息。我们稍后会详细说明我们为什么这样做。同样,我们订阅了 onInput 事件来传达箭头的转动。
componentWillMount(){
window.addEventListener('message', this.onMainWindowMessage);
this.setState({current_scene: this.state.scenes[0]})
}
onMainWindowMessage(e){
switch (e.data.type) {
case 'newCoordinates':
var scene_navigation = this.state.current_scene.navigations[0];
this.state.current_scene.navigations[0]['translate'] = [e.data.coordinates.x,e.data.coordinates.y,e.data.coordinates.z]
this.forceUpdate();
break;
default:
return;
}
}
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
rotatePointer(nativeEvent){
switch (nativeEvent.keyCode) {
case 38:
this.state.current_scene.navigations[0]['rotation'][1] += 4;
break;
case 39:
this.state.current_scene.navigations[0]['rotation'][0] += 4;
break;
case 40:
this.state.current_scene.navigations[0]['rotation'][2] += 4;
break;
default:
return;
}
this.forceUpdate();
}
分别针对 Y-X-Z 轴使用 ↑→↓ alt 键完成箭头转动。
在 Github 此处查看并下载整个 index.vr.js 文件。
Client.js 文件
进一步进入虚拟现实 Web 应用程序的 React VR 示例,我们将以下代码添加到 init 函数中。目标是处理 ondblclick、onmousewheel 和消息事件,其中后者在渲染线程中进行消息交换。此外,我们为 vr 和 vr.player._camera 对象保留了 link。
window.playerCamera = vr.player._camera;
window.vr = vr;
window.ondblclick= onRendererDoubleClick;
window.onmousewheel = onRendererMouseWheel;
vr.rootView.context.worker.addEventListener('message', onVRMessage);
我们引入了onVRMessage函数,用于在场景变化时返回默认缩放。此外,我们还添加了场景更改时的加载器。
function onVRMessage(e) {
switch (e.data.type) {
case 'sceneChanged':
if (window.playerCamera.zoom != 1) {
window.playerCamera.zoom = 1;
window.playerCamera.updateProjectionMatrix();
}
break;
case 'sceneLoadStart':
document.getElementById('loader').style.display = 'block';
break;
case 'sceneLoadEnd':
document.getElementById('loader').style.display = 'none';
break;
default:
return;
}
}
onRendererDoubleClick
函数,用于计算 3D 坐标并向 vr 组件发送消息以更改箭头坐标。 get3DPoint
函数是我们的 web VR 应用程序自定义的,如下所示:
function onRendererDoubleClick(){
var x = 2 * (event.x / window.innerWidth) - 1;
var y = 1 - 2 * ( event.y / window.innerHeight );
var coordinates = get3DPoint(window.playerCamera, x, y);
vr.rootView.context.worker.postMessage({ type: "newCoordinates", coordinates: coordinates });
}
切换到鼠标滚轮
我们使用 onRendererMouseWheel
功能将缩放切换为鼠标滚轮。
function onRendererMouseWheel(){
if (event.deltaY > 0 ){
if(window.playerCamera.zoom > 1) {
window.playerCamera.zoom -= 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
else {
if(window.playerCamera.zoom < 3) {
window.playerCamera.zoom += 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
}
导出坐标
然后我们利用 Three.js 处理 3D 图形。在这个文件中,我们只传达了一个功能,将屏幕坐标导出到世界坐标。
import * as THREE from 'three';
export function get3DPoint(camera,x,y){
var mousePosition = new THREE.Vector3(x, y, 0.5);
mousePosition.unproject(camera);
var dir = mousePosition.sub(camera.position).normalize();
return dir;
}
在 Github 此处查看并下载整个 client.js 文件。 cameraHelper.js 文件的工作原理可能不需要解释,因为它非常简单,您也可以下载它。
此外,如果您对类似的项目估算或有关 ReactVR 开发的相同附加技术细节感兴趣 - 您可以找到一些信息 here: