美文网首页
react-native在web中的应用

react-native在web中的应用

作者: MasterPaul | 来源:发表于2020-10-16 11:32 被阅读0次

    如果你跟我一样是从APP开发转的react-native,没有写过html的经验,但是想把你的项目在web上运行,或者有一些html的需求,比如分享APP的某个页面,那么这个库react-native-web可以帮助到你。
    附上github地址
    https://github.com/necolas/react-native-web

    现在已经有很多rn的第三方组件都已经支持了web端,比如react-navigation
    https://reactnavigation.org/docs/getting-started
    蚂蚁金服的UI库antd
    https://rn.mobile.ant.design/docs/react/introduce-cn

    在使用之前,需要先学习一下webpack的知识

    下面说步骤
    1、新建一个空的RN项目,我的RN版本是0.63.3,修改package.json,已经加入了mobx相关依赖

    {
      "name": "rn_web01",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "android": "react-native run-android",
        "ios": "react-native run-ios",
        "start": "react-native start",
        "test": "jest",
        "lint": "eslint .",
        "server": "webpack-dev-server --config web/webpack.config.js --port 8090 --open "
      },
      "dependencies": {
        "react": "16.13.1",
        "react-dom": "^16.14.0",
        "react-native": "0.63.3",
        "react-native-web": "^0.14.3"
      },
      "devDependencies": {
        "@babel/core": "^7.10.2",
        "@babel/plugin-proposal-class-properties": "^7.10.1",
        "@babel/plugin-proposal-decorators": "^7.2.3",
        "@babel/plugin-transform-runtime": "^7.2.0",
        "@babel/preset-env": "^7.10.3",
        "@babel/preset-react": "^7.10.1",
        "@babel/preset-stage-0": "^7.8.3",
        "@babel/runtime": "^7.10.2",
        "@react-native-community/eslint-config": "^1.1.0",
        "assets-webpack-plugin": "^5.0.2",
        "babel-jest": "^26.0.1",
        "babel-loader": "^8.1.0",
        "copy-webpack-plugin": "^6.0.2",
        "css-loader": "^3.6.0",
        "eslint": "^7.2.0",
        "file-loader": "^6.0.0",
        "http-proxy-middleware": "^1.0.4",
        "jest": "^26.0.1",
        "metro-react-native-babel-preset": "^0.59.0",
        "react-test-renderer": "16.11.0",
        "style-loader": "^1.2.1",
        "url-loader": "^4.1.0",
        "webpack": "^4.43.0",
        "webpack-cli": "^3.3.12",
        "webpack-dev-server": "^3.11.0",
        "webpack-node-externals": "^1.7.2"
      },
      "jest": {
        "preset": "react-native"
      }
    }
    
    

    2、新建web入口index.web.js文件

    /**
     * @format
     */
    
    import {AppRegistry} from 'react-native';
    import App from './src/App';
    // import App from './src/Router'
    import {name as appName} from './app.json';
    
    AppRegistry.registerComponent(appName, () => App);
    
    AppRegistry.runApplication(appName,{
        initialProps:{},
        rootTag:document.getElementById('root')
    })
    
    

    3、新建web目录
    目录结构如下


    image.png

    其中web->public->index.html代码如下,fastclick是antd库需要的,不需要的话可以不加

    <!DOCTYPE html>
    <html lang="en" style="height:100%">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>rn-web-demo</title>
        <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
        <script>
    
            if ('addEventListener' in document) {
                document.addEventListener('DOMContentLoaded', function() {
                    FastClick.attach(document.body);
                }, false);
            }
    
    
            if(!window.Promise) {
                document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
            }
    
        </script>
    </head>
    <body style="height:100%;touch-action: none">
    <div id='root' style="display:flex;height:100%">
    </div>
    <script type="text/javascript" src="main.bundle.js"></script>
    </body>
    </html>
    
    

    webpack.config.js代码如下

    const webpack = require('webpack')
    const path = require('path');
    const appDirectory = path.resolve(__dirname, '../')
    const CopyPlugin = require('copy-webpack-plugin')
    
    
    const babelLoaderConfiguration = {
        test: /(\.jsx|\.js)$/,
        include: [
            path.resolve(appDirectory, 'src'),
            path.resolve(appDirectory, 'index.web.js'),
        ],
        use: {
            loader: 'babel-loader',
            options: {
                cacheDirectory: false,
                presets: ["@babel/preset-env", "@babel/preset-react", "module:metro-react-native-babel-preset"],
                plugins: [
                    ["@babel/plugin-proposal-decorators", { "legacy": true }],
                    [require("@babel/plugin-proposal-class-properties"), { "loose": false }],
                ]
            },
        },
    
    }
    const imageLoaderConfiguration = {
        test: /\.(gif|jpe?g|png|svg)$/,
        use: {
            loader: 'url-loader',
            options: {
                limit:1,
                name: '/images/[name].[ext]',
            },
        },
    }
    
    const htmlLoaderConfiguration = {
        test: /\.html$/,
        use: {
            loader: 'html-loader'
        }
    }
    
    const cssLoaderConfiguration = {
        test: /\.css|\.less$/,
        use: ['style-loader',
            'css-loader'],
    }
    
    module.exports = {
        mode: 'development',
        // mode: 'production',
        entry: path.resolve(appDirectory, 'index.web.js'),
        // devtool: 'eval-source-map',
        devtool: 'false',
        output: {
            filename: '[name].bundle.js',
            path: path.resolve(appDirectory, './web/public'),
        },
        devServer: {
            contentBase: path.join(__dirname, 'public'),
            historyApiFallback: true,
            inline: true,
            hot: true,
            progress: true,
            proxy:{
                '/api/*':{
                    target:'https://www.doutuimei.com',
                    changeOrigin:true,
                }
            }
    
        },
    
        module: {
            rules: [
                babelLoaderConfiguration,
                cssLoaderConfiguration,
                imageLoaderConfiguration,
                htmlLoaderConfiguration,
            ]
        },
        plugins: [
            // new webpack.HotModuleReplacementPlugin(),
    
            new CopyPlugin({
                patterns:[
                    {
                        from:path.resolve(appDirectory,'src/images') ,
                        to:path.resolve(appDirectory, './web/public/images')
                    }
                ]
            })
        ],
        resolve: {
            extensions: ['.web.js', '.js'],
            alias: {
                'react-native$': 'react-native-web',
            },
        },
        performance: {
            hints: false
        }
    
    }
    
    

    此时已经完成了基本配置,下面可以尝试一下运行了
    src目录下创建App.js文件

    import React from 'react';
    import {
      SafeAreaView,
      StyleSheet,
      ScrollView,
      View,
      Text,
      StatusBar,
        Image
    } from 'react-native';
    
    
    const App: () => React$Node = () => {
      return (
        <View style={styles.container}>
          <Image source={'../images/cat.jpg'} style={{width:100,height:100}}/>
          <Text>Hello,react native web</Text>
        </View>
      );
    };
    
    const styles = StyleSheet.create({
      container:{
        flex:1,justifyContent:'center',alignItems:'center'
      }
    });
    
    export default App;
    
    

    在项目目录中执行yarn server即可在浏览器中打开了,


    image.png

    如果调试好没问题,要上传到服务器,需要先修改webpack.config.js中的mode为production,然后再打包:cd到web目录,输入webpack指令,然后会生成main.bundle.js文件,拷贝src/images文件夹到public/images文件夹


    image.png

    把public文件夹压缩丢给后台就可以了。

    相关文章

      网友评论

          本文标题:react-native在web中的应用

          本文链接:https://www.haomeiwen.com/subject/halzpktx.html