React Hooks入门教程九:在React中集成使用Vue实现数据双向绑定,手动配置Webpack和Babel


发布者 ourjs  发布时间 1594214124726
关键字 JavaScript  前端  react hooks  vue 

本教程是React Hooks系统教程中的一部分。

Vue是非常优秀的能实现双向数据绑定的前端框架,可极大提高开发效率。与在 React 中集成 jquery及原生javascript编写的组件一样。React 中也可集成vue。

这里我们通过一个 React+Vue 实现的登录页面为例,介绍如何将二者结合使用。

最终效果如下:

React 手动配置 webpack 和 Babel

vue 中使用 v-on/v-model/v-bind 等自定义html属性,这些属性无法通过Babel的验证检查,如下所示:

react-vue-0.png

通过 create-react-app 创建的项目,无法精细地控制 webpack 和 babel 的配置,因此需要我们自己在 React 项目中手动配置 webpack 和 Babel,允许在JSX中添加vue的自定义属性。此方法同样适用在React中添加SVG等命名空间。

配置 package.json

在项目中自定义 package.json,添加 webpack/ babel/ vue/ css编辑器等信赖,并基于 webpack 创建 start / debug / build 脚本。

{
  "scripts": {
    "start": "webpack-dev-server",
    "debug": "webpack --mode=development",
    "build": "webpack --mode=production"
  },
  "devDependencies": {
    "webpack-cli": "^3.3.12"
  },
  "dependencies": {
    "@babel/core": "^7.10.4",
    "@babel/preset-env": "^7.10.4",
    "@babel/preset-react": "^7.10.4",
    "babel-loader": "^8.1.0",
    "css-loader": "^3.6.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "style-loader": "^1.2.1",
    "vue": "^2.6.11",
    "webpack": "^4.43.0",
    "webpack-dev-server": "^3.11.0"
  }
}

配置 webpack.config.js

创建 webpack.config.js,定义入口/输出文件,并配置 babel 对 js 进行预处理,支持 import css 文件等。

const path = require('path');

module.exports = {
  entry: './src/index.js', // relative path
  output: {
    path: path.join(__dirname, 'public'), // absolute path
    filename: 'bundle.js' // file name
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
      /*
      //启用 scss,需要安装 sass-loader
      ,{
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      }
      */
    ]
  },
  //devtool: 'cheap-module-eval-source-map',
  devServer: {
    contentBase: path.join(__dirname, 'public')
  }
};

配置 .babelrc.json

创建 .babelrc.json 文件,添加 throwIfNamespace: false,即允许 vue 自定义属性。

{
  "presets": [
    "@babel/preset-env",
    ["@babel/preset-react", {
      "throwIfNamespace": false
    }]
  ]
}

编写 public/index.html

创建 public/index.html 文件,引入 webpack 中配置的出口文件bundle.js。这里为了编写界面方便,也引入了 public/bootstrap.min.css。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>React App</title>
    <link rel="stylesheet" href="./bootstrap.min.css" />
  </head>
  <body>
    <div id="root"></div>

    <script src="./bundle.js"></script>
  </body>
</html>

编写 src/index.js

此为 js 入口文件,引入 App.js 登录模块。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
    <div className="App">
      <App/>
    </div>
  , document.getElementById('root')
);

编写 src/App.js

登录模块的代码,这里使用 jsx 生成DOM,然后使用 useEffect 在DOM生成后初始化 vue,实现数据绑定。

import React, { useEffect } from 'react';
import Vue from 'vue/dist/vue.js';

import './App.css';

let loginInfo = {
  title: 'Login',
  username: '',
  password: '',
  logged: false
};

function login() {
  loginInfo.title = 'Logging in'

  setTimeout(()=>{
    if (loginInfo.username == 'admin' && loginInfo.password == '1234') {
      loginInfo.title = 'Logged'
      loginInfo.logged = true
      return
    }

    loginInfo.title = 'Username or password error'
  }, 1000)
}

function logout() {
  loginInfo.title = 'Logout'
  loginInfo.logged = false
}

function initVue() {
  new Vue({
    el      : '#loginForm',
    data    : loginInfo,
    methods : { login, logout }
  })
}

function App() {
  useEffect(initVue, []);

  return (
    <form className="form-horizontal" id="loginForm">
      <div className="form-group">
        <h3 className="text-center" v-text="title"></h3>
      </div>
      <div v-if="!logged">
        <div className="form-group">
          <label className="col-sm-2 control-label">Username</label>
          <div className="col-sm-10">
            <input v-model="username" type="text" className="form-control" placeholder="Username: admin" />
          </div>
        </div>
        <div className="form-group">
          <label for="inputPassword3" className="col-sm-2 control-label">Password</label>
          <div className="col-sm-10">
            <input v-model="password" type="password" className="form-control" placeholder="Password: 1234" />
          </div>
        </div>
        <div className="form-group">
          <div className="col-sm-offset-2 col-sm-10">
            <div className="checkbox">
              <label>
                <input type="checkbox"/> Remember me
              </label>
            </div>
          </div>
        </div>
        <div className="form-group">
          <div className="col-sm-offset-2 col-sm-10">
            <a v-on:click="login" className="btn btn-default">Login</a>
          </div>
        </div>
      </div>
      <div v-if="logged">
        <div className="text-center">
          <a v-on:click="logout" className="btn btn-primary">Logout</a>
        </div>
      </div>
    </form>
  )
};

export default App;

编写 src/App.css,添加一些样式:

form {
  margin: 64px auto;
  width: 480px;
  padding: 32px;
  background: #efefef;
  border-radius: 12px;
}

编绎项目

文件创建完之后,先通过 yarn 或 npm 安装依赖。

yarn install
//或
npm install

然后可通过 npm start 或 npm run start 启动调试项目

与 create-react-app 生成的 react 不一样,webpack 默认使用的端口为 8080,

可通过 http://localhost:8080 访问,效果如下图所示:

react-vue-1.png

源文件地址: http://ourjs.com/oncedoc?dir=demo/react-vue