创建react项目

创建react项目有几种方法:

  1. 构建:create-react-app 快速脚手架
  2. 构建:generator-react-webpack  
  3. 构建:webpack一步一步构建

先试试第三种:

 https://www.cnblogs.com/cina33blogs/p/9115294.html

哇!我发现干货~~~~按照下面的操作起来!

第一部

转自https://blog.csdn.net/xw505501936/article/details/80621740

思索良久,决定还是记录下心得体会:一个基于create-react-app官方脚手架,搭建起来的dva开发模式的react项目。

当然现今的前端市场如此强大,你可以在网络上找到你想要的任何脚手架,并且很多可以开箱即用,不可否认它们很优秀,开发它们的人或团队更值得我们竖起大拇指,为他们点赞!比较适合国人还是阿里系的一套react开发脚手架,dva-cli,antd,Umi等,当然gitHub上也有诸多优秀的脚手架,有兴趣的同学可以自行查阅学习。

这里,仅仅以react官方脚手架开启项目,安装采用dva方式的,构建项目,展示记录过程中遇到的各种点和Keng,若你也遇到类似问题,也许能帮上你。

1 安装create-react-app(鉴于国内网络以下使用cnpm,具体配置网上可找大量资料)

cnpm i create-react-app -g
2 创建项目,目录名project

create-react-app project
等待命令执行完成,脚手架会为你安装好基础的组件包,目录生成完毕如下:

这就是脚手架标准目录,我们再来看下package.json文件如下:

{
  "name": "project",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.4.0",
    "react-dom": "^16.4.0",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
如上所示,很干净的目录。

此时已可运行npm start运行起来项目了,默认端口3000,效果如图:

注意scripts执行命令中有一个eject,意为弹射暴露出所有配置,其实脚手架还是为我们封装了一些东西的,这里我们就暴露出所有配置吧。

运行npm run eject,一旦选择eject,那么所封装的组件依赖和项目结构会有所变化,如图:

我们打开package.json文件如下所示,是暴露出的依赖配置项,可以看到已经为我们安装好webpack,babel,eslint等:

{
  "name": "project",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "autoprefixer": "7.1.6",
    "babel-core": "6.26.0",
    "babel-eslint": "7.2.3",
    "babel-jest": "20.0.3",
    "babel-loader": "7.1.2",
    "babel-preset-react-app": "^3.1.1",
    "babel-runtime": "6.26.0",
    "case-sensitive-paths-webpack-plugin": "2.1.1",
    "chalk": "1.1.3",
    "css-loader": "0.28.7",
    "dotenv": "4.0.0",
    "dotenv-expand": "4.2.0",
    "eslint": "4.10.0",
    "eslint-config-react-app": "^2.1.0",
    "eslint-loader": "1.9.0",
    "eslint-plugin-flowtype": "2.39.1",
    "eslint-plugin-import": "2.8.0",
    "eslint-plugin-jsx-a11y": "5.1.1",
    "eslint-plugin-react": "7.4.0",
    "extract-text-webpack-plugin": "3.0.2",
    "file-loader": "1.1.5",
    "fs-extra": "3.0.1",
    "html-webpack-plugin": "2.29.0",
    "jest": "20.0.4",
    "object-assign": "4.1.1",
    "postcss-flexbugs-fixes": "3.2.0",
    "postcss-loader": "2.0.8",
    "promise": "8.0.1",
    "raf": "3.4.0",
    "react": "^16.4.0",
    "react-dev-utils": "^5.0.1",
    "react-dom": "^16.4.0",
    "resolve": "1.6.0",
    "style-loader": "0.19.0",
    "sw-precache-webpack-plugin": "0.11.4",
    "url-loader": "0.6.2",
    "webpack": "3.8.1",
    "webpack-dev-server": "2.9.4",
    "webpack-manifest-plugin": "1.3.2",
    "whatwg-fetch": "2.0.3"
  },
  "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom"
  },
  "jest": {
    "collectCoverageFrom": [
      "src/**/*.{js,jsx,mjs}"
    ],
    "setupFiles": [
      "<rootDir>/config/polyfills.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/__tests__/**/*.{js,jsx,mjs}",
      "<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
    ],
    "testEnvironment": "node",
    "testURL": "http://localhost",
    "transform": {
      "^.+\\.(js|jsx|mjs)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
      "^(?!.*\\.(js|jsx|mjs|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
    },
    "transformIgnorePatterns": [
      "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$"
    ],
    "moduleNameMapper": {
      "^react-native$": "react-native-web"
    },
    "moduleFileExtensions": [
      "web.js",
      "js",
      "json",
      "web.jsx",
      "jsx",
      "node",
      "mjs"
    ]
  },
  "babel": {
    "presets": [
      "react-app"
    ]
  },
  "eslintConfig": {
    "extends": "react-app"
  }
}
此处我本地更改下3000端口为9999,避免与其他本地项目冲突,安装cross-env:

cross-env:运行跨平台设置和使用环境变量的脚本(转https://www.jianshu.com/p/e8ba0caa6247

cnpm i cross-env
修改start命令为:

- "start": "node scripts/start.js",
+ "start": "cross-env PORT=9999 node scripts/start.js",
然后启动:npm start 效果如图:

3 安装dva库(dva也有自己的脚手架dva-cli,也可快速构建项目,目前已升至2.x版本,采用react-router@4.x路由版本)

cnpm i dva --save
安装history组件,等会后面会用到,主要做BrowserHistory浏览器历史功能,有兴趣的同学可网上自行学习。

4 改造项目为dva模式(不了解dva的同学可网上自行学习https://www.jianshu.com/p/f7401adce447),在src目录下新建目录:models,services,routes,utils(utils将来存放配置文件和工具方法),如图:

5 路由设计,简单点暂设计为三个demo地址,分别如下:

(1)http://localhost:9999/aaa

(2)http://localhost:9999/aaa/bbb

(3)http://localhost:9999/ccc

6 组件设计,在routes目录下新建三个文件:AAA.js BBB.js CCC.js 如图:

代码分别为:

AAA.js

import React, { Component } from 'react';
 
class AAA extends Component {
  render() {
    return (
      <div>
        <p>
          AAA页
        </p>
      </div>
    );
  }
}
 
export default AAA;
BBB.js

import React, { Component } from 'react';
 
class BBB extends Component {
  render() {
    return (
      <div>
        <p>
          BBB页
        </p>
      </div>
    );
  }
}
 
export default BBB;
CCC.js

import React, { Component } from 'react';
 
class CCC extends Component {
  render() {
    return (
      <div>
        <p>
          CCC页
        </p>
      </div>
    );
  }
}
 
export default CCC;
7 model设计,在model下新建四个文件:aaa.js bbb.js ccc.js 和app.js(app作为全局model使用,将来存放全局变量,如国际化参数,登录用户信息等)

代码分别为:

aaa.js

export default {
 
    namespace: 'aaa',
  
    state: {
      name:'这是aaa的model'
    },
  
    subscriptions: {
      
    },
  
    effects: {
      
    },
  
    reducers: {
      
    },
  
  };
bbb.js

export default {
 
    namespace: 'bbb',
  
    state: {
      name:'这是bbb的model'
    },
  
    subscriptions: {
      
    },
  
    effects: {
      
    },
  
    reducers: {
      
    },
  
  };
ccc.js

export default {
 
    namespace: 'ccc',
  
    state: {
      name:'这是ccc的model'
    },
  
    subscriptions: {
      
    },
  
    effects: {
      
    },
  
    reducers: {
      
    },
  
  };
app.js

export default {
 
    namespace: 'app',
  
    state: {
      name:'这是app的model'
    },
  
    subscriptions: {
      
    },
  
    effects: {
      
    },
  
    reducers: {
      
    },
  
  };
8 src目录下创建router.js路由控制文件,其中menuGlobal后期会提出到配置文件中,此处暂先这样放便于查看,大家发现其中也定义了id,pid,name,icon等字段,这些并不是dva路由必须字段,没错这些事自定义的字段,将来会用到,菜单关系,菜单是否显示,和icon图标等

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import dynamic from 'dva/dynamic'
 
const menuGlobal=[
  {
      id:'aaa',
      pid:'0',
      name:'aaa页',
      icon:'user',
      path: '/aaa',
      models: () => [import('./models/aaa')], //models可多个
      component: () => import('./routes/AAA'),
  }, 
  {
      id:'bbb',
      pid:'0',
      name:'bbb页',
      icon:'user',
      path: '/aaa/bbb',
      models: () => [import('./models/bbb')], //models可多个
      component: () => import('./routes/BBB'),
  }, 
  {
      id:'ccc',
      pid:'0',
      name:'ccc页',
      icon:'user',
      path: '/ccc',
      models: () => [import('./models/ccc')], //models可多个
      component: () => import('./routes/CCC'),
  }, 
];
 
function RouterConfig({ history, app }) {
 
  return (
    <Router history={history}>
      <Switch>
        {
          menuGlobal.map(({path,...dynamics},index)=>(
            <Route
              key={index} 
              path={path} 
              exact 
              component={dynamic({
                app,
                ...dynamics
              })} 
            />
          ))
        }
      </Switch>
    </Router>
  );
}
 
export default RouterConfig;
9 修改src目录下index.js入口文件:

import dva from 'dva';
import './index.css';
import createHistory from 'history/createBrowserHistory'
 
// 1. Initialize
const app = dva({
    history:createHistory()
});
 
// 2. Plugins
// app.use({});
 
// 3. Model
app.model(require('./models/app').default);
 
// 4. Router
app.router(require('./router').default);
 
// 5. Start
app.start('#root');
 
 

至此,dva的改造基本完毕,后续还有其他的细节补充,运行起来吧:npm start

效果如图:

试试看,基本的路由已经OK了,接下来,我们将进行对以上主体构造的细节坐下补充。

此处路由只是通过浏览器地址栏直接访问的形式,我们还需要增加路由跳转<Link>

(1)AAA.js中引入import { Link } from 'dva/router'; 并增加跳转链接如下:

import React, { Component } from 'react';
import { Link } from 'dva/router';
 
class AAA extends Component {
  render() {
    return (
      <div>
        <p>
          AAA页
        </p>
        <Link to={'/aaa/bbb'}>去BBB页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>
      </div>
    );
  }
}
 
export default AAA;
(1)BBB.js中引入import { Link } from 'dva/router'; 并增加跳转链接如下:

import React, { Component } from 'react';
import { Link } from 'dva/router';
 
class BBB extends Component {
  render() {
    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>
      </div>
    );
  }
}
 
export default BBB;
(1)CCC.js中引入import { Link } from 'dva/router'; 并增加跳转链接如下:

import React, { Component } from 'react';
import { Link } from 'dva/router';
 
class CCC extends Component {
  render() {
    return (
      <div>
        <p>
          CCC页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/aaa/bbb'}>去BBB页面</Link>
      </div>
    );
  }
}
 
export default CCC;
此时页面中已有链接,三个页面可相互跳转了。

现在我们将router.js中的menuGlobal提出,放于公用文件中,首先在utils下新建文件config.js和index.js 代码分别如下:

config.js文件:

const menuGlobal=[
    {
        id:'aaa',
        pid:'0',
        name:'aaa页',
        icon:'user',
        path: '/aaa',
        models: () => [import('../models/aaa')], //models可多个
        component: () => import('../routes/AAA'),
    }, 
    {
        id:'bbb',
        pid:'0',
        name:'bbb页',
        icon:'user',
        path: '/aaa/bbb',
        models: () => [import('../models/bbb')], //models可多个
        component: () => import('../routes/BBB'),
    }, 
    {
        id:'ccc',
        pid:'0',
        name:'ccc页',
        icon:'user',
        path: '/ccc',
        models: () => [import('../models/ccc')], //models可多个
        component: () => import('../routes/CCC'),
    }, 
  ];
  
export default {
    menuGlobal
}
index.js文件(之后utils中的配置文件,均可在index.js暴露出去):

import config from './config';
 
export {
    config
}
修改src下的router.js文件,如下:

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import dynamic from 'dva/dynamic'
 
import {config} from './utils'
const { menuGlobal } = config
 
function RouterConfig({ history, app }) {
 
  return (
    <Router history={history}>
      <Switch>
        {
          menuGlobal.map(({path,...dynamics},index)=>(
            <Route
              key={index} 
              path={path} 
              exact 
              component={dynamic({
                app,
                ...dynamics
              })} 
            />
          ))
        }
      </Switch>
    </Router>
  );
}
 
export default RouterConfig;
刷新页面即可,之所以把menu提出配置文件中,便于管理和后期拓展。

 

第二部

转自https://blog.csdn.net/xw505501936/article/details/80625613

先来看下现有项目:

点击 去BBB页面 如下:

点击 去CCC页面 如下:

好,以上是现有项目情况。

下面我们让页面稍微美观一些,引入UI库,这里依然选用阿里系的antd(具体不做介绍,有兴趣的同学可官网查阅,此UI库也有针对angular的版本,也有mobile移动版,还有自己的antd脚手架,很优秀的UI库哦)

1 安装antd

cnpm i antd --save
修改AAA.js文件:

import React, { Component } from 'react';
import { Link } from 'dva/router';
import { Button } from 'antd';
 
class AAA extends Component {
  render() {
    return (
      <div>
        <p>
          AAA页
        </p>
        <Link to={'/aaa/bbb'}>
          <Button type={'primary'} icon={'link'}>
            去BBB页面
          </Button>
        </Link>
        <br />
        <Link to={'/ccc'}>
          <Button type={'default'} icon={'enter'}>
            去CCC页面
          </Button>
        </Link>
      </div>
    );
  }
}
 
export default AAA;
 

然后运行npm start,不出意外,会按预期出现按钮形态的页面,好我们刷新页面:

 

为什么没有样式?

不要着急,使用antd的时候,还需要一些配置的,

2 样式引入,antd官方给出两种引入方式:

(1)全局一次性引入样式

(2)按需加载样式(当然我们最终会使用这种咯)

首页说一下全局一次性引入方式:

在src下的index.css目录中直接@import '~antd/dist/antd.css'; 引入即可,刷新页面如下:

但是这种一次性把样式文件全部引入,对资源的占用和性能消耗不友好,故我们采用按需引用方式。

这里特别说明:按需引入的方式,与之前我们创建create-react-app项目时,是否eject暴露配置不同,也就是没有eject的引入方式和eject过的引入方式有差异;因我们的项目暴露配置了,这里只讲eject过的配置方法,至于未eject的配置方法antd官方有详细说明:https://ant.design/docs/react/use-with-create-react-app-cn

3 安装babel-plugin-import,这是一个用于按需加载组件代码和样式的 babel 插件

cnpm i babel-plugin-import --save //antd按需加载
首先去除index.css中的引入;

然后修改相关配置,有两种方式可处理,二者选其一即可:

(1)package.json文件中找到babel配置项增加如下代码:

"plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": "css"
        }
      ]
    ]
修改完后如图:

此时,重启服务,刷新页面即可看到:

(2)第二种方式需修改config目录下的webpack.config.dev.js和webpack.config.prod.js,切记开发环境和生产环境一并修改了,一遍之后编译打包时,避免不必要错误;

打开文件,搜索babel-loader,找到options添加如下:

以上两种方式均可实现,antd样式的按需引入,觉得OK了吧,NO NO NO,到现在我们引入的都是css,其实我们知道less和sacc才是样式系的王者,没错接下来,快乐的把css替换为less吧(antd官方也推荐使用less方式,便于样式覆盖和主体定义,灵活性可想而知)。

4 less样式配置

同样,此处的配置页分为eject过的项目和未eject的项目两种,后者antd逛网有详细描述可参考,此处只讲本项目中的配置方式,要用less,当然少不了安装less和less-loader了,运行安装:

cnpm i less less-loader --save
默认的脚手架中不支持less的,那我们就要配置咯,打开webpack.config.dev.js和webpack.config.prod.js,记得两者一并修改了;

解决:react项目中,npm run eject之后生成的webpack配置文件只有webpack.config.js和配置less和ant按需加载的问题https://blog.csdn.net/qq_42190134/article/details/88528852

步骤1 找到 .css 修改为 .(css|less)

步骤2 在use中增加代码,引入less-loader:

{
  loader:require.resolve('less-loader'),
  options: { javascriptEnabled: true }
}
如图:

步骤3 修改package.json的babel配置项:

style项可设置为true或者“css”均可

步骤4 修改src下index.css为index.less

步骤5 修改src下index.js中引入的index.css为index.less 如图:

 

至此,重启服务npm start刷新页面:

less配置已经成功。
 

第三部

转自https://blog.csdn.net/xw505501936/article/details/80625626

项目配置到这里之后,接下来就需要处理以下配置了:

国际化
store的数据存储结构
 国际化和store数据结构的设计:

此处采用immutable数据格式(immutable一款很棒的数据操作工具,此处不做详解,有兴趣的同学可自行学习),把数据存于model,同样国际化的判断参数定为: i18n 存于app的model中,取值来源于浏览器的本地缓存localStorage用户若设置了某种语言,则存在这里,用户下次访问系统,也依然能唤起上次所选中的语言,当初次访问时,语言默认先取自浏览器,若依然取不到则默认咱们的中文。

这里我们只实现 中文,英文,繁体 三种语言的国家化即可,因为引用了antd组件库,故此处国际化部分包括两部分,

(1) antd库的国际化,比如antd中的固定组件里的 ‘确定,OK’‘下一页,Next Page’等,antd官网有详细说明

(2) 业务框架自己的国际化,比如“用户名,Username”,“密码,Password”等,这里采用react-intl国际化组件实现

1 安装immutable和react-intl

cnpm i immutable react-intl --save
修改models目录下的app.js中引入import {Map} from 'immutable'; 修改如下:

import {Map} from 'immutable';
 
const initState = Map({
    i18n: 'zh_CN'
})
 
export default {
 
    namespace: 'app',
  
    state:initState,
  
    subscriptions: {
      
    },
  
    effects: {
 
      * changeLang ({
        payload: {value},
        }, { put }) {
            yield put({ type: 'updateLang', payload: {value}});
        },
        
    },
  
    reducers: {
        updateLang (state,{payload:{value}}) {
            return state.set('i18n',value);
        },
    },
  
  };
修改routes目录下BBB.js,如下:

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button} from 'antd'
 
class BBB extends Component {
 
  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }
 
  render() {
    const {i18n} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )
 
    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>
 
        <Row>
          <Col offset={2}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
        </Row>
         
      </div>
    );
  }
}
 
export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(BBB)
以上修改主要功能:

app.js 增加初始语言参数i18n,增加effects和reducers方法,用于接收语言切换的action,并存储选中的key值

BBB.js 增加connect使当前组件接入store数据,增加切换组件,用于点击切换语言,并dispatch一个action给app/changeLang,触发修改修改model数据

效果如图:

到这里,数据层面的流程已经打通,接下来处理国际化逻辑,国际化组件必然放于跟组件或最外层组件包裹,这样全局均可以使用并生效

2 src目录下新建文件locale.js,此组件仅用于接入国际化使用:

import {connect} from 'dva';
import React from 'react';
import { LocaleProvider } from 'antd' //antd国际化组件
import {IntlProvider} from 'react-intl' //业务文案的国际化组件
import {ANT_LANGPACKAGE, LANGPACKAGE} from './locales';
 
 
const Locale=({ children,i18n })=>{
 
  return (
    <LocaleProvider locale={ANT_LANGPACKAGE[i18n]}>
      <IntlProvider
        locale={i18n}
        messages={LANGPACKAGE[i18n]}
      >
        {children}
      </IntlProvider>
    </LocaleProvider>
  );
}
 
export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(Locale)
3 src目录下,新建locales目录,里面新建index.js文件,此目录用于存放所有项目的文案国际化文件

其中index.js代码:

import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
import zgh from 'react-intl/locale-data/zgh';
import en_US_ant from 'antd/lib/locale-provider/en_US';
import zh_CN_ant from 'antd/lib/locale-provider/zh_CN';
import zh_HK_ant from 'antd/lib/locale-provider/zh_TW';
 
const zh_CN={
    "App.username": "用户名",
    "App.password": "密码"
}
const en_US={
    "App.username": "Username",
    "App.password": "Password"
}
const zh_HK={
    "App.username": "用戶名",
    "App.password": "密碼"
}
 
 
addLocaleData([
  ...en, 
  ...zh, 
  ...zgh,
  {locale: "en_US", parentLocale: "en"},
  {locale: "zh_CN", parentLocale: "zh"},
  {locale: "zh_HK", parentLocale: "zgh"},
]);
 
 
 
export const ANT_LANGPACKAGE = {
  en_US: en_US_ant,
  zh_CN: zh_CN_ant,
  zh_HK: zh_HK_ant
}
 
export const LANGPACKAGE = {
  en_US,
  zh_CN,
  zh_HK
}
 
 

此时项目目录如下:

4 修改router.js文件,包裹组件<Locale>

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import dynamic from 'dva/dynamic'
import Locale from './locale'
import {config} from './utils'
const { menuGlobal } = config
 
function RouterConfig({ history, app }) {
 
  return (
    <Locale>
      <Router history={history}>
        <Switch>
          {
            menuGlobal.map(({path,...dynamics},index)=>(
              <Route
                key={index} 
                path={path} 
                exact 
                component={dynamic({
                  app,
                  ...dynamics
                })} 
              />
            ))
          }
        </Switch>
      </Router>
    </Locale>
  );
}
 
export default RouterConfig;


5 修改BBB.js 增加injectIntl国际化的接入,并增加三个示例,两个antd组件 分页和日期,一个业务文案 用户名和密码

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button, Pagination, Calendar} from 'antd'
import { injectIntl } from 'react-intl';
 
class BBB extends Component {
 
  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }
 
  render() {
    const {i18n, intl:{formatMessage}} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )
 
    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>
 
        <Row>
          <Col offset={2} span={10}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
          <Col span={12}>
            <p>{formatMessage({id:'App.username'})}</p>
            <p>{formatMessage({id:'App.password'})}</p>
            <div>
              <Pagination defaultCurrent={1} total={20} showSizeChanger />
              <Calendar fullscreen={false}  />
            </div>
          </Col>
        </Row>
         
      </div>
    );
  }
}
 
export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(injectIntl(BBB))
好了,保存文件,重启运行npm start,跑起来咯!

项目已然OK,但是需知,复杂的项目,国际化文案很庞大,我们需要把翻译文件提出来,不能放于locales/index.js文件中。

6 在locales目录下新建三个目录:en_US zh_CN zh_HK 用于存放翻译文件

7 在中英繁对应目录下创建如下文件:

以zh_CN目录为例

index.js代码:

import App from './app.json'
import Aaa from './aaa.json'
import Bbb from './bbb.json'
 
const document = {
  ...App,
  ...Aaa,
  ...Bbb,
}
 
export default document;
app.json代码:

{
  "App.username": "用户名",
  "App.password": "密码"
}
aaa.json代码:

{
  "Aaa.title": "A标题"
}
bbb.json代码:

{
  "Bbb.title": "B标题"
}
同样zh_HK和en_US目录页一样:

8 修改locales目录下index.js文件:

import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
import zgh from 'react-intl/locale-data/zgh';
import en_US_ant from 'antd/lib/locale-provider/en_US';
import zh_CN_ant from 'antd/lib/locale-provider/zh_CN';
import zh_HK_ant from 'antd/lib/locale-provider/zh_TW';
import zh_CN from './zh_CN';
import en_US from './en_US';
import zh_HK from './zh_HK';
 
addLocaleData([
  ...en, 
  ...zh, 
  ...zgh,
  {locale: "en_US", parentLocale: "en"},
  {locale: "zh_CN", parentLocale: "zh"},
  {locale: "zh_HK", parentLocale: "zgh"},
]);
 
 
export const ANT_LANGPACKAGE = {
  en_US: en_US_ant,
  zh_CN: zh_CN_ant,
  zh_HK: zh_HK_ant
}
 
export const LANGPACKAGE = {
  en_US,
  zh_CN,
  zh_HK
}
 
修改BBB.js文件:

import React, { Component } from 'react';
import {connect} from 'dva';
import { Link } from 'dva/router';
import {Row, Col, Dropdown, Menu, Button, Pagination, Calendar} from 'antd'
import { injectIntl } from 'react-intl';
 
class BBB extends Component {
 
  changeLang=(e)=>{
    const {dispatch} = this.props;
    dispatch({
      type:'app/changeLang',
      payload:{
        value:e.key
      }
    })
  }
 
  render() {
    const {i18n, intl:{formatMessage}} = this.props;
    const menu=(
      <Menu 
        onClick={this.changeLang}
        selectedKeys={[i18n]}
      >
      <Menu.Item key="zh_CN">
        中文
      </Menu.Item>
      <Menu.Item key="en_US">
        英文
      </Menu.Item>
      <Menu.Item key="zh_HK">
        繁体
      </Menu.Item>
    </Menu>
    )
 
    return (
      <div>
        <p>
          BBB页
        </p>
        <Link to={'/aaa'}>去AAA页面</Link>
        <br />
        <Link to={'/ccc'}>去CCC页面</Link>
 
        <Row>
          <Col offset={2} span={10}>
            <Dropdown trigger={['click']} overlay={menu}>
              <Button>{i18n=='zh_CN'?'中文':i18n=='en_US'?'英文':'繁体'}</Button>
            </Dropdown>
          </Col>
          <Col span={12}>
            <p>{formatMessage({id:'App.username'})}</p>
            <p>{formatMessage({id:'App.password'})}</p>
            <p>{formatMessage({id:'Aaa.title'})}</p>
            <p>{formatMessage({id:'Bbb.title'})}</p>
            <div>
              <Pagination defaultCurrent={1} total={20} showSizeChanger />
              <Calendar fullscreen={false}  />
            </div>
          </Col>
        </Row>
         
      </div>
    );
  }
}
 
export default connect(({
  app
})=>({
  i18n:app.get('i18n')
}))(injectIntl(BBB))
OK,重启刷新,查看页面:

项目至此,基础架构已搭建完毕,剩下的就是布局Layout和公用组件components的封装了,比如业务组件转化器,业务组件过滤器等等。

给大家推荐几个常用并且好用的工具,也许对你有帮助,可自行网上查阅资料,研究使用:

path-to-regexp

react-helmet

classnames

moment

目前的项目基础已经形成,可以说非常干净的一个流程,没有复杂化的东西,希望对你有所帮助!

Thank!

 

 

 

 

补充知识:

webpack中loader的使用方法,以及几个常用loader的应用小实例

https://blog.csdn.net/lhjuejiang/article/details/80230419

mkdir 创建文件夹

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值