本教程是React Hooks系统教程中的一部分。
Vue是非常优秀的能实现双向数据绑定的前端框架,可极大提高开发效率。与在 React 中集成 jquery及原生javascript编写的组件一样。React 中也可集成vue。
这里我们通过一个 React+Vue 实现的登录页面为例,介绍如何将二者结合使用。
最终效果如下:
React 手动配置 webpack 和 Babel
vue 中使用 v-on/v-model/v-bind 等自定义html属性,这些属性无法通过Babel的验证检查,如下所示:
通过 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 访问,效果如下图所示: