├── .vscode
└── settings.json
├── src
├── redux
│ ├── actions
│ │ ├── counter.js
│ │ └── userInfo.js
│ ├── middleware
│ │ ├── promiseMiddleware.js
│ │ └── clientMiddleware.js
│ ├── reducers.js
│ ├── store.js
│ └── reducers
│ │ ├── counter.js
│ │ ├── userInfo.js
│ │ └── reduxCommon.js
├── containers
│ ├── Es6
│ │ ├── scss
│ │ │ └── Es6.scss
│ │ └── Es6.js
│ ├── Default
│ │ ├── scss
│ │ │ └── Default.scss
│ │ └── Default.js
│ ├── img
│ │ ├── 1.jpg
│ │ └── 2.jpg
│ ├── UserInfo
│ │ ├── img
│ │ │ └── smiley_0.png
│ │ ├── ui.scss
│ │ ├── UserInfo.css
│ │ └── UserInfo.js
│ ├── Home
│ │ ├── scss
│ │ │ └── Home.scss
│ │ └── Home.js
│ ├── page2
│ │ └── page2.js
│ ├── index.js
│ ├── page3
│ │ └── page3.js
│ ├── page1
│ │ ├── page.scss
│ │ └── page1.js
│ ├── page4
│ │ ├── page.scss
│ │ └── page4.js
│ ├── Counter
│ │ └── Counter.js
│ └── App
│ │ ├── scss
│ │ └── App.scss
│ │ └── App.js
├── components
│ ├── Navbar
│ │ ├── img
│ │ │ └── icon-arrow-left-white.png
│ │ ├── scss
│ │ │ └── Navbar.scss
│ │ └── Navbar.js
│ ├── ListItem
│ │ ├── scss
│ │ │ └── ListItem.scss
│ │ └── ListItem.js
│ ├── index.js
│ └── DefHref
│ │ ├── scss
│ │ └── DefHref.scss
│ │ └── DefHref.js
├── styles
│ └── Common.scss
├── config.js
├── index.js
├── router
│ ├── Bundle.js
│ ├── router.js
│ └── router.scss
├── helpers
│ └── ApiClient.js
├── index.html
└── Common
│ └── Utility.js
├── .gitignore
├── dist
└── api
│ └── user.json
├── public
└── image
│ └── home.png
├── tsconfig.json
├── .babelrc
├── postcss.config.js
├── .github
└── workflows
│ └── main.yml
├── webpack
├── dev.config.js
├── prod.config.js
└── common.config.js
├── readme.md
├── .eslintrc
└── package.json
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/src/redux/actions/counter.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/containers/Es6/scss/Es6.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/containers/Default/scss/Default.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .history/
2 | dist/www/
3 | dist/react/
4 | node_modules/
5 |
--------------------------------------------------------------------------------
/src/redux/middleware/promiseMiddleware.js:
--------------------------------------------------------------------------------
1 | // export default function clientMi
--------------------------------------------------------------------------------
/dist/api/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": " 纺三啦纺三啦",
3 | "intro": " 哈哈!@#哈哈!@#哈哈!@#哈哈!@#"
4 | }
--------------------------------------------------------------------------------
/public/image/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotuni/react-webpack-demo/HEAD/public/image/home.png
--------------------------------------------------------------------------------
/src/containers/img/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotuni/react-webpack-demo/HEAD/src/containers/img/1.jpg
--------------------------------------------------------------------------------
/src/containers/img/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotuni/react-webpack-demo/HEAD/src/containers/img/2.jpg
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true,
4 | "allowJs": true
5 | }
6 | }
--------------------------------------------------------------------------------
/src/containers/UserInfo/img/smiley_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotuni/react-webpack-demo/HEAD/src/containers/UserInfo/img/smiley_0.png
--------------------------------------------------------------------------------
/src/components/Navbar/img/icon-arrow-left-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaotuni/react-webpack-demo/HEAD/src/components/Navbar/img/icon-arrow-left-white.png
--------------------------------------------------------------------------------
/src/components/ListItem/scss/ListItem.scss:
--------------------------------------------------------------------------------
1 | .listItemCss {
2 | padding: 5px;
3 |
4 | .row {
5 | display: flex;
6 |
7 | .name{
8 | flex: 1;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "react",
5 | "stage-0"
6 | ],
7 | "plugins": [
8 | "react-hot-loader/babel",
9 | "transform-decorators-legacy",
10 | "transform-runtime"
11 | ]
12 | }
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('autoprefixer'),
4 | require('postcss-pxtorem')({
5 | rootValue: 37.4,
6 | replace: true,
7 | minPixelValue: 3,
8 | propList: [
9 | '*'
10 | ],
11 | })
12 | ]
13 | };
14 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import ApiClient from '../helpers/ApiClient';
2 | export const ApiInfo = new ApiClient().API;
3 |
4 | export Utility from 'common/Utility';
5 | export Navbar from './Navbar/Navbar';
6 | export DefHref from './DefHref/DefHref';
7 | export ListItem from './ListItem/ListItem';
8 |
9 |
--------------------------------------------------------------------------------
/src/containers/UserInfo/ui.scss:
--------------------------------------------------------------------------------
1 | .a {
2 | width: 100%;
3 | text-align: center;
4 | font-size: 18px;
5 | padding: 10px;
6 | margin: 10px;
7 | display: flex;
8 | color: #222;
9 | justify-content: center;
10 |
11 | .b {
12 | width: 100px;
13 | height: 200px;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/styles/Common.scss:
--------------------------------------------------------------------------------
1 | .btns {
2 | display: flex;
3 |
4 | .btn,
5 | button {
6 | padding: 5px 15px;
7 | text-align: center;
8 | margin: 5px;
9 | }
10 |
11 | .btn {
12 | border: 1px solid #f0c0f0;
13 | border-radius: 5px;
14 | }
15 | }
16 |
17 | .navbar {
18 | margin-top: 40px;
19 | }
20 |
--------------------------------------------------------------------------------
/src/containers/UserInfo/UserInfo.css:
--------------------------------------------------------------------------------
1 | .userInfoCss {
2 | border: 1px solid yellow;
3 | padding: 10px 20px;
4 | }
5 |
6 | .userInfoCss .img01{
7 | width: 100%;
8 | height: 48px;
9 | background-image: url('./img/smiley_0.png');
10 | background-position: center;
11 | background-size: contain;
12 | background-repeat: no-repeat;
13 | }
--------------------------------------------------------------------------------
/src/redux/reducers.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import { routerReducer } from 'react-router-redux';
4 | import counter from 'reducers/counter';
5 | import userInfo from 'reducers/userInfo';
6 | import Common from 'reducers/reduxCommon';
7 |
8 | export default combineReducers({
9 | routing: routerReducer, counter, userInfo, Common
10 | });
11 |
--------------------------------------------------------------------------------
/src/containers/Home/scss/Home.scss:
--------------------------------------------------------------------------------
1 | .homeCss {
2 | position: relative;
3 | width: 100%;
4 | // margin-top: 45px;
5 |
6 | .btns {
7 | margin: 10px;
8 | display: flex;
9 |
10 | > div {
11 | padding: 5px 25px;
12 | text-align: center;
13 | border: 1px solid #eee;
14 | border-radius: 5px;
15 | background: #1438d4;
16 | color: #fff;
17 | margin: 5px;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/redux/actions/userInfo.js:
--------------------------------------------------------------------------------
1 | export const GET_USER_INFO_LOADING = 'userinfo/loading';
2 | export const GET_USER_INFO_SUCCESS = 'userinfo/success';
3 | export const GET_USER_INFO_FAIL = 'userinfo/fail';
4 |
5 | export function getUserInfo() {
6 | return {
7 | types: [GET_USER_INFO_LOADING, GET_USER_INFO_SUCCESS, GET_USER_INFO_FAIL],
8 | promise: (client) => client.get(client.API.UserInfo, { params: { id: 1 }, data: { data: 1234 } })
9 | };
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | const env = {
2 | development: {
3 | // serverApi: 'https://127.0.0.1:30081/webapi',
4 | serverApi: 'https://127.0.0.1:4011/webapi',
5 | isProduction: false
6 | },
7 | production: {
8 | serverApi: 'https://127.0.0.1:30081/webapi',
9 | isProduction: true
10 | }
11 | }[process.env.NODE_ENV || 'development'];
12 |
13 | module.exports = Object.assign({
14 | app: {
15 | BaseName: '/react/',
16 | BuildPath: '/dist/react'
17 | }
18 | }, env);
19 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: GitHub Actions Build and Deploy Demo
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | build-and-deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v3
12 |
13 | - name: Build and Deploy
14 | uses: JamesIves/github-pages-deploy-action@releases/v3
15 | env:
16 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
17 | BRANCH: master
18 | FOLDER: build
19 | BUILD_SCRIPT: npm install && npm run build
20 |
--------------------------------------------------------------------------------
/src/components/DefHref/scss/DefHref.scss:
--------------------------------------------------------------------------------
1 | .defHrefCss {
2 | font-size: 14px;
3 | .groups {
4 | display: flex;
5 | flex-wrap: wrap;
6 | text-align: center;
7 | .urlInfo {
8 | width: 33.33vw;
9 | .url {
10 | padding: 5px;
11 | >div {
12 | padding: 5px 10px; // margin: 5px;
13 | border: 1px solid #a0a0a0a0;
14 | border-radius: 5px;
15 | background: rgba(219, 186, 186, 0.88);
16 | }
17 | }
18 | }
19 | & :nth-of-type(3n) {
20 | margin-right: 0px;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/containers/Default/Default.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { DefHref } from 'components';
3 | const comStyles = require('styles/Common.scss');
4 |
5 | const styles = require('./scss/Default.scss');
6 |
7 | export default class Default extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {};
11 | }
12 |
13 | componentWillMount() {
14 | // const a = 123;
15 | }
16 | render() {
17 | return (
18 |
19 |
20 | 哈哈123
21 |
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/Navbar/scss/Navbar.scss:
--------------------------------------------------------------------------------
1 | .navbarCss {
2 | width: 100.1vw;
3 | height: 40px;
4 | position: fixed;
5 | top: 0;
6 | left: 0;
7 | background: #e6e6e6;
8 | z-index: 99999;
9 | display: flex;
10 | align-items: center;
11 | .left {
12 | padding: 5px;
13 | >div {
14 | height: 25px;
15 | width: 30px;
16 | background-image: url('../img/icon-arrow-left-white.png');
17 | background-position: center;
18 | background-repeat: no-repeat;
19 | background-size: contain;
20 | }
21 | }
22 | .center {
23 | text-align: center;
24 | flex: 1;
25 | font-size: 20px;
26 | color: #222;
27 | }
28 | .right {
29 | padding: 5px;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux';
2 | // import thunkMiddleware from 'redux-thunk';
3 | import reducers from './reducers.js';
4 | import clientMiddleware from './middleware/clientMiddleware.js';
5 |
6 | // let store = createStore(reducers, applyMiddleware(thunkMiddleware));
7 | // export default store;
8 |
9 | import { routerMiddleware } from 'react-router-redux';
10 |
11 | export default function BuildStore(client, history) {
12 | const reduxRouterMiddleware = routerMiddleware(history);
13 | const middleware = [clientMiddleware(client), reduxRouterMiddleware];
14 | const finalCreateStore = applyMiddleware(...middleware)(createStore);
15 | return finalCreateStore(reducers);
16 | }
17 |
--------------------------------------------------------------------------------
/src/redux/reducers/counter.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'counter/INCREMENT';
2 | export const DECREMENT = 'counter/DECREMENT';
3 | export const RESET = 'counter/RESET';
4 |
5 | const initState = { count: 0 };
6 |
7 | export default function reducer(state = initState, action) {
8 | switch (action.type) {
9 | case INCREMENT:
10 | return { ...state, count: state.count + 1 };
11 | case DECREMENT:
12 | return { ...state, count: state.count - 1 };
13 | case RESET:
14 | return { ...state, count: 0 };
15 | default:
16 | return state;
17 | }
18 | }
19 |
20 |
21 | export function increment() {
22 | return { type: INCREMENT };
23 | }
24 | export function decrement() {
25 | return { type: DECREMENT };
26 | }
27 | export function reset() {
28 | return { type: RESET };
29 | }
30 |
--------------------------------------------------------------------------------
/src/redux/reducers/userInfo.js:
--------------------------------------------------------------------------------
1 | import { GET_USER_INFO_LOADING, GET_USER_INFO_SUCCESS, GET_USER_INFO_FAIL } from 'actions/userInfo';
2 |
3 | const initState = {
4 | isLoading: false,
5 | userInfo: {},
6 | errorMsg: '',
7 | };
8 |
9 | export default function reducer(state = initState, action) {
10 | switch (action.type) {
11 | case GET_USER_INFO_FAIL:
12 | return {
13 | ...state, isLoading: false, userInfo: null, errorMsg: '请求错误啦',
14 | };
15 | case GET_USER_INFO_LOADING:
16 | return {
17 | ...state, isLoading: true, userInfo: null, errorMsg: '请求中...',
18 | };
19 | case GET_USER_INFO_SUCCESS:
20 | return {
21 | ...state, isLoading: false, userInfo: action.result, errorMsg: '成功了',
22 | };
23 | default:
24 | return state;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/containers/page2/page2.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Utility } from 'components';
3 | const comStyles = require('styles/Common.scss');
4 |
5 | export default class Page2 extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = { count: 0 };
9 | }
10 |
11 | render() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 | 哈哈这是Page2
19 |
20 | {
21 | this.state.count
22 | }
23 |
24 |
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/containers/index.js:
--------------------------------------------------------------------------------
1 | import cfg from '../config';
2 | const { isProduction } = cfg;
3 |
4 | import App from './App/App';
5 | import Default from './Default/Default';
6 | import page1 from './page1/page1';
7 | import page2 from './page2/page2';
8 | import page3 from './page3/page3';
9 | import page4 from './page4/page4';
10 | import Home from './Home/Home';
11 | import Counter from './Counter/Counter';
12 | import UserInfo from './UserInfo/UserInfo';
13 | import Es6 from './Es6/Es6';
14 |
15 | const obj = {
16 | Default, page1, page2, page3, page4, Home, UserInfo, Es6, Counter
17 | };
18 | if (!!isProduction) {
19 | // 生产环境下使用懒加载方法
20 | Object.keys(obj).forEach((key) => {
21 | try {
22 | obj[key] = require('bundle-loader?lazy&name=[name]!containers/' + key + '/' + key);
23 | } catch (ex) {
24 | console.log(ex);
25 | }
26 | });
27 | }
28 | export default Object.assign(obj, { App });
29 |
--------------------------------------------------------------------------------
/src/containers/page3/page3.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Utility } from 'components';
3 | const comStyles = require('styles/Common.scss');
4 |
5 | export default class Page3 extends Component {
6 | constructor(props) {
7 | super(props);
8 |
9 | this.state = {};
10 | console.log('----page3---', new Date().getTime());
11 | }
12 |
13 | render() {
14 | console.log('----page3--111-', new Date().getTime());
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
{
22 | setTimeout(() => { }, 1000);
23 | }}> aaaaaaaa
24 |
25 | 哈哈这是Page3
26 |
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/redux/middleware/clientMiddleware.js:
--------------------------------------------------------------------------------
1 | export default function clientMiddleware(client) {
2 | return ({ dispatch, getState }) => {
3 | return (next) => (action) => {
4 | if (typeof action === 'function') {
5 | return action(dispatch, getState);
6 | }
7 |
8 | const { promise, types, ...rest } = action; // eslint-disable-line no-redeclare
9 | if (!promise) {
10 | return next(action);
11 | }
12 |
13 | const [REQUEST, SUCCESS, FAILURE] = types;
14 | next({ ...rest, type: REQUEST });
15 |
16 | const actionPromise = promise(client);
17 | actionPromise.then(
18 | (result) => next({ ...rest, result, type: SUCCESS }),
19 | (error) => next({ ...rest, error, type: FAILURE })
20 | ).catch((error) => {
21 | console.error('MIDDLEWARE ERROR:', error);
22 | next({ ...rest, error, type: FAILURE });
23 | });
24 |
25 | return actionPromise;
26 | };
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/Navbar/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | // import { connect } from 'react-redux';
4 | import { Utility } from 'components';
5 | const styles = require('./scss/Navbar.scss');
6 |
7 | export default class Navbar extends Component {
8 | static propTypes = {
9 | Title: PropTypes.string,
10 | }
11 |
12 | constructor(props) {
13 | super(props);
14 | this.state = {};
15 | this.__HandlerOnClickLeft = this.__HandlerOnClickLeft.bind(this);
16 | }
17 |
18 | __HandlerOnClickLeft() {
19 | Utility.$goBack();
20 | }
21 |
22 | render() {
23 | const { Title } = this.props;
24 | return (
25 |
26 |
29 |
{Title || '这是标题'}
30 |
31 |
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/containers/page1/page.scss:
--------------------------------------------------------------------------------
1 | .page1Css {
2 | padding: 0;
3 | .info {
4 | line-height: 2; // background-image: url('./img/0001.jpg');
5 | background-position: center;
6 | background-size: 100% 100%;
7 | background-repeat: no-repeat;
8 | height: 600px;
9 | display: -webkit-box;
10 | -webkit-box-align: center;
11 | -webkit-box-pack: center;
12 | >div {
13 | text-align: center;
14 | color: #e8b801;
15 | margin-top: -68%;
16 | font-weight: bolder;
17 | .a1 {
18 | font-size: 28px;
19 | }
20 | .a2 {
21 | font-size: 16px;
22 | >span {
23 | margin: 0 5px;
24 | }
25 | }
26 | }
27 | }
28 | .row {
29 | display: flex;
30 | margin-bottom: 5px;
31 | border: 1px solid #f0f0f0;
32 | padding: 5px 10px;
33 | }
34 | }
35 |
36 | .page4Css {
37 | position: relative; // .abc {
38 | // .btn {
39 | // padding: 10px;
40 | // border: 1px solid;
41 | // border-radius: 5px;
42 | // }
43 | // }
44 | }
--------------------------------------------------------------------------------
/src/containers/page4/page.scss:
--------------------------------------------------------------------------------
1 | .page1Css {
2 | padding: 0;
3 |
4 | .info {
5 | line-height: 2;
6 | // background-image: url('./img/0001.jpg');
7 | background-position: center;
8 | background-size: 100% 100%;
9 | background-repeat: no-repeat;
10 | height: 600px;
11 | display: -webkit-box;
12 | -webkit-box-align: center;
13 | -webkit-box-pack: center;
14 |
15 | > div {
16 | text-align: center;
17 | color: #e8b801;
18 | margin-top: -68%;
19 | font-weight: bolder;
20 |
21 | .a1 {
22 | font-size: 28px;
23 | }
24 |
25 | .a2 {
26 | font-size: 16px;
27 |
28 | > span {
29 | margin: 0 5px;
30 | }
31 | }
32 | }
33 | }
34 |
35 | .row {
36 | display: flex;
37 | margin-bottom: 5px;
38 | border: 1px solid #f0f0f0;
39 | padding: 5px 10px;
40 | }
41 | }
42 |
43 | .page4Css {
44 | position: relative;
45 | // .abc {
46 | // .btn {
47 | // padding: 10px;
48 | // border: 1px solid;
49 | // border-radius: 5px;
50 | // }
51 | // }
52 | }
53 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { AppContainer } from 'react-hot-loader';
4 | import { Provider } from 'react-redux';
5 | import BuildStore from './redux/store';
6 | import ApiClient from './helpers/ApiClient';
7 | import createHistory from 'history/createBrowserHistory';
8 | const history = createHistory();
9 | const ApiClientStore = BuildStore(new ApiClient(), history);
10 | import getRouter from './router/router';
11 | import { Router } from 'react-router';
12 |
13 | function renderWithHotReload(RootElement) {
14 | ReactDOM.render(
15 |
16 |
17 |
18 | {RootElement}
19 |
20 |
21 | ,
22 | document.getElementById('app')
23 | );
24 | }
25 |
26 | /**
27 | * 初始化
28 | */
29 | renderWithHotReload(getRouter());
30 |
31 | /**
32 | * 热更新
33 | */
34 | if (module.hot) {
35 | module.hot.accept('./router/router', () => {
36 | const getRouter1 = require('./router/router').default;
37 | renderWithHotReload(getRouter1());
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/DefHref/DefHref.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | // import { connect } from 'react-redux';
4 | import { Utility } from 'components';
5 | const styles = require('./scss/DefHref.scss');
6 |
7 | export default class DefHref extends Component {
8 | static propTypes = {
9 | Title: PropTypes.string,
10 | }
11 |
12 | constructor(props) {
13 | super(props);
14 | this.state = {};
15 | }
16 |
17 | __HandlerToJump(url, key) {
18 | const a = key.substring(1, key.length);
19 | if (a) {
20 | Utility.toPage(a);
21 | }
22 | }
23 |
24 | __BuildHrefHtml() {
25 | return Object.keys(Utility.constItem.UrlTitle).map((key, index) => {
26 | const url = Utility.constItem.UrlTitle[key];
27 | return (
28 |
29 |
30 |
31 | {`${index + 1}${url.Title}`}
32 |
33 |
34 |
35 | );
36 | });
37 | }
38 |
39 | render() {
40 | return (
41 |
42 |
43 | {
44 | this.__BuildHrefHtml()
45 | }
46 |
47 |
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/containers/Counter/Counter.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 | import * as cActions from 'reducers/counter';
5 | import { Utility } from 'components';
6 | const comStyles = require('styles/Common.scss');
7 |
8 | @connect((state) => ({ counter: state.counter }), { ...cActions })
9 | export default class Counter extends Component {
10 | static propTypes = {
11 | increment: PropTypes.func,
12 | decrement: PropTypes.func,
13 | reset: PropTypes.func,
14 | }
15 |
16 | constructor(props) {
17 | super(props);
18 | this.state = {};
19 | }
20 |
21 | render() {
22 | const { increment, decrement, reset } = this.props;
23 | return (
24 |
25 |
26 |
27 |
28 |
29 |
当前计数为(显示redux计数):
30 |
31 |
35 | ___
36 |
37 |
41 | ___
42 |
46 |
47 |
48 |
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/router/Bundle.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React, { Component } from 'react';
3 | // import { connect } from 'react-redux';
4 | import { Utility, Navbar } from 'components';
5 |
6 | class Bundle extends Component {
7 | static propTypes = {
8 | load: PropTypes.any,
9 | isProduction: PropTypes.bool,
10 | children: PropTypes.any,
11 | location: PropTypes.any,
12 | }
13 | constructor(props) {
14 | super(props);
15 | this.state = {
16 | mod: null // short for "module" but that's keyword in js,so "mod"
17 | };
18 | }
19 |
20 | componentWillMount() {
21 | this.load(this.props);
22 | }
23 |
24 | componentWillReceiveProps(nextProps) {
25 | if (nextProps.load !== this.props.load) {
26 | this.load(nextProps);
27 | }
28 | }
29 |
30 | getTitle() {
31 | const title = Utility.getContent('__URL_TITLE_INFO_');
32 | if (title) {
33 | return title.Title;
34 | }
35 | return '默认标题';
36 | }
37 |
38 | load(props) {
39 | const { load, isProduction } = props;
40 | if (!!isProduction) {
41 | this.setState({ mod: null });
42 | props.load((mod) => {
43 | // handle both es import and cjs
44 | this.setState({ mod: mod.default ? mod.default : mod });
45 | });
46 | } else {
47 | this.setState({ mod: load });
48 | }
49 | }
50 |
51 | render() {
52 | return (
53 |
54 |
55 | {
56 | this.props.children(this.state.mod)
57 | }
58 |
59 | );
60 | }
61 | }
62 |
63 | export default Bundle;
64 |
--------------------------------------------------------------------------------
/webpack/dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const merge = require('webpack-merge');
3 | const CommCfg = require('./common.config.js');
4 | const APP_PATH = path.join(__dirname, '..');
5 | const AppCfg = require('../src/config');
6 |
7 | const devConfig = {
8 | devtool: 'inline-source-map',
9 | entry: {
10 | app: [
11 | 'react-hot-loader/patch',
12 | path.join(APP_PATH, 'src/index.js')
13 | ]
14 | },
15 | output: {
16 | filename: '[name].[hash].js',
17 | },
18 | module: {
19 | rules: [
20 | { test: /\.css$/, use: ['style-loader', 'css-loader'] },
21 | {
22 | test: /\.scss$/,
23 | use: [
24 | { loader: 'style-loader' },
25 | {
26 | loader: 'css-loader', options: {
27 | sourceMap: true, modules: true,
28 | localIdentName: '[local]_[hash:base64:5]'
29 | }
30 | },
31 | {
32 | loader: 'postcss-loader',
33 | options: {
34 | sourceMap: true,
35 | config: {
36 | path: 'postcss.config.js'
37 | }
38 | }
39 | },
40 | {
41 | loader: 'sass-loader', options: { sourceMap: true }
42 | }
43 | ]
44 | }
45 | ]
46 | },
47 | devServer: {
48 | port: 11111,
49 | // contentBase: path.join(__dirname, '..', './react'),
50 | historyApiFallback: { index: AppCfg.app.BaseName }, // 解决进行非默认页面,刷新报404问题。
51 | host: '0.0.0.0'
52 | },
53 | };
54 |
55 | const mergeCfg = merge({
56 | customizeArray(a, b, key) {
57 | /**
58 | * entry.app不合并,全替换
59 | */
60 | if (key === 'entry.app') {
61 | return b;
62 | }
63 | return undefined;
64 | }
65 | })(CommCfg, devConfig);
66 |
67 | module.exports = mergeCfg;
68 |
--------------------------------------------------------------------------------
/src/router/router.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { BrowserRouter as Router, Route } from 'react-router-dom';
3 | // import { connect } from 'react-redux';
4 | import pageComponent from 'containers';
5 | const {
6 | App, Default, UserInfo, Counter, Home, page1, page2, page3, page4, Es6,
7 | } = pageComponent;
8 | const AppCfg = require('../config');
9 | const { isProduction } = AppCfg;
10 | import Bundle from './Bundle';
11 |
12 | const Loading = () => {
13 | return 加载中...
;
14 | };
15 | // args = {history, location, match} 三个参数
16 | const CreateComponent = (component) => (args) => (
17 |
18 | {
19 | (Component) => Component ? :
20 | }
21 |
22 | );
23 |
24 | const getRouters = () => (
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 |
41 | export default getRouters;
42 |
43 | //
44 | //
45 | //
46 | //
47 | //
48 | //
49 | //
50 | //
51 | //
52 |
--------------------------------------------------------------------------------
/webpack/prod.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | // 清空打包目录
4 | const CleanWebpackPlugin = require('clean-webpack-plugin');
5 | // 代码丑化
6 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
7 | // 抽取css
8 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
9 | const merge = require('webpack-merge');
10 | const CommCfg = require('./common.config.js');
11 |
12 | const AppCfg = require('../src/config');
13 | const APP_PATH = path.join(__dirname, '..');
14 | // const AppCfg = CommCfg.AppCfg;
15 | // console.log('-----CommCfg---------');
16 | // console.log(AppCfg);
17 | // console.log('-----CommCfg---------');
18 |
19 | const proCfg = {
20 | // devtool: 'cheap-module-source-map',
21 | devtool: 'source-map',
22 | module: {
23 | rules: [
24 | { test: /\.css$/, use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }) },
25 | {
26 | test: /\.scss$/,
27 | use: ExtractTextPlugin.extract({
28 | fallback: 'style-loader',
29 | use: [
30 | {
31 | loader: 'css-loader', options: {
32 | sourceMap: true, minimize: true, modules: true,
33 | localIdentName: '[local]_[hash:base64:5]'
34 | }
35 | },
36 | {
37 | loader: 'postcss-loader',
38 | options: { sourceMap: true, config: { path: 'postcss.config.js' } }
39 | },
40 | {
41 | loader: 'sass-loader', options: { sourceMap: true }
42 | }]
43 | })
44 | }
45 | ]
46 | },
47 | plugins: [
48 | // new CleanWebpackPlugin([path.join(APP_PATH, AppCfg.app.BuildPath)]),
49 | new CleanWebpackPlugin([path.join(APP_PATH, AppCfg.app.BuildPath)], { root: APP_PATH }),
50 | new UglifyJSPlugin(),
51 | new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }),
52 | new ExtractTextPlugin({ filename: '[name].[contenthash:5].css', allChunks: true }),
53 | ],
54 | };
55 |
56 | module.exports = merge(CommCfg, proCfg);
57 |
--------------------------------------------------------------------------------
/src/containers/Home/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Utility } from 'components';
4 |
5 | const styles = require('./scss/Home.scss');
6 |
7 | export default class Home extends Component {
8 | static propTypes = {
9 | children: PropTypes.object, // 子项
10 | location: PropTypes.object, // location信息
11 | };
12 | static contextTypes = {
13 | router: PropTypes.object.isRequired,
14 | // history: PropTypes.object,
15 | }
16 |
17 | constructor(props) {
18 | super(props);
19 | this.state = {};
20 | }
21 |
22 | componentWillMount() {
23 | const __key = Utility.constItem.KeyHistory;
24 | if (!Utility.getContent(__key)) {
25 | Utility.setContent(__key, this.context.router.history);
26 | const self = this;
27 | const { UrlTitle } = Utility.constItem;
28 | const __IsGoBackKey = Utility.constItem.KeyGoBack;
29 | this.context.router.history.listen((location, action) => {
30 | Utility.setContent(__IsGoBackKey, action === 'POP');
31 | const { pathname } = location;
32 | if (UrlTitle && UrlTitle[pathname]) {
33 | self.state.UrlTitle = UrlTitle[pathname];
34 | Utility.setContent('__URL_TITLE_INFO_', UrlTitle[pathname]);
35 | }
36 | });
37 | }
38 | }
39 |
40 | componentDidMount() {
41 | this.state.IsMount = true;
42 | }
43 |
44 | componentWillUnmount() {
45 | delete this.state.IsMount;
46 | console.log('-------home-----component Will Umount');
47 | }
48 |
49 | __UpdateRender() {
50 | if (!!this.state.IsMount) {
51 | this.setState({ __CURRENT_TIME_: new Date() });
52 | }
53 | }
54 |
55 | __HandlerJudgPage() {
56 | Utility.toPage('userinfo');
57 | }
58 | render() {
59 | // const { UrlTitle } = this.state;
60 | // const { Title } = UrlTitle || {};
61 | // const __Flag = 0;
62 |
63 | return (
64 |
65 | {}
66 |
67 | );
68 | }
69 | }
70 | // {
71 | // __Flag === 2 &&
72 | // }
73 |
--------------------------------------------------------------------------------
/webpack/common.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const webpack = require('webpack');
4 | const APP_PATH = path.join(__dirname, '..');
5 | const AppCfg = require('../src/config');
6 |
7 | const Config = {
8 | entry: {
9 | app: [path.join(APP_PATH, 'src/index.js')],
10 | vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']
11 | },
12 | output: {
13 | path: path.join(APP_PATH, AppCfg.app.BuildPath),// './dist/react'),
14 | filename: '[name].[chunkhash].js',
15 | chunkFilename: '[name].[chunkhash].js',
16 | publicPath: AppCfg.app.BaseName // '/react/' // 这里必须和router里面写的那个basename要一样。要不能会出问题。
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.js$/,
22 | use: [
23 | 'babel-loader?cacheDirectory=true',
24 | {
25 | loader: 'eslint-loader', options: {}
26 | }
27 | ],
28 | include: path.join(APP_PATH, 'src')
29 | },
30 | {
31 | test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
32 | use: [
33 | {
34 | loader: 'url-loader', options: { limit: 8192 }
35 | }
36 | ]
37 | },
38 | ]
39 | },
40 | resolve: {
41 | alias: {
42 | pages: path.join(APP_PATH, 'src/pages'),
43 | component: path.join(APP_PATH, 'src/component'),
44 | router: path.join(APP_PATH, 'src/router'),
45 | actions: path.join(APP_PATH, 'src/redux/actions'),
46 | reducers: path.join(APP_PATH, 'src/redux/reducers'),
47 | containers: path.join(APP_PATH, 'src/containers'),
48 | components: path.join(APP_PATH, 'src/components'),
49 | common: path.join(APP_PATH, 'src/common'),
50 | styles: path.join(APP_PATH, 'src/styles'),
51 | }
52 | },
53 | plugins: [
54 | new HtmlWebpackPlugin({
55 | filename: 'index.html',
56 | template: path.join(APP_PATH, 'src/index.html')
57 | }),
58 | new webpack.HashedModuleIdsPlugin(),
59 | new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', }),
60 | new webpack.optimize.CommonsChunkPlugin({ name: 'runtime' }), // runtime以及vendor的顺序关系很重要要。
61 | ],
62 | };
63 |
64 | module.exports = Config;
65 |
--------------------------------------------------------------------------------
/src/containers/UserInfo/UserInfo.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 | import { getUserInfo } from 'actions/userInfo';
5 | import { Utility } from 'components';
6 | const comStyles = require('styles/Common.scss');
7 |
8 | require('./UserInfo.css');
9 |
10 | @connect((state) => ({ userInfo: state.userInfo }), { getUserInfo })
11 | export default class UserInfo extends Component {
12 | static propTypes = {
13 | userInfo: PropTypes.object,
14 | getUserInfo: PropTypes.func,
15 | }
16 | static contextTypes = {
17 | router: PropTypes.object.isRequired,
18 | // history: PropTypes.object,
19 | }
20 |
21 | constructor(props) {
22 | super(props);
23 | this.state = {};
24 | this.__HandlerGoBack = this.__HandlerGoBack.bind(this);
25 | }
26 |
27 | __HandlerGoBack() {
28 | Utility.$goBack();
29 | }
30 |
31 | render() {
32 | const styles = require('./ui.scss');
33 | const demoimg = require('./img/smiley_0.png');
34 | const { userInfo, isLoading, errorMsg } = this.props.userInfo;
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 哈哈!!看看了
44 |
45 |
46 |
47 |
54 |
55 |
56 | {errorMsg}
57 |
58 |
59 | {
60 | !isLoading &&
61 |
62 |
用户信息
63 |
用户名称:{userInfo && userInfo.name}
64 |
介绍:{userInfo && userInfo.intro}
65 |
66 | }
67 |
68 |
69 | );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/helpers/ApiClient.js:
--------------------------------------------------------------------------------
1 | import superagent from 'superagent';
2 |
3 | const methods = ['get', 'post', 'put', 'patch', 'del'];
4 | function formatUrl(path) {
5 | const adjustedPath = path[0] !== '/' ? '/' + path : path;
6 | // const _ApiUrl = 'http://127.0.0.1:11111/react/www' + adjustedPath;
7 | const _ApiUrl = 'https://127.0.0.1:30081/webapi' + adjustedPath;
8 | return _ApiUrl;
9 | }
10 |
11 | export default class ApiClient {
12 | API = {
13 | /**
14 | * 通用的方法。
15 | */
16 | Common: {
17 |
18 | },
19 | UserInfo: 'api/user.json',
20 | Users: 'userinfo/users',
21 | MapPlacelist: 'map/placelist',
22 | Demo: 'demo',
23 | }
24 |
25 | constructor() {
26 | const self = this;
27 | methods.forEach((method) =>
28 | self[method] = (path, { params, data } = {}) => new Promise((resolve, reject) => {
29 | const request = superagent[method](formatUrl(path));
30 | if (params) {
31 | request.query(params);
32 | }
33 | if (data) {
34 | request.send(data);
35 | }
36 | request.header.token = 'xtn_21232f297a57a5a743894a0e4a801fc3_c3284d0f94606de1fd2af172aba15bf3';
37 |
38 | /**
39 | * 错误处理及提示
40 | *
41 | * @param {any} err
42 | */
43 | function __ProcessError(err) {
44 | try {
45 | if (err.status) {
46 | console.log(err.status);
47 | } else if (!!err.crossDomain) {
48 | console.log('与服务器连接中断...');
49 | } else if (err.message && err.message !== '') {
50 | console.log(err.message);
51 | }
52 | } catch (ex) {
53 | console.log(ex);
54 | }
55 | }
56 |
57 | function __SendRequest(_request) {
58 | _request.end((err, response) => {
59 | const { body, headers } = response || {};
60 | const { date } = headers || {};
61 | console.log(date);
62 | if (err) {
63 | __ProcessError(err, body, response);
64 | reject(body || err); // reject-->拒绝; resolve-->解决
65 | } else {
66 | if (!body) {
67 | console.log({ status: response.status, msg: '处理成功' });
68 | }
69 | setTimeout(() => {
70 | resolve(body);
71 | }, 1000);
72 | }
73 | });
74 | }
75 |
76 | try {
77 | __SendRequest(request);
78 | } catch (ex) {
79 | console.log(ex);
80 | }
81 | }));
82 | }
83 | empty() {
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # react-webpack-demo
2 |
3 |
4 | ## 关于
5 | 当前项目模版中使用到的技术:
6 |
7 | * [React 16](https://github.com/facebook/react)
8 | * [React Router4](https://github.com/rackt/react-router)
9 | * [React Hot Loader](https://github.com/gaearon/react-hot-loader) 模块热加载
10 | * [Babel](http://babeljs.io) ES6 、ES7 语法转换
11 | * [Webpack3](http://webpack.github.io) 打包工具
12 | * [webpack Dev Server](http://github.com/webpack/webpack-dev-serverl)
13 | * [Redux](https://github.com/rackt/redux)
14 | * [React Router Redux](https://github.com/reactjs/react-router-redux) Redux/React 路由绑定.
15 | * [ESLint](http://eslint.org) 保持一致的代码风格
16 | * [Superagent](https://github.com/visionmedia/superagent) 接口调用
17 | * [bundle-loader](https://github.com/webpack-contrib/bundle-loader) 按需要加载相应页面的JS
18 | * [Postcss Loader](https://github.com/postcss/postcss-loader) 兼容不同浏览器样式加前缀
19 |
20 |
21 | ## 安装
22 | ```bash
23 | npm install
24 | 或者
25 | yarn install
26 | ```
27 |
28 | ## 运行开发环境
29 | ```base
30 | npm run dev
31 | ```
32 | 起来在浏览器上输入:http://127.0.0.1:11111/react; /react这个是可以在config.js里进行配置,这个就是route basename。
33 |
34 | 
35 |
36 | ## 项目打包
37 | ```base
38 | npm run build
39 | ```
40 | 项目打包后,会在项目根目录里生成 dist/www目录,拿到这个就可以进行部署了。
41 |
42 | 如果部署到Nginx里面,如果出现在404的时候,可以参考:[Nginx配置ReactJs项目,Url后面直接输入路由路径时老报404问题。](http://blog.csdn.net/xiaotuni/article/details/77745189)
43 |
44 | ## image 引入
45 | ```
46 | render(){
47 | const image = require('../img/demo.png);
48 | return(
49 |
50 | );
51 | }
52 | ```
53 | ## 样式引入
54 | ```
55 | render(){
56 | const styles = require('./scss/style.scss');
57 | return (
58 | class name
59 | );
60 | }
61 | ```
62 |
63 | ----
64 |
65 | ## 引入scss
66 |
67 | webpack.dev.config
68 | ```code
69 | const styles = require('./demo.scss');
70 |
71 | render(){
72 | return(
73 | content
74 | );
75 | }
76 | ```
77 | ### 配置 url:https://github.com/webpack-contrib/css-loader
78 | ```
79 |
80 | {
81 | test: /\.scss$/,
82 | use: [
83 | { loader: "style-loader" },
84 | {
85 | loader: "css-loader", options: {
86 | sourceMap: true,
87 | modules: true, minimize: true,
88 | localIdentName: '[local]_[hash:base64:5]'
89 | }
90 | },
91 | {loader: "sass-loader", options:{sourceMap:true }}
92 | ]
93 | }
94 | ```
95 |
96 |
97 | ## 参与文献
98 | * [从零搭建React全家桶框架教程](https://github.com/brickspert/blog/issues/1)
99 | * [React Redux Universal Hot Example](https://github.com/erikras/react-redux-universal-hot-example)
100 |
--------------------------------------------------------------------------------
/src/components/ListItem/ListItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Utility } from 'components';
3 | import PropTypes from 'prop-types';
4 |
5 | const styles = require('./scss/ListItem.scss');
6 |
7 | export default class ListItem extends Component {
8 | static propTypes = {
9 | DataSource: PropTypes.array,
10 | onDelete: PropTypes.func,
11 | }
12 |
13 | constructor(props) {
14 | super(props);
15 | this.state = {};
16 | }
17 | componentWillMount() {
18 | console.log('-listitem-1----will mount------');
19 | }
20 | componentDidMount() {
21 | console.log('-listitem-2----did mount------');
22 | }
23 | componentWillReceiveProps(nextProps, nextState) {
24 | const { a } = nextState;
25 | if (a) {
26 | console.log(a);
27 | }
28 | console.log('-listitem-3----will receive props------------');
29 | }
30 | shouldComponentUpdate(nextProps, nextState, nextContext) {
31 | const { a } = nextContext;
32 | if (a) {
33 | console.log(a);
34 | }
35 |
36 | console.log('-listitem-4----should update-----------------');
37 | return true;
38 | }
39 | componentWillUpdate(nextProps, nextState, nextContext) {
40 | const { a } = nextContext;
41 | if (a) {
42 | console.log(a);
43 | }
44 | console.log('-listitem-5----will update-------------');
45 | }
46 | componentDidUpdate(prevProps, prevState) {
47 | const { a } = prevState;
48 | if (a) {
49 | console.log(a);
50 | }
51 | console.log('-listitem-6----did update-----------');
52 | }
53 | componentWillUnmount() {
54 | console.log('-listitem-7----will unmount-----------');
55 | }
56 |
57 | onClickSelectItem(item, index) {
58 | console.log(item);
59 | const { onDelete } = this.props;
60 | if (onDelete) {
61 | onDelete(item, index);
62 | }
63 | }
64 |
65 | componentDidCatch() {
66 | console.log('-listitem-----------did catch-------------');
67 | }
68 |
69 | BuildHtml() {
70 | const { DataSource } = this.props;
71 | if (!Utility.isArray(DataSource)) {
72 | return null;
73 | }
74 | return DataSource.map((item, index) => {
75 | const { CurrentDate } = item;
76 | return (
77 |
{item.id}
78 |
{item.Name}
79 |
{CurrentDate.toLocaleDateString() + ' ' + CurrentDate.toLocaleTimeString()}
80 |
);
81 | });
82 | }
83 |
84 | render() {
85 | return (
86 |
87 | {
88 | this.BuildHtml()
89 | }
90 |
91 | );
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/router/router.scss:
--------------------------------------------------------------------------------
1 | $top-hight:0;// 40px;
2 |
3 | .com {
4 | background: #fff;
5 | position: fixed;
6 | top: $top-hight; //bottom:50px; 去掉是因为界面最下面老是会跳的效果,改为下面这种
7 | // padding-bottom: 50px;
8 | bottom: 0;
9 | left: 0;
10 | right: 0;
11 | }
12 |
13 | .__spEnter {
14 | @extend .com;
15 | transform: translate3d(100%, 0, 0);
16 | }
17 |
18 | .__spEnterActive {
19 | @extend .com;
20 | transform: translate3d(0, 0, 0);
21 | transition: all ease-out 500ms;
22 | }
23 |
24 | .__spLeave {
25 | @extend .com;
26 | transform: translate3d(0, 0, 0);
27 | }
28 |
29 | .__spLeaveActive {
30 | @extend .com;
31 | transform: translate3d(-100%, 0, 0);
32 | transition: all ease-out 500ms;
33 | }
34 |
35 | .__spAppear {
36 | opacity: .01;
37 | }
38 |
39 | .__spAppearActive {
40 | opacity: 1;
41 | transition: opacity 1.5s ease-in;
42 | }
43 |
44 | /**************************返回***************************/
45 |
46 | .__spEnterReturn {
47 | @extend .com;
48 | transform: translate3d(-100%, 0, 0);
49 | }
50 |
51 | .__spEnterActiveReturn {
52 | @extend .com;
53 | transform: translate3d(0, 0, 0);
54 | transition: all ease-out 500ms;
55 | }
56 |
57 | .__spLeaveReturn {
58 | @extend .com;
59 | transform: translate3d(0, 0, 0);
60 | }
61 |
62 | .__spLeaveActiveReturn {
63 | @extend .com;
64 | transform: translate3d(100%, 0, 0);
65 | transition: all ease-out 500ms;
66 | }
67 |
68 | .__spAppearReturn {
69 | opacity: .01;
70 | transition: opacity 1.5s ease-in;
71 | }
72 |
73 | .__spAppearActiveReturn {
74 | opacity: 1;
75 | transition: opacity 1.5s ease-in;
76 | }
77 |
78 | .appContent {
79 | width: 100%;
80 | background: #fff;
81 | position: absolute;
82 | top: $top-hight;
83 |
84 | .spEnter {
85 | @extend .__spEnter;
86 | }
87 |
88 | .spEnterActive {
89 | @extend .__spEnterActive;
90 | }
91 |
92 | .spLeave {
93 | @extend .__spLeave;
94 | }
95 |
96 | .spLeaveActive {
97 | @extend .__spLeaveActive;
98 | }
99 |
100 | .spAppear {
101 | @extend .__spAppear;
102 | }
103 |
104 | .spAppearActive {
105 | @extend .__spAppearActive;
106 | }
107 | /**************************返回***************************/
108 | .spEnterReturn {
109 | @extend .__spEnterReturn;
110 | }
111 |
112 | .spEnterActiveReturn {
113 | @extend .__spEnterActiveReturn;
114 | }
115 |
116 | .spLeaveReturn {
117 | @extend .__spLeaveReturn;
118 | }
119 |
120 | .spLeaveActiveReturn {
121 | @extend .__spLeaveActiveReturn;
122 | }
123 |
124 | .spAppearReturn {
125 | @extend .__spAppearReturn;
126 | }
127 |
128 | .spAppearActiveReturn {
129 | @extend .__spAppearActiveReturn;
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/containers/App/scss/App.scss:
--------------------------------------------------------------------------------
1 | $top-hight:0;// 40px;
2 |
3 | .com {
4 | background: #fff;
5 | position: fixed;
6 | top: $top-hight; //bottom:50px; 去掉是因为界面最下面老是会跳的效果,改为下面这种
7 | // padding-bottom: 50px;
8 | bottom: 0;
9 | left: 0;
10 | right: 0;
11 | }
12 |
13 | .__spEnter {
14 | @extend .com;
15 | transform: translate3d(100%, 0, 0);
16 | }
17 |
18 | .__spEnterActive {
19 | @extend .com;
20 | transform: translate3d(0, 0, 0);
21 | transition: all ease-out 500ms;
22 | }
23 |
24 | .__spLeave {
25 | @extend .com;
26 | transform: translate3d(0, 0, 0);
27 | }
28 |
29 | .__spLeaveActive {
30 | @extend .com;
31 | transform: translate3d(-100%, 0, 0);
32 | transition: all ease-out 500ms;
33 | }
34 |
35 | .__spAppear {
36 | opacity: .01;
37 | }
38 |
39 | .__spAppearActive {
40 | opacity: 1;
41 | transition: opacity 1.5s ease-in;
42 | }
43 |
44 | /**************************返回***************************/
45 |
46 | .__spEnterReturn {
47 | @extend .com;
48 | transform: translate3d(-100%, 0, 0);
49 | }
50 |
51 | .__spEnterActiveReturn {
52 | @extend .com;
53 | transform: translate3d(0, 0, 0);
54 | transition: all ease-out 500ms;
55 | }
56 |
57 | .__spLeaveReturn {
58 | @extend .com;
59 | transform: translate3d(0, 0, 0);
60 | }
61 |
62 | .__spLeaveActiveReturn {
63 | @extend .com;
64 | transform: translate3d(100%, 0, 0);
65 | transition: all ease-out 500ms;
66 | }
67 |
68 | .__spAppearReturn {
69 | opacity: .01;
70 | transition: opacity 1.5s ease-in;
71 | }
72 |
73 | .__spAppearActiveReturn {
74 | opacity: 1;
75 | transition: opacity 1.5s ease-in;
76 | }
77 |
78 | .appContent {
79 | width: 100%;
80 | background: #fff;
81 | position: absolute;
82 | top: $top-hight;
83 |
84 | .spEnter {
85 | @extend .__spEnter;
86 | }
87 |
88 | .spEnterActive {
89 | @extend .__spEnterActive;
90 | }
91 |
92 | .spLeave {
93 | @extend .__spLeave;
94 | }
95 |
96 | .spLeaveActive {
97 | @extend .__spLeaveActive;
98 | }
99 |
100 | .spAppear {
101 | @extend .__spAppear;
102 | }
103 |
104 | .spAppearActive {
105 | @extend .__spAppearActive;
106 | }
107 | /**************************返回***************************/
108 | .spEnterReturn {
109 | @extend .__spEnterReturn;
110 | }
111 |
112 | .spEnterActiveReturn {
113 | @extend .__spEnterActiveReturn;
114 | }
115 |
116 | .spLeaveReturn {
117 | @extend .__spLeaveReturn;
118 | }
119 |
120 | .spLeaveActiveReturn {
121 | @extend .__spLeaveActiveReturn;
122 | }
123 |
124 | .spAppearReturn {
125 | @extend .__spAppearReturn;
126 | }
127 |
128 | .spAppearActiveReturn {
129 | @extend .__spAppearActiveReturn;
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/containers/page1/page1.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { connect } from 'react-redux';
4 | import { Utility, ApiInfo } from 'components';
5 | import * as CommonActions from 'reducers/reduxCommon';
6 | const comStyles = require('styles/Common.scss');
7 | const styles = require('./page.scss');
8 |
9 | @connect((state) => ({
10 | UserList: state.Common.UserList,
11 | Demo: state.Common.Demo,
12 | MapPlacelist: state.Common.MapPlacelist,
13 | }), { ...CommonActions })
14 | export default class Page1 extends Component {
15 | static propTypes = {
16 | UserList: PropTypes.any,
17 | Demo: PropTypes.any,
18 | MapPlacelist: PropTypes.any,
19 | onApiGet: PropTypes.func,
20 | }
21 |
22 | constructor(props) {
23 | super(props);
24 | this.state = {};
25 | }
26 |
27 | onCallApi() {
28 | const { onApiGet } = this.props;
29 | if (!onApiGet) {
30 | return;
31 | }
32 | // onApiGet('UserList', ApiInfo.Users, {}).then((data) => {
33 | // console.log(data);
34 | // }).catch((er) => {
35 | // console.log(er);
36 | // });
37 |
38 | function* testa() {
39 | console.log('---------1----------');
40 | yield onApiGet('UserList', ApiInfo.Users, {});
41 | console.log('---------2----------');
42 | yield onApiGet('MapPlacelist', ApiInfo.MapPlacelist, {});
43 | console.log('---------3----------');
44 | yield onApiGet('Demo', ApiInfo.Demo, {});
45 | console.log('---------4----------');
46 | yield 'ok';
47 | }
48 | const gen = testa();
49 |
50 | let result = gen.next();
51 | console.log(result);
52 | result = gen.next();
53 | console.log(result);
54 | result = gen.next();
55 | console.log(result);
56 | result = gen.next();
57 | console.log(result);
58 | result = gen.next();
59 | console.log(result);
60 | }
61 |
62 |
63 | render() {
64 | console.log('-----------------', new Date().getTime());
65 | const { UserList } = this.props;
66 | return (
67 |
68 |
69 |
70 |
71 |
72 |
73 | acdef
74 | {
75 | Utility.isArray(UserList) && UserList.map((item, index) => {
76 | const {
77 | address, age, cityname, username
78 | } = item;
79 | return (
80 |
81 |
{username}
82 |
{cityname}
83 |
{age}
84 |
{address}
85 |
86 | );
87 | })
88 | }
89 |
90 |
91 | );
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "env": {
4 | "browser": true,
5 | "node": true,
6 | "mocha": true
7 | },
8 | "settings": {
9 | "import/parser": "babel-eslint",
10 | "import/resolve": {
11 | "moduleDirectory": ["node_modules", "src"]
12 | },
13 | "propWrapperFunctions": [ "forbidExtraProps" ] // The names of any functions used to wrap the propTypes object, such as `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
14 | },
15 | "parser": "babel-eslint",
16 | "plugins": [
17 | "react", "import", "jsx-a11y"
18 | ],
19 | "rules": {
20 | "jsx-a11y/href-no-hash": "off",
21 | "jsx-a11y/anchor-is-valid": ["warn", { "aspects": ["invalidHref"] }],
22 | "import/newline-after-import": 0,
23 | "import/no-extraneous-dependencies": 0,
24 | "import/extensions":0,
25 | "import/first":0,
26 | "import/no-dynamic-require":0,
27 | "react/require-default-props":0,
28 | "react/no-unused-prop-types":0,
29 | "class-methods-use-this":0,
30 | "react/no-array-index-key":0,
31 | "prefer-template":0,
32 | "jsx-a11y/no-static-element-interactions":0,
33 | "no-underscore-dangle": 0,
34 | "react/jsx-uses-react": 2,
35 | "react/forbid-prop-types":0,
36 | "jsx-a11y/click-events-have-key-events":0,
37 | "react/jsx-uses-vars": 2,
38 | "prefer-destructuring": 0,
39 | "react/no-unused-state": 0,
40 | "react/jsx-closing-tag-location": 0,
41 | "react/no-multi-comp": 0,
42 | "react/jsx-curly-brace-presence": 0,
43 | "import/default": 0,
44 | "import/no-duplicates": 0,
45 | "import/named": 0,
46 | "no-proto": 0,
47 | "no-prototype-builtins": 0,
48 | "import/namespace": 0,
49 | "import/no-unresolved": 0,
50 | "import/no-named-as-default": 2,
51 | "comma-dangle": 0, // not sure why airbnb turned this on. gross!
52 | "indent": [2, 2, {"SwitchCase": 1}],
53 | "no-console": 0,
54 | "no-alert": 0,
55 | "id-length": 0,
56 | "no-trailing-spaces": 0,
57 | "no-nested-ternary": 0,
58 | "camelcase": [0],
59 | "semi": 2,
60 | "eqeqeq": "off",
61 | "curly": "error",
62 | "no-cond-assign": 2,
63 | "linebreak-style": 0,
64 | "arrow-body-style": 0,
65 | "arrow-parens": ["error", "always"],
66 | "max-len": 0,
67 | "global-require": 0,
68 | "no-return-assign": 0,
69 | "no-extra-boolean-cast": 0,
70 | "no-multi-spaces": 0,
71 | "no-restricted-syntax": 0,
72 | "no-param-reassign": 0,
73 | "prefer-rest-params": 0,
74 | "react/jsx-no-bind": 0,
75 | "object-property-newline": 0,
76 | "import/no-webpack-loader-syntax":0,
77 | "react/jsx-closing-bracket-location":0,
78 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
79 | "no-confusing-arrow": 0, // ["error", {"allowParens": false}],
80 | "prefer-arrow-callback": 2, // 箭头回调函数优先
81 | "no-var": "error" // 禁用var变量
82 | // "quotes": ["error", "double"]
83 | },
84 | "parserOptions": {
85 | "ecmaFeatures": {
86 | "jsx": true
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-webpack-demo",
3 | "version": "1.0.0",
4 | "description": "Example of webapp using react redux and hot reloading",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start-prod": "better-npm-run start-prod",
9 | "build": "better-npm-run start-prod",
10 | "start-dev": "better-npm-run start-dev",
11 | "dev": "concurrent --kill-others \"npm run start-dev\""
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/xiaotuni/react-webpack-demo"
16 | },
17 | "homepage": "https://github.com/xiaotuni/react-webpack-demo",
18 | "keywords": [
19 | "babel",
20 | "bundle-loader",
21 | "eslint",
22 | "hot reloading",
23 | "react",
24 | "react-router-dom",
25 | "react-hot-reloader",
26 | "redux",
27 | "webpack"
28 | ],
29 | "author": "xiaotuni (http://github.com/xiaotuni)",
30 | "license": "ISC",
31 | "betterScripts": {
32 | "start-dev": {
33 | "command": "webpack-dev-server --config webpack/dev.config.js --color --progress --hot",
34 | "env": {
35 | "NODE_ENV": "development"
36 | }
37 | },
38 | "start-prod": {
39 | "command": "webpack --config webpack/prod.config.js",
40 | "env": {
41 | "NODE_ENV": "production"
42 | }
43 | }
44 | },
45 | "dependencies": {
46 | "autoprefixer": "^7.1.5",
47 | "babel-core": "^6.26.0",
48 | "babel-eslint": "^8.0.1",
49 | "babel-loader": "^7.1.2",
50 | "babel-plugin-transform-decorators-legacy": "^1.3.4",
51 | "babel-plugin-transform-runtime": "^6.23.0",
52 | "babel-polyfill": "^6.26.0",
53 | "babel-preset-es2015": "^6.24.1",
54 | "babel-preset-react": "^6.24.1",
55 | "babel-preset-stage-0": "^6.24.1",
56 | "better-npm-run": "^0.1.0",
57 | "bundle-loader": "^0.5.5",
58 | "clean-webpack-plugin": "^0.1.16",
59 | "concurrently": "^3.5.0",
60 | "css-loader": "^0.28.7",
61 | "eslint": "^4.8.0",
62 | "eslint-config-airbnb": "^16.0.0",
63 | "eslint-loader": "^1.9.0",
64 | "eslint-plugin-import": "^2.7.0",
65 | "eslint-plugin-jsx-a11y": "^6.0.2",
66 | "eslint-plugin-react": "^7.3.0",
67 | "eslint-plugin-redux-saga": "^0.5.0",
68 | "extract-text-webpack-plugin": "^3.0.0",
69 | "file-loader": "^0.11.2",
70 | "html-webpack-plugin": "^2.30.1",
71 | "node-sass": "^4.5.3",
72 | "postcss-loader": "^2.0.6",
73 | "postcss-pxtorem": "^4.0.1",
74 | "react": "^16.0.0",
75 | "react-dom": "^16.0.0",
76 | "react-hot-loader": "next",
77 | "react-redux": "^5.0.6",
78 | "react-router-dom": "^4.2.2",
79 | "react-router-redux": "^4.0.8",
80 | "react-transition-group": "1.x",
81 | "redux": "^3.7.2",
82 | "redux-thunk": "^2.2.0",
83 | "sass-loader": "^6.0.6",
84 | "style-loader": "^0.18.2",
85 | "superagent": "^3.6.0",
86 | "uglifyjs-webpack-plugin": "^0.4.6",
87 | "url-loader": "^0.5.9",
88 | "webpack": "^3.7.1",
89 | "webpack-dev-server": "^2.9.1",
90 | "webpack-merge": "^4.1.0"
91 | },
92 | "browserslist": [
93 | "defaults",
94 | "not ie < 11",
95 | "last 2 versions",
96 | "> 1%",
97 | "iOS 7",
98 | "last 3 iOS versions"
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------
/src/containers/App/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { CSSTransitionGroup } from 'react-transition-group';
4 | import { Switch } from 'react-router-dom';
5 | import { Utility } from 'components';
6 | const styles = require('./scss/App.scss');
7 |
8 | export default class App extends Component {
9 | static propTypes = {
10 | children: PropTypes.any, // 子项
11 | location: PropTypes.object,
12 | Title: PropTypes.string,
13 | }
14 | static contextTypes = {
15 | router: PropTypes.object.isRequired,
16 | history: PropTypes.object,
17 | }
18 |
19 | constructor(props) {
20 | super(props);
21 | this.state = {};
22 | }
23 |
24 | componentWillMount() {
25 | const __key = Utility.constItem.KeyHistory;
26 | if (!Utility.getContent(__key)) {
27 | Utility.setContent(__key, this.context.router.history);
28 | const self = this;
29 | const { UrlTitle } = Utility.constItem;
30 | const __IsGoBackKey = Utility.constItem.KeyGoBack;
31 | this.context.router.history.listen((location, action) => {
32 | Utility.setContent(__IsGoBackKey, action === 'POP');
33 | const { pathname } = location;
34 | if (UrlTitle && UrlTitle[pathname]) {
35 | self.state.UrlTitle = UrlTitle[pathname];
36 | Utility.setContent('__URL_TITLE_INFO_', UrlTitle[pathname]);
37 | }
38 | });
39 | }
40 | }
41 | componentDidMount() {
42 | console.log('app did mount');
43 | }
44 |
45 |
46 | getTransitionsName() {
47 | const __IsGoback = Utility.getContent(Utility.constItem.KeyGoBack);
48 | const __tranName = {};
49 | if (!!__IsGoback) {
50 | __tranName.enter = styles.spEnterReturn;
51 | __tranName.enterActive = styles.spEnterActiveReturn;
52 | __tranName.leave = styles.spLeaveReturn;
53 | __tranName.leaveActive = styles.spLeaveActiveReturn;
54 | __tranName.appear = styles.spAppearReturn;
55 | __tranName.appearActive = styles.spAppearActiveReturn;
56 | } else {
57 | __tranName.enter = styles.spEnter;
58 | __tranName.enterActive = styles.spEnterActive;
59 | __tranName.leave = styles.spLeave;
60 | __tranName.leaveActive = styles.spLeaveActive;
61 | __tranName.appear = styles.spAppear;
62 | __tranName.appearActive = styles.spAppearActive;
63 | }
64 | return __tranName;
65 | }
66 |
67 | getTitle() {
68 | const title = Utility.getContent('__URL_TITLE_INFO_');
69 | if (title) {
70 | return title.Title;
71 | }
72 | return '默认标题';
73 | }
74 |
75 | render() {
76 | const __timeout = 500;
77 | const { context } = this;
78 | const { router } = context || {};
79 | const { route } = router || {};
80 | const { location } = route || {};
81 | const { key } = location || {};
82 |
83 | return (
84 |
85 |
92 |
93 | {this.props.children}
94 |
95 |
96 |
97 | );
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/containers/page4/page4.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Utility, ListItem } from 'components';
3 | const comStyles = require('styles/Common.scss');
4 | const styles = require('./page.scss');
5 |
6 | export default class Page4 extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = { DataSource: [] };
10 | }
11 |
12 | componentWillMount() {
13 | console.log('--1----will mount------');
14 | }
15 | componentDidMount() {
16 | console.log('--2----did mount------');
17 | }
18 | componentWillReceiveProps(nextProps, nextState) {
19 | const { a } = nextState;
20 | if (a) {
21 | console.log(a);
22 | }
23 | console.log('--3----will receive props------------');
24 | }
25 | shouldComponentUpdate(nextProps, nextState, nextContext) {
26 | const { a } = nextContext;
27 | if (a) {
28 | console.log(a);
29 | }
30 |
31 | console.log('--4----should update-----------------');
32 | return true;
33 | }
34 | componentWillUpdate(nextProps, nextState, nextContext) {
35 | const { a } = nextContext;
36 | if (a) {
37 | console.log(a);
38 | }
39 | console.log('--5----will update-------------');
40 | }
41 | componentDidUpdate(prevProps, prevState) {
42 | const { a } = prevState;
43 | if (a) {
44 | console.log(a);
45 | }
46 | console.log('--6----did update--12---------');
47 | }
48 | componentWillUnmount() {
49 | console.log('--7----will unmount-----------');
50 | }
51 |
52 |
53 | onListItemDelete(item, index) {
54 | this.state.DataSource.splice(index, 1);
55 | this.setState({ CurrentDate: new Date() });
56 | }
57 |
58 | componentDidCatch() {
59 | console.log('------------did catch-------------');
60 | }
61 |
62 | btnUpdateDate() {
63 | // new Date().toLocaleTimeString();
64 | const { DataSource } = this.state;
65 | DataSource.push({ id: DataSource.length + 1, CurrentDate: new Date(), Name: '哈哈__' });
66 |
67 | this.setState({ CurrentDate: new Date() });
68 | }
69 | btnArrayObjectSort() {
70 | const ArrayObj = [
71 | { Count: 7, name: 1 },
72 | { Count: 4, name: 2 },
73 | { Count: 245, name: 3 },
74 | { Count: 1, name: 4 },
75 | { Count: 2, name: '张三5' },
76 | { Count: 21, name: '张6三' },
77 | { Count: 80, name: '张8三' },
78 | ];
79 |
80 | const sortResult = ArrayObj.sort((a, b) => a.Count > b.Count);
81 | console.log(JSON.stringify(sortResult));
82 | console.log('-----------排序--------------');
83 | const aaaList = [];
84 | for (let i = 0; i < 10000; i += 1) {
85 | aaaList.push(Math.round(Math.random() * 100));
86 | }
87 | const _BeginDate = new Date().getTime();
88 | console.log('----------开始--------', _BeginDate);
89 | // console.log(JSON.stringify(aaaList));
90 | const aaaCountInfo = {};
91 | aaaList.forEach((key) => {
92 | if (!aaaCountInfo[key]) {
93 | aaaCountInfo[key] = { Count: 0, Key: key, name: '张——' };
94 | }
95 | aaaCountInfo[key].Count += 1;
96 | });
97 | // console.log(JSON.stringify(aaaCountInfo));
98 | console.log('------------------------');
99 | const aaaValue = Object.values(aaaCountInfo);
100 | // console.log(JSON.stringify(aaaValue));
101 | console.log('------------------------');
102 | const CountResult = aaaValue.sort((a, b) => a.Count - b.Count);
103 | console.log('------------------------');
104 | console.log(JSON.stringify(CountResult));
105 | console.log('----------开始--------', new Date().getTime() - _BeginDate);
106 |
107 | this.state.index = 0;
108 | this.setState({ index: this.state.index += 1 });
109 | }
110 |
111 | render() {
112 | const { CurrentDate, DataSource, index } = this.state;
113 | return (
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
单击事件
122 |
数组排序
123 |
124 |
125 |
{index}{CurrentDate && CurrentDate.toLocaleTimeString()}
126 |
127 |
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | webpack react redux router es6
9 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/src/redux/reducers/reduxCommon.js:
--------------------------------------------------------------------------------
1 | // import Utility from '../../Common/Utility';
2 | const __Base = 'XIAOTUNI/REDUX/Common/';
3 | const Load = __Base + 'Load';
4 | const LoadSuccess = __Base + 'LoadSuccess';
5 | const LoadFail = __Base + 'LoadFail';
6 |
7 | const _BaseNBEditTitle = __Base + 'NavBar/';
8 | const NbTitleEdit = _BaseNBEditTitle + 'Title_Edit';
9 | const NbTitleInfo = _BaseNBEditTitle + 'Title_Info';
10 |
11 | const __UpdateTime = __Base + '/__UpdateTime';
12 | const __DeleteStateByFields = __Base + '/DeleteStateByFields';
13 | // 清空信息
14 | const ClearContentSuccess = __Base + '/ClearContentSuccess';
15 |
16 | /**
17 | * 设置变量操作
18 | * @type {string}
19 | */
20 | const OnSetContent = __Base + 'OnSetContent';
21 | const UrlParamsEdit = __Base + 'UrlParamsEdit';
22 |
23 | const __API = __Base + 'API/';
24 | const __POST = __API + '/POST'; // POST方法处理
25 | const __PUT = __API + '/PUT'; // PUT方法处理
26 | const __DELETE = __API + '/DELETE'; // DELETE方法处理
27 | const __GET = __API + '/GET'; // GET方法处理
28 |
29 | let __TEMP_SERVICES_SYSTEM_TIEM;
30 | const initialState = { loaded: false, __Times: 0, };
31 |
32 |
33 | export default function reducer(state = initialState, action = {}) {
34 | const __Result = { ...state };
35 | if (action.result) { // 这里就是请求完成了
36 | Object.assign(__Result, { loading: false, loaded: true });
37 | __Result.Result = action.result;
38 | }
39 | if (action.error) { // 请求完了之后出错信息
40 | Object.assign(__Result, { loading: false, loaded: false });
41 | __Result.Error = action.error;
42 | }
43 |
44 | const { StateName, result } = action;
45 | const { __CurrentSystemTimes } = result || {};
46 | if (__CurrentSystemTimes) {
47 | __TEMP_SERVICES_SYSTEM_TIEM = __CurrentSystemTimes;
48 | }
49 | __Result.CurrentSystemTimes = __TEMP_SERVICES_SYSTEM_TIEM;
50 | __Result.SystemTimes = __TEMP_SERVICES_SYSTEM_TIEM;
51 | switch (action.type) {
52 | case OnSetContent:
53 | __Result[action.Key] = action.Value;
54 | break;
55 | case Load: // 加载
56 | __Result.loading = true;
57 | break;
58 | case LoadSuccess: // 加载成功
59 | __Result.data = action.result;
60 | break;
61 | case NbTitleInfo: // 修改标题,是否显示返回按键
62 | __Result.Title = action.Title || '默认标题';
63 | __Result.IsShowBackArrow = action.IsShowBackArrow ? action.IsShowBackArrow : false;
64 | break;
65 | case NbTitleEdit: // 修改标题
66 | __Result.Title = action.Title || '默认标题';
67 | break;
68 | case UrlParamsEdit: // url 参数
69 | __Result.UrlParams = action.query;
70 | break;
71 | case LoadFail: // 加载失败
72 | break;
73 | case __DELETE:
74 | break;
75 | case __POST:
76 | case __PUT:
77 | if (StateName) {
78 | __Result[StateName] = result;
79 | }
80 | break;
81 | case __GET:
82 | __Result[StateName || 'GetResult'] = result;
83 | // __Result = __ProcessRequestByGet(state, action);
84 | break;
85 | case __UpdateTime:
86 | __Result.__Times += 1;
87 | break;
88 | case ClearContentSuccess:
89 | __Result[action.Key] = null; // 清空信息
90 | break;
91 | default:
92 | }
93 | return __Result;
94 | }
95 |
96 | function __RequestProcess(method, StateName, api, args) {
97 | const __Method = {
98 | get: __GET, post: __POST, put: __PUT, del: __DELETE
99 | };
100 | return {
101 | types: [Load, __Method[method] || __GET, LoadFail],
102 | promise: (client) => client[method || 'get'](api, args),
103 | Condition: args,
104 | StateName
105 | };
106 | }
107 |
108 | /**
109 | * post保存接口调用方法。
110 | *
111 | * @export
112 | * @param {any} StateName
113 | * @param {any} Api
114 | * @param {any} Args {params:{}:data:{}}
115 | * @returns
116 | */
117 | export function onApiPost(StateName, Api, Args) {
118 | return __RequestProcess('post', StateName, Api, Args);
119 | }
120 |
121 | /**
122 | * put方法,修改方法操作。
123 | * @export
124 | * @param {any} StateName
125 | * @param {any} Api
126 | * @param {any} Args
127 | * @returns
128 | */
129 | export function onApiPut(StateName, Api, Args) {
130 | return __RequestProcess('put', StateName, Api, Args);
131 | }
132 |
133 | /**
134 | * 删除
135 | *
136 | * @export
137 | * @param {any} Api
138 | * @param {any} Args
139 | * @returns
140 | */
141 | export function onApiDelete(Api, Args) {
142 | return __RequestProcess('del', null, Api, Args);
143 | }
144 |
145 | /**
146 | * 获取
147 | *
148 | * @export
149 | * @param {any} StateName
150 | * @param {any} Api
151 | * @param {any} Args
152 | * @returns
153 | */
154 | export function onApiGet(StateName, Api, Args) {
155 | return __RequestProcess('get', StateName, Api, Args);
156 | }
157 |
158 | /**
159 | * 删除List的数据.
160 | *
161 | * @export
162 | * @param {any} StateName
163 | * @param {any} Fields [{Key:'SourceId',Value:123},...] or {Key:'SourceId',Value:123}
164 | * @returns
165 | */
166 | export function onDeleteByFields(StateName, Fields) {
167 | return { type: __DeleteStateByFields, StateName, Fields };
168 | }
169 |
170 | /**
171 | * 清空信息
172 | * @param {key} string
173 | * @param value
174 | * @returns
175 | */
176 | export function onClearContent(key) {
177 | return { type: ClearContentSuccess, Key: key };
178 | }
179 |
180 | export function onUpdateRedux() {
181 | return { type: __UpdateTime };
182 | }
183 |
184 | /**
185 | * 保存信息到 store里面去。
186 | * @param key
187 | * @param value
188 | * @returns {{type: string, Key: *, Value: *}}
189 | */
190 | export function onSetContent(key, value) {
191 | return { type: OnSetContent, Key: key, Value: value };
192 | }
193 |
--------------------------------------------------------------------------------
/src/containers/Es6/Es6.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | const comStyles = require('styles/Common.scss');
4 | const styles = require('./scss/Es6.scss');
5 |
6 | export default class Es6 extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.state = {};
10 | }
11 |
12 | componentWillMount() {
13 | // this.testDemo();
14 | // this.testClassDemo();
15 | try {
16 | this.testObjectDefineProperty();
17 | this.testGenerator();
18 | } catch (ex) {
19 | console.log(ex);
20 | }
21 | }
22 | printLine(args) {
23 | console.log('-------------------' + (args || '') + '-------------------');
24 | }
25 | testGenerator() {
26 | function* tempOther() {
27 | yield 11;
28 | yield 12;
29 | yield 13;
30 | }
31 |
32 | function* temp() {
33 | yield 1;
34 | yield 2;
35 | yield* tempOther();
36 | yield 4;
37 | return '最后啦';
38 | }
39 | const list = temp();
40 | for (const a of list) {
41 | console.log(a);
42 | }
43 |
44 | class Tree {
45 | constructor(value, children) {
46 | this.value = value;
47 | this.children = children;
48 | }
49 |
50 | * print() {
51 | yield this.value;
52 | for (const child of this.children) {
53 | yield* child.print();
54 | }
55 | }
56 | }
57 | this.printLine();
58 | const __tree = new Tree(0, [
59 | new Tree(11, [new Tree(111, [])]),
60 | new Tree(22, [new Tree(222, [])]),
61 | new Tree(33, [new Tree(333, [])]),
62 | ]);
63 |
64 | for (const tree of __tree.print()) {
65 | console.log(tree);
66 | }
67 | this.printLine();
68 | const isEves = (x) => x % 2 === 0;
69 | console.log(isEves(10));
70 | const notEves = (fn) => (...args) => {
71 | console.log('--------------b----------');
72 | return !fn(args);
73 | };
74 |
75 | console.log(notEves(isEves)(10));
76 |
77 | this.printLine();
78 | }
79 |
80 | testObjectDefineProperty() {
81 | const obj = {};
82 | Object.defineProperty(obj, 'field', {
83 | value: 1234,
84 | writable: true,
85 | enumerable: true, // 可以枚举。
86 | });
87 | Object.defineProperty(obj, 'field2', {
88 | enumerable: true, // 可以枚举。
89 | get() {
90 | return this._field2;
91 | },
92 | set(newValue) {
93 | if (this._field2 !== newValue) {
94 | this._field2 = newValue;
95 | }
96 | }
97 | });
98 | obj.field = 111;
99 | obj.field2 = '哈哈';
100 | obj._field2 = 'private field';
101 | console.log(Object.keys(obj));
102 | console.log(obj);
103 | this.printLine();
104 |
105 | const [a, b, c, d, ...e] = [[1, 2], [3, 4], [5, 6], [7, 8], 11, 22, 33, 44, 55];
106 | // const [a, b, c, d, e] = [1, 2, 3, 4, 5];
107 | console.log(a, b, c, d, e);
108 | const { field: xxField, field } = obj;
109 | console.log(xxField);
110 | console.log(field);
111 | const [aa, bb, ...cc] = '哈啦是不是的呀';
112 | console.log(aa, bb, cc);
113 | }
114 |
115 | testClassDemo() {
116 | class Point {
117 | constructor(x, y) {
118 | this.x = x;
119 | this.y = y;
120 | }
121 | toString() {
122 | const value = 'x:' + this.x + ' y:' + this.y;
123 | return value;
124 | }
125 | }
126 | Object.assign(Point.prototype, {
127 | sayHello() {
128 | console.log('say hello');
129 | }
130 | });
131 | const p = new Point(1, 2, 'bbc');
132 | this.printLine(p.toString());
133 | p.sayHello();
134 | const a = p.__proto__.hasOwnProperty('toString');
135 | console.log(a);
136 |
137 | class GetSetClass {
138 | get(name) {
139 | return this[name];
140 | }
141 | set(name, value = '默认值') {
142 | this[name] = value;
143 | }
144 | }
145 |
146 | const gs = new GetSetClass();
147 | gs.set('name01', '张三');
148 | gs.set('name00');
149 | console.log('--------', gs.get('name00'));
150 | console.log('--------', gs.get('name01'));
151 | }
152 |
153 | testDemo() {
154 | const arr = [1, 2, 3];
155 | const [a, b, c] = arr;
156 | console.log(a, b, c);
157 | const [foo, [[bar], baz]] = [1, [[2], 3]];
158 | console.log(foo, bar, baz);
159 | const [, , third] = ['foo', 'bar', 'baz'];
160 | console.log(third);
161 | const [head, ...tail] = [1, 2, 3, 4];
162 | console.log(head, tail);
163 | console.log('-----------------------es6 1-------------');
164 | // const [first, second, third1, fourth, fifth, sixth] = fibs();
165 | // console.log(first, second, third1, fourth, fifth, sixth);
166 |
167 | function* helloWorldGenerator() {
168 | yield 'hello';
169 | yield 'world';
170 | return 'ending';
171 | }
172 |
173 | const hw = helloWorldGenerator();
174 | console.log(hw);
175 |
176 | this.testIterator();
177 | }
178 | testIterator() {
179 | console.log('------------testIterator-------------');
180 | const makeIterator = (arr) => {
181 | let nextIndex = -1;
182 | return {
183 | next: () => {
184 | return nextIndex < arr.length ?
185 | { value: arr[nextIndex += 1], done: false } : { value: undefined, done: true };
186 | }
187 | };
188 | };
189 | const it = makeIterator(['a', 'b', 'c']);
190 | console.log(it.next());
191 | console.log(it.next());
192 | console.log(it.next());
193 | console.log(it.next());
194 |
195 | this.printLine('Iterator');
196 |
197 | const arr = [1, 2, 3, 4, 5, 6];
198 | const iter = arr[Symbol.iterator]();
199 | console.log(iter.next());
200 | console.log(iter.next());
201 | console.log(iter.next());
202 | console.log(iter.next());
203 | console.log(iter.next());
204 | console.log(iter.next());
205 | console.log(iter.next());
206 | this.printLine('||||||||');
207 |
208 | const obj = (value) => {
209 | this.value = value;
210 | this.next = null;
211 | };
212 | obj.prototype[Symbol.iterator] = () => {
213 | let current = this;
214 | const nexta = () => {
215 | if (current) {
216 | const value = current.value;
217 | current = value;
218 | return { value, done: false };
219 | }
220 | return { done: true };
221 | };
222 | const iterator = { next: nexta };
223 | return iterator;
224 | };
225 | const place = 55.03;
226 | const a = (place * 24000 * 0.92) - 50000;
227 | const b = a / 2;
228 |
229 | this.printLine(a + ' ' + b);
230 | }
231 |
232 | render() {
233 | return (
234 |
237 | );
238 | }
239 | }
240 |
241 |
--------------------------------------------------------------------------------
/src/Common/Utility.js:
--------------------------------------------------------------------------------
1 | export default class Utility {
2 | static __Instance;
3 |
4 | constructor() {
5 | this._TempSaveContent = {};
6 | this.__ConstPrefix = 'WeiXinXTN';
7 | }
8 |
9 | /**
10 | * 实例
11 | * @returns {*}
12 | */
13 | static instance() {
14 | if (this.__Instance === null || typeof this.__Instance === 'undefined') {
15 | this.__Instance = new this();
16 | }
17 | return this.__Instance;
18 | }
19 |
20 | /**
21 | * 常量
22 | * @type {{SaveUrlPath: string}}
23 | */
24 | static constItem = {
25 | PageSize: 15, // 每页大小数据
26 | CaptchaTimeout: 60,
27 | /**
28 | * 当前的上下文
29 | */
30 | Context: 'XTNContext', // 当前页面的Context
31 | ReduxKey: {
32 | ManualInputModify: 'ManualInputModify',
33 | },
34 | /**
35 | * 事件
36 | */
37 | Event: 'onXTNEvent', // 事件。
38 | Events: {
39 | HttpStatus: {
40 | 1: 'onHttpStatus_XTN_1',
41 | 200: 'onHttpStatus_XTN_200', // 处理成功
42 | 400: 'onHttpStatus_XTN_400', // 请求无效
43 | 401: 'onHttpStatus_XTN_401', // 未授权访问
44 | 402: 'onHttpStatus_XTN_402',
45 | 403: 'onHttpStatus_XTN_403', // 禁止访问
46 | 404: 'onHttpStatus_XTN_404', // 资源未找到
47 | 405: 'onHttpStatus_XTN_405',
48 | 406: 'onHttpStatus_XTN_406',
49 | 407: 'onHttpStatus_XTN_407',
50 | 408: 'onHttpStatus_XTN_408',
51 | 409: 'onHttpStatus_XTN_409',
52 | 411: 'onHttpStatus_XTN_411', // 登陆超时
53 | 500: 'onHttpStatus_XTN_500', // 服务器错误
54 | 501: 'onHttpStatus_XTN_501',
55 | 502: 'onHttpStatus_XTN_502',
56 | 503: 'onHttpStatus_XTN_503',
57 | },
58 | ShowModel: {
59 | OnActionSheet: 'onXTN_ShowModel_ActionSheet', //
60 | OnLoading: 'onXTN_ShowModel_Loading', // 加载
61 | OnAlert: 'onXTN_ShowModel_Alert', // 弹出信息
62 | OnConfirm: 'onXTN_ShowModel_Confirm', // 确定--取消
63 | OnShowDialog: 'onXTN_ShowModel_ShowDialog', // 打开对话框
64 | OnShowDialogHide: 'onXTN_ShowModel_ShowDialogHide', // 隐藏对话框
65 | OnShowDialogClose: 'onXTN_ShowModel_ShowDialogClose', // 关闭对话框
66 | OnActionSheetHide: 'onXTN_ShowModel_ActionSheetHide', // 关闭
67 | OnLoadingHide: 'onXTN_ShowModel_LoadingHide',
68 | OnConfirmHide: 'onXTN_ShowModel_ConfirmHide',
69 | },
70 | OnGoBack: 'onXTNEvent_GoBack', // 页面退回事件
71 | OnEditNavBarTitle: 'onXTNEvent_EditNavBarTitle', // 修改导航条标题
72 | OnEditNavBarRight: 'onXTNEvent_EditNavBarRight', // 修改导航条右边
73 | OnEditPageSliderInfo: 'onXTNEvent_EditPageSliderInfo', // 页面切换
74 | OnOpenDatePicker: 'onXTNEvent_OnOpenDatePicker', // 打开日期控件
75 | OnKeyboard: 'onXTNEvent_Keyboard', // 获取焦点键盘弹起;失去焦点键盘消失
76 | OnSetTitle: 'onXTNEvent_OnSetTitle', // 修改导航条的标题
77 | },
78 | /**
79 | * url 列表
80 | */
81 | UrlItem: {
82 | GoBack: 'goBack', // 回退操作
83 | Login: 'login', // 登录
84 | Page1: 'page1', // 首页-->商品列表
85 | Page2: 'page2', // 首页-->商品列表
86 | Page3: 'page3', // 首页-->商品列表
87 | Page4: 'page4', // 首页-->商品列表
88 | Counter: 'counter', // 首页-->商品列表
89 | UserInfo: 'userinfo', // 首页-->商品列表
90 | Es6: 'es6', // 首页-->商品列表
91 | },
92 | UrlTitle: {
93 | '/': { Title: '默认页面', Index: 0 },
94 | '/page1': { Title: 'page1', Index: 0 },
95 | '/page2': { Title: 'page2', Index: 0 },
96 | '/page3': { Title: 'page3', Index: 0 },
97 | '/page4': { Title: 'page4', Index: 0 },
98 | '/counter': { Title: '计数', Index: 0 },
99 | '/userinfo': { Title: '用户信息', Index: 0 },
100 | '/es6': { Title: 'Es6', Index: 0 },
101 | },
102 | /**
103 | * 显示模式
104 | */
105 | ShowModel: {
106 | ActionSheet: 'XTNShowModelActionSheet', //
107 | Loading: 'XTNShowModelLoading', // 加载
108 | Alert: 'XTNShowModelAlert', // 弹出信息
109 | Confirm: 'XTNShowModelConfirm', // 确定--取消
110 | },
111 | KeyHistory: 'XTN_KEY_HISTORY',
112 | KeyGoBack: 'XTN_KEY_GOBACK'
113 | }
114 |
115 | /**
116 | * 是否是数组
117 | * @param obj
118 | * @returns {boolean}
119 | */
120 | static isArray(obj) {
121 | if (!obj || !obj.length || obj.length === 0) {
122 | return false;
123 | }
124 | return Array.isArray(obj);
125 | }
126 |
127 | /**
128 | * 判断是否为空
129 | * true-为空;false-不为空
130 | * @param obj
131 | * @returns {boolean}
132 | */
133 | static isNull(obj) {
134 | return obj === null;
135 | }
136 |
137 | /**
138 | * 判断是否是微信打开的
139 | * @returns {boolean}
140 | */
141 | static isWeiXin() {
142 | try {
143 | const ua = window.navigator.userAgent.toLowerCase();
144 | const isWeiXin = ua.match(/micromessenger/i).indexOf('micromessenger');
145 | console.log(isWeiXin);
146 | return isWeiXin >= 0;
147 | } catch (ex) {
148 | return false;
149 | }
150 | }
151 |
152 | /**
153 | * 浏览器信息
154 | * @returns {Browser}
155 | */
156 | static browserInfo() {
157 | const _Browser = {
158 | versions: () => {
159 | const uu = navigator.userAgent;
160 | // const app = navigator.appVersion;
161 | return {
162 | trident: uu.indexOf('Trident') > -1, // IE内核
163 | presto: uu.indexOf('Presto') > -1, // opera内核
164 | webKit: uu.indexOf('AppleWebKit') > -1, // 苹果、谷歌内核
165 | gecko: uu.indexOf('Gecko') > -1 && uu.indexOf('KHTML') === -1, // 火狐内核
166 | mobile: !!uu.match(/AppleWebKit.*Mobile.*/), // 是否为移动终端
167 | ios: !!uu.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端
168 | android: uu.indexOf('Android') > -1 || uu.indexOf('Adr') > -1, // android终端
169 | iPhone: uu.indexOf('iPhone') > -1, // 是否为iPhone或者QQHD浏览器
170 | iPad: uu.indexOf('iPad') > -1, // 是否iPad
171 | webApp: uu.indexOf('Safari') === -1, // 是否web应该程序,没有头部与底部
172 | weixin: uu.indexOf('MicroMessenger') > -1, // 是否微信 (2015-01-22新增)
173 | qq: uu.match(/\sQQ/i) === ' qq' // 是否QQ
174 | };
175 | },
176 | language: (navigator.browserLanguage || navigator.language).toLowerCase()
177 | };
178 | return _Browser;
179 | }
180 |
181 | /**
182 | * 是否IOS系统
183 | *
184 | * @static
185 | * @returns
186 | *
187 | * @memberOf Utility
188 | */
189 | static $isIOS() {
190 | try {
191 | const u = navigator.userAgent;
192 | const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
193 | return isIOS;
194 | } catch (ex) {
195 | console.log(ex);
196 | return false;
197 | }
198 | }
199 |
200 | /**
201 | * 获取android版本
202 | *
203 | * @static
204 | * @returns
205 | *
206 | * @memberOf Utility
207 | */
208 | static $androidVersion() {
209 | const { userAgent } = navigator;
210 | if (userAgent.indexOf('Android') > -1 || userAgent.indexOf('Linux') > -1) {
211 | const num = userAgent.substr(userAgent.indexOf('Android') + 8, 3);
212 | return { type: 'Android', version: num };
213 | }
214 | return null;
215 | }
216 |
217 | /**
218 | * 对Date的扩展,将 Date 转化为指定格式的String
219 | * 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
220 | * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
221 | * @method __FormatDate
222 | * @param fmt
223 | * @param date
224 | * @return {*}
225 | * @example
226 | * Utility.FormatDate('yyyy-MM-dd hh:mm:ss.S',new Date());
227 | * @constructor
228 | */
229 | static formatDate(fmt, date) {
230 | if (!date) {
231 | return '';
232 | }
233 | let __this = new Date();
234 | let _fmt = fmt || 'yyyy-MM-dd HH:mm:ss.S';
235 | if (date !== null) {
236 | if (Date.parse(date)) {
237 | __this = date;
238 | } else {
239 | try {
240 | __this = new Date(date);
241 | } catch (ex) {
242 | __this = new Date();
243 | }
244 | }
245 | }
246 | const oo = {
247 | 'M+': __this.getMonth() + 1, // 月份
248 | 'd+': __this.getDate(), // 日
249 | 'D+': __this.getDate(), // 日
250 | 'H+': __this.getHours(), // 小时
251 | 'h+': __this.getHours(), // 小时
252 | 'm+': __this.getMinutes(), // 分
253 | 's+': __this.getSeconds(), // 秒
254 | 'q+': Math.floor((__this.getMonth() + 3) / 3), // 季度
255 | S: __this.getMilliseconds() // 毫秒
256 | };
257 | if (/(y+)/.test(_fmt)) {
258 | /(y+)/.exec(_fmt);
259 | // const aa = /(y+)/.test(_fmt);
260 | // if (aa) {
261 | const fmt1 = _fmt.replace(RegExp.$1, (__this.getFullYear() + '').substr(4 - RegExp.$1.length));
262 | _fmt = fmt1;
263 | // }
264 | }
265 | for (const kk in oo) {
266 | if (new RegExp('(' + kk + ')').test(fmt)) {
267 | _fmt = _fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (oo[kk]) : (('00' + oo[kk]).substr(('' + oo[kk]).length)));
268 | }
269 | }
270 | return _fmt;
271 | }
272 |
273 | /**
274 | * 打印输出日志
275 | * @method __PrintLog
276 | * @param {object} args 内容
277 | * @private
278 | */
279 | static printLog(args) {
280 | try {
281 | let __callmethod = '';
282 | try {
283 | throw new Error();
284 | } catch (ex) {
285 | // console.log(e.stack);
286 | __callmethod = ex.stack.replace(/Error\n/).split(/\n/)[1].replace(/^\s+|\s+$/, '');
287 | }
288 |
289 | const _curDate = new Date();
290 | const _aa = _curDate.toLocaleDateString() + ' ' + _curDate.toLocaleTimeString() + '.' + _curDate.getMilliseconds();
291 | console.log('--begin->', _aa, ' call method :', __callmethod);
292 | const __content = JSON.stringify(args);
293 | console.log(__content);
294 | } catch (ex) {
295 | console.log('---------输出日志,传入的内容传为JSON出现在异常--------------');
296 | console.log(ex);
297 | console.log('---------输出日志,内容为下--------------');
298 | console.log(args);
299 | }
300 | }
301 |
302 | /**
303 | * 判断输入的是否是手机号
304 | * @method __PhonePattern
305 | * @param {number} phone 手机号
306 | * @return {boolean} true 成功;false 失败
307 | * @example
308 | * Utility.PhonePattern('13000100100');
309 | * @private
310 | */
311 | static PhonePattern(phone) {
312 | const ex = /^(13[0-9]|14[0-9]|15[0-9]|17[0-9]|18[0-9])\d{8}$/;
313 | return ex.test(phone);
314 | }
315 |
316 | /**
317 | * 密码验证
318 | * @method __PasswordPattern
319 | * @param {string} password 密码
320 | * @return {boolean} true 成功;false 失败
321 | * @private
322 | */
323 | static PasswordPattern(password) {
324 | // test('/^[_0-9a-z]{6,16}$/i');
325 | const ex = /^[_0-9a-zA-Z]{6,25}$/;
326 | return ex.test(password);
327 | }
328 |
329 | /**
330 | * 是否含有中文(也包含日文和韩文)
331 | * @method __IsChineseChar
332 | * @param {string} str 要判断的内容
333 | * @return {boolean} true:成功;false:失败.
334 | * @private
335 | */
336 | static IsChineseChar(str) {
337 | // const reg = !/^[\u4E00-\u9FA5]/g; // \uF900-\uFA2D
338 | // return !/^[\u4e00-\u9fa5]+$/gi.test(str);// .test(str);
339 |
340 | const regu = '^[\u4e00-\u9fa5]+$';
341 | const re = new RegExp(regu);
342 | return re.test(str);
343 | }
344 |
345 | /**
346 | * 设置内容,这里主要是用来存放临时数据的。
347 | * @method _SetContent
348 | * @param key 键值,用于下次的时候获取内容用的。其实就是 _TempSaveContent的属性名称。
349 | * @param content 要存储的内容
350 | * @param isSaveLocalStorage 是否保存到本地存储里面
351 | * @param IsUser 根据用户uid 来获取缓存里的数据。
352 | * @private
353 | */
354 | static setContent(key, content, isSaveLocalStorage, IsUser) {
355 | try {
356 | const self = this.instance();
357 | if (isSaveLocalStorage) {
358 | let __Content = content;
359 | if (IsUser) {
360 | const __UserInfo = self._TempSaveContent[this.constItem.API.UserInfo];
361 | if (typeof __UserInfo !== 'undefined' && __UserInfo !== null) {
362 | __Content = {};
363 | __Content[__UserInfo.member_id] = content;
364 | }
365 | }
366 | __Content = JSON.stringify(__Content);
367 | // __content = CryptoJS.AES.encrypt(__Content, __key);
368 |
369 | if (typeof window !== 'undefined') {
370 | window.localStorage.setItem(key, __Content);
371 | }
372 | }
373 | self._TempSaveContent[key] = content;
374 | } catch (ex) {
375 | console.log(ex);
376 | }
377 | }
378 |
379 | /**
380 | * 删除指定字段值。
381 | * @method __RemoveContent
382 | * @param key
383 | * @return {null}
384 | * @private
385 | */
386 | static removeContent(key, IsRemoveLocalStorage) {
387 | try {
388 | const __self = this.instance();
389 | if (key === null || typeof key === 'undefined') {
390 | return;
391 | }
392 | if (__self._TempSaveContent[key]) {
393 | delete __self._TempSaveContent[key];
394 | }
395 |
396 | if (IsRemoveLocalStorage && typeof window !== 'undefined') {
397 | window.localStorage.removeItem(key);
398 | }
399 | } catch (ex) {
400 | this.printLog(ex.toString());
401 | }
402 | }
403 |
404 | /**
405 | * 获取内容,
406 | * @method _GetContent
407 | * @param key 健名称。其实就是 _TempSaveContent的属性名称。
408 | * @return {*} 返回内容
409 | * @private
410 | */
411 | static getContent(key, IsUser) {
412 | try {
413 | let __Content = null;
414 | const __self = this.instance();
415 | if (__self._TempSaveContent[key]) {
416 | __Content = __self._TempSaveContent[key];
417 | return __Content;
418 | }
419 | if (typeof window === 'undefined') {
420 | return null;
421 | }
422 | if (__Content === null || typeof __Content === 'undefined') {
423 | const _value = window.localStorage.getItem(key);
424 | if (_value !== null && _value !== '' && typeof _value !== 'undefined') {
425 | const __JSONValue = JSON.parse(_value);
426 | __self._TempSaveContent[key] = __JSONValue;
427 | if (IsUser) {
428 | //
429 | }
430 | __Content = __self._TempSaveContent[key];
431 | }
432 | }
433 |
434 | return __Content;
435 | } catch (ex) {
436 | console.log(ex);
437 | return null;
438 | }
439 | }
440 |
441 | /**
442 | * 判断是否是函数
443 | * @param func 判断函数对象
444 | * @returns {boolean} true:成功,false:失败。
445 | */
446 | static isFunction(func) {
447 | if (func !== null && typeof func !== 'undefined' && func.constructor.name === 'Function') {
448 | return true;
449 | }
450 | return false;
451 | }
452 |
453 | /**
454 | * 判断是否未定义
455 | * @param obj 判断对象
456 | * @returns {boolean} true:成功,false:失败。
457 | */
458 | static isUndefined(obj) {
459 | if (typeof obj === 'undefined') {
460 | return true;
461 | }
462 | return false;
463 | }
464 |
465 | /**
466 | * 判断是否未定义
467 | * @param obj 判断对象
468 | * @returns {boolean} true:成功,false:失败。
469 | */
470 | static isInvalid(obj) {
471 | if (typeof obj === 'undefined' || obj === null || obj === '' || obj === {}) {
472 | return true;
473 | }
474 | return false;
475 | }
476 |
477 | /**
478 | * 判断是否定义。
479 | * @param obj 判断对象
480 | * @return {boolean} true:成功,false:失败。
481 | */
482 | static isDefined(obj) {
483 | if (typeof obj !== 'undefined') {
484 | return true;
485 | }
486 | return false;
487 | }
488 |
489 | /**
490 | * 判断是否是日期类型
491 | *
492 | * @static * @param {any} obj 判断对象
493 | * @returns {boolean} true: 是日期,false:不是日期。
494 | * @example
495 | * Utility.isDate('abcadfa') ---> false
496 | * Utility.isDate(new Date()) ---> true
497 | * Utility.isDate('2013年10月10日') ---> true
498 | * @memberOf Utility
499 | */
500 | static isDate(obj) {
501 | if (typeof obj === 'undefined' || obj === null || obj === '') { // 判断是不是 undefined,或 null
502 | return false;
503 | }
504 | const __isDate = obj.constructor.name === 'Date'; // 如果传入的就是日期
505 | if (__isDate) {
506 | return true;
507 | }
508 | try {
509 | return (new Date(obj.replace('年', '-').replace('月', '-').replace('日', ''))).constructor.name === 'Date';
510 | } catch (ex) {
511 | return false;
512 | }
513 | }
514 |
515 | /**
516 | * 将一个 对象转成url参数与&分开
517 | *
518 | * @param params 参数对象
519 | * @param split 分割符
520 | * @returns {*}
521 | * @example {a:a,b:b,c:c,e:e}
522 | * a=a&b=b&c=c&e=e
523 | */
524 | static convertToUrlParams(params, options) {
525 | const { split, notFields } = options || {};
526 | if (this.isUndefined(params) || params === null) {
527 | return '';
528 | }
529 | const __KeyValue = [];
530 | const self = this;
531 | const __JSONValue = (value) => {
532 | try {
533 | let __JValue;
534 | if (value === null) {
535 | return '';
536 | }
537 | const { constructor } = value;
538 | if (typeof constructor === 'undefined' || constructor === null) {
539 | return '';
540 | }
541 | switch (value.constructor.name) {
542 | case 'Object':
543 | __JValue = '{' + this.convertToUrlParams(value) + '}';
544 | break;
545 | case 'Array':
546 | __JValue = JSON.stringify(value);
547 | break;
548 | default:
549 | __JValue = value;
550 | }
551 | return __JValue;
552 | } catch (ex) {
553 | console.log(ex.message);
554 | return value || '';
555 | }
556 | };
557 | Object.keys(params).forEach((key) => {
558 | const __value = params[key];
559 | if (self.isDefined(__value) && __value !== '') {
560 | if (key.toLowerCase() !== 'IsExistsNextData'.toLowerCase()) {
561 | // const __JsonValue = (self.isArray(__value) ? JSON.stringify(__value) : __value);
562 | if (notFields) {
563 | if (notFields.indexOf(key) === -1) {
564 | __KeyValue.push(key + '=' + __JSONValue(__value));
565 | }
566 | } else {
567 | __KeyValue.push(key + '=' + __JSONValue(__value));
568 | }
569 | }
570 | }
571 | });
572 | return __KeyValue.join(split || '&');
573 | }
574 |
575 | /**
576 | * 将 map对象 转成 key-value 数组对象
577 | * @param row
578 | * @returns {Array}
579 | */
580 | static convertMapToObject(row) {
581 | if (this.isUndefined(row) || this.isNull(row) || row === '') {
582 | return [];
583 | }
584 | const __Array = [];
585 | Object.keys(row).forEach((key) => {
586 | const __obj = {};
587 | __obj.key = key;
588 | __obj.value = row[key];
589 | __Array.push(__obj);
590 | });
591 | return __Array;
592 | }
593 |
594 | /**
595 | * 解析状态数据
596 | * @param state 状态
597 | * @param fieldName 字段名称
598 | * @param action 行为
599 | * @returns {*}
600 | */
601 | static parseStateMoreData(state, fieldName, action) {
602 | if (typeof action.result === 'undefined') {
603 | return state;
604 | }
605 | if (Utility.isUndefined(state[fieldName]) || state[fieldName] === null) {
606 | state[fieldName] = {};
607 | }
608 | const __Condition = action.Condition || {};
609 | const __pgIndex = __Condition.pgIndex || 0;
610 | const __pgCount = __Condition.pgCount || this.constItem.PageSize;
611 | const __Result = action.result;
612 | __Condition.IsExistsNextData = action.result.length === __pgCount;
613 | if (__pgIndex !== 0 && Utility.isArray(state[fieldName].List)) {
614 | state[fieldName].List = state[fieldName].List.concat(__Result);
615 | } else {
616 | state[fieldName].List = __Result;
617 | }
618 | __Condition.pgIndex = __Condition.IsExistsNextData ? (__pgIndex + 1) : __pgIndex;
619 | __Condition.pgCount = __pgCount;
620 | state[fieldName].Condition = __Condition;
621 | return state;
622 | }
623 |
624 | /**
625 | * 页面跳转
626 | * @param url 要跳转的页面。
627 | * @param params 参数
628 | */
629 | static toPage(url, params) {
630 | try {
631 | const __history = this.getContent(this.constItem.KeyHistory);
632 | if (this.isUndefined(url) || url === '' || this.isUndefined(__history)) {
633 | return;
634 | }
635 | this.$loadingHide();
636 |
637 | if (url === this.constItem.UrlItem.GoBack) {
638 | this.setContent(this.constItem.KeyGoBack, true);
639 | __history.goBack();
640 | return;
641 | }
642 | const __pathname = '/' + url;
643 | __history.push(__pathname, Object.assign(params || {}, { _timestamp: new Date().getTime() }));
644 | } catch (ex) {
645 | console.log(ex.toString());
646 | }
647 | }
648 |
649 | /**
650 | * 格式化
651 | * @example
652 | * sprintf('Latitude: %s, Longitude: %s, Count: %d', 41.847, -87.661, 'two')
653 | * Expected output: Latitude: 41.847, Longitude: -87.661, Count: 0
654 | * @returns {*}
655 | */
656 | static sprintf() {
657 | const args = arguments;
658 | const string = args[0];
659 | let __index = 1;
660 | return string.replace(/%((%)|s|d)/g, (mm) => {
661 | // m is the matched format, e.g. %s, %d
662 | let val = null;
663 | if (mm[2]) {
664 | val = mm[2];
665 | } else {
666 | val = args[__index];
667 | // A switch statement so that the formatter can be extended. Default is %s
668 | switch (mm) {
669 | case '%d':
670 | val = parseFloat(val);
671 | if (!val) {
672 | val = 0;
673 | }
674 | break;
675 | default:
676 | break;
677 | }
678 | __index += 1;
679 | }
680 | return val;
681 | });
682 | }
683 |
684 | /**
685 | * 格式化
686 | * @example
687 | * format('{0} is dead, but {1} is alive! {0} {2}', 'ASP', 'ASP.NET');
688 | * ASP is dead, but ASP.NET is alive! ASP {2}
689 | * @param format
690 | * @returns {*}
691 | */
692 | static format(format) {
693 | const args = Array.prototype.slice.call(arguments, 1);
694 | return format.replace(/{(\d+)}/g, (match, number) => {
695 | return typeof args[number] !== 'undefined'
696 | ? args[number] : match;
697 | });
698 | }
699 |
700 | /**
701 | * 解析URL地址
702 | * @method __ParseURL
703 | * @param {string} url 完整的URL地址
704 | * @return {object} 自定义的对象
705 | * @example
706 | * 用法示例:var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top');
707 | * myURL.file='index.html'
708 | * myURL.hash= 'top'
709 | * myURL.host= 'abc.com'
710 | * myURL.query= '?id=255&m=hello'
711 | * myURL.params= Object = { id: 255, m: hello }
712 | * myURL.path= '/dir/index.html'
713 | * myURL.segments= Array = ['dir', 'index.html']
714 | * myURL.port= '8080'
715 | * yURL.protocol= 'http'
716 | * myURL.source= 'http://abc.com:8080/dir/index.html?id=255&m=hello#top'
717 | */
718 | static parseURL(url) {
719 | const ae = document.createElement('a');
720 | ae.href = url;
721 | return {
722 | source: url,
723 | protocol: ae.protocol.replace(':', ''),
724 | host: ae.hostname,
725 | port: ae.port,
726 | query: ae.search,
727 | params: (() => {
728 | const ret = {};
729 | const seg = ae.search.replace(/^\?/, '').split('&');
730 | const len = seg.length;
731 | let ii = 0;
732 | let ss;
733 | for (; ii < len; ii += 1) {
734 | if (seg[ii]) {
735 | ss = seg[ii].split('=');
736 | ret[ss[0]] = ss[1];
737 | }
738 | }
739 | return ret;
740 | })(),
741 | file: (ae.pathname.match(/\/([^/?#]+)$/i) || [''])[1],
742 | hash: ae.hash.replace('#', ''),
743 | path: ae.pathname.replace(/^([^/])/, '/$1'),
744 | relative: (ae.href.match(/tps?:\/\/[^/]+(.+)/) || [''])[1],
745 | segments: ae.pathname.replace(/^\//, '').split('/')
746 | };
747 | }
748 |
749 | /**
750 | * 事件处理
751 | * @param eventName 事件名称
752 | * @param param1 参数名称1
753 | * @param param2 参数名称2
754 | * @param param3 参数名称3
755 | * @param param4 参数名称4
756 | * @param param5 参数名称5
757 | * @param param6 参数名称6
758 | * @param param7 参数名称7
759 | * @param param8 参数名称8
760 | * @param param9 参数名称9
761 | */
762 | static $emit(eventName, param1, param2, param3, param4, param5, param6, param7, param8, param9) {
763 | if (this.isUndefined(eventName)) {
764 | return;
765 | }
766 | const event = this.getContent(this.constItem.Event);
767 | if (this.isUndefined(event) || event === null) {
768 | return;
769 | }
770 | if (!this.isFunction(event.emit)) {
771 | return;
772 | }
773 | event.emit(eventName, param1, param2, param3, param4, param5, param6, param7, param8, param9);
774 | }
775 |
776 | /**
777 | * 添加事件
778 | * @param eventName {string} 事件名称
779 | * @param callBack {function} 回调的方法名称
780 | */
781 | static $on(eventName, callBack) {
782 | if (this.isUndefined(eventName)) {
783 | return;
784 | }
785 | const event = this.getContent(this.constItem.Event);
786 | if (this.isUndefined(event) || event === null) {
787 | return;
788 | }
789 | if (!this.isFunction(event.on)) {
790 | return;
791 | }
792 | event.on(eventName, callBack);
793 | }
794 |
795 | /**
796 | * 弹出提示信息
797 | * @param Content 弹出显示内容
798 | * @param Title 弹出显示的标题,可以不填写,默认为当前导航条里的标题
799 | * @param ToPage 弹出来,页面跳转到下一个页面 {Url: Utility.constItem.UrlItem.Login, Options: {}}
800 | * @constructor
801 | */
802 | static $actionSheet(Content, Title, ToPage) {
803 | this.$emit(this.constItem.Events.ShowModel.OnActionSheet, {
804 | Title, ContentInfo: { Content }, ToPage
805 | });
806 | }
807 |
808 | /**
809 | * 确定,取消窗体
810 | * @param Message 信息内容
811 | * @param okButton 点击确定事件
812 | * @param Title 弹出窗体上的标题 (可空)
813 | * @param onCancel 点击取消事件 (可空)
814 | */
815 | static $confirm(Message, okButton, Title, onCancel, options) {
816 | this.$emit(
817 | this.constItem.Events.ShowModel.OnConfirm,
818 | {
819 | Title, Content: Message, okButton, onCancel, Options: options
820 | }
821 | );
822 | }
823 |
824 | static $showDialog(Html, Title, okButton, onCancel, Options) {
825 | this.$emit(
826 | this.constItem.Events.ShowModel.OnShowDialog,
827 | {
828 | Title, Html, okButton, onCancel, isShowAction: true,
829 | Options: Object.assign(Options || {}, { IsHideCancel: true, IsHideOk: true })
830 | }
831 | );
832 | }
833 |
834 | static $showDialogHide(args) {
835 | this.$emit(this.constItem.Events.ShowModel.OnShowDialogHide, args);
836 | }
837 |
838 | static $showDialogConfirm(msg, Title, okButton, onCancel) {
839 | let _title = Title;
840 | let _okButton = okButton;
841 | if (this.isFunction(Title)) {
842 | _title = '提示信息';
843 | _okButton = Title;
844 | }
845 | this.$emit(
846 | this.constItem.Events.ShowModel.OnShowDialog,
847 | {
848 | Content: msg, Title: _title, okButton: _okButton, onCancel
849 | }
850 | );
851 | }
852 |
853 | static $alert(msg, title) {
854 | let _title = title;
855 | let _okButton;
856 | if (this.isFunction(title)) {
857 | _title = '提示信息';
858 | _okButton = title;
859 | }
860 | this.$emit(
861 | this.constItem.Events.ShowModel.OnShowDialog,
862 | {
863 | Content: msg, Title: _title, okButton: _okButton, Options: { IsHideCancel: true }
864 | }
865 | );
866 | }
867 |
868 | /**
869 | * 打开加载动画
870 | */
871 | static $loading() {
872 | this.$emit(this.constItem.Events.ShowModel.OnLoading);
873 | }
874 |
875 | /**
876 | * 关闭加载动画
877 | */
878 | static $loadingHide() {
879 | this.$emit(this.constItem.Events.ShowModel.OnLoadingHide);
880 | }
881 |
882 | /**
883 | * 去空格
884 | * @param value
885 | * @returns {*}
886 | */
887 | static $trim(value) {
888 | if (typeof value !== 'undefined') {
889 | return value.replace(/(^\s*)|(\s*$)/g, '');
890 | }
891 | return '';
892 | }
893 |
894 | /**
895 | * 去右边空格
896 | * @param value
897 | * @returns {*}
898 | */
899 | static $trimRight(value) {
900 | if (typeof value !== 'undefined') {
901 | return value.replace(/(\s*$)/g, '');
902 | }
903 | return '';
904 | }
905 |
906 | /**
907 | * 去左边空格
908 | * @param s
909 | * @returns {*}
910 | */
911 | static $trimLeft(value) {
912 | if (typeof value !== 'undefined') {
913 | return value.replace(/(^\s*)/g, '');
914 | }
915 | return '';
916 | }
917 |
918 | /**
919 | * 菜单-->添加按键
920 | * @param Text
921 | * @param onClick
922 | * @param Color
923 | * @param BgColor
924 | */
925 | static $navBarRightAddButton(Text, onClick, Color, BgColor) {
926 | this.$emit(
927 | this.constItem.Events.OnEditNavBarRight,
928 | this.constItem.NavBarRightType.NBButton,
929 | {
930 | Text, onClick, Color, BgColor
931 | }
932 | );
933 | }
934 |
935 | /**
936 | * 菜单-->添加图标
937 | * @param Icon
938 | * @param onClick
939 | */
940 | static $navBarRightAddIcon(Icon, onClick) {
941 | this.$emit(
942 | this.constItem.Events.OnEditNavBarRight,
943 | this.constItem.NavBarRightType.NBIcon,
944 | { Icon, onClick }
945 | );
946 | }
947 |
948 | /**
949 | * 菜单-->添加菜单
950 | * [{Text:'菜单1',onClick:onClick},{Text:'菜单2',onClick:onClick},...]
951 | * @param MenuItem
952 | */
953 | static $navBarRightAddMenuItem(MenuItem) {
954 | this.$emit(this.constItem.Events.OnEditNavBarRight, this.constItem.NavBarRightType.NBMenu, MenuItem);
955 | }
956 |
957 | /**
958 | * 打开日期控件
959 | *
960 | * @static * @param {datetime} currentDate 当前时间
961 | * @param {boolean} isShowTime 是否显示时间
962 | * @param {Function} ok 点击确定按钮事件-->这里可以获取到返回的日期
963 | * @param {Function} cancel 取消按钮事件
964 | *
965 | * @example
966 | * // 打开日期
967 | * Utility.$openDatePicker(new Date(),false,(date)=>{console.log(date);},()=>{ // cancel todo });
968 | * // 打开日期和时间
969 | * Utility.$openDatePicker(new Date(),true,(date)=>{console.log(date);},()=>{ // cancel todo });
970 | * // 传入日期
971 | * Utility.$openDatePicker('2013-10-10',false,(date)=>{console.log(date);},()=>{// cancel todo });
972 | * // 传入日期和时间
973 | * Utility.$openDatePicker('2010-10-10 12:20,true,(date)=>{console.log(date);},()=>{ // cancel todo });
974 | * // 传入值,如果是null 或 '' 默认为当前时间
975 | * Utility.$openDatePicker('',false,(date)=>{console.log(date);},()=>{// cancel todo });
976 | *
977 | * @memberOf Utility
978 | */
979 | static $openDatePicker(currentDate, isShowTime, ok, cancel) {
980 | this.$emit(this.constItem.Events.OnOpenDatePicker, currentDate, isShowTime, ok, cancel);
981 | }
982 |
983 | /**
984 | * 将日期转为时间戳
985 | *
986 | * @static * @param {any} date
987 | * @returns
988 | *
989 | * @memberOf Utility
990 | */
991 | static $convertToTimestamp(date) {
992 | if (typeof date === 'undefined' || date === null || date === '') {
993 | return 0;
994 | }
995 | if (this.isDate(date)) {
996 | // replace(/(\s*$)/g, '') r.replace(/-/g, "/")
997 | return date.constructor.name === 'Date' ? date.getTime() : new Date(date.replace('年', '-').replace('月', '-').replace('日', '').replace(/-/g, '/')).getTime();
998 | }
999 | return 0;
1000 | }
1001 |
1002 | /**
1003 | * 将时间戳转为日期类型
1004 | *
1005 | * @static * @param {number} value
1006 | * @returns
1007 | * @example
1008 | * Utility.$convertToDateByTimestamp('1478131200000') -> 2016-11-03
1009 | * Utility.$convertToDateByTimestamp('1478131200000','yyyy年MM月dd日') -> 2016年11月03日
1010 | * @memberOf Utility
1011 | */
1012 | static $convertToDateByTimestamp(value, format) {
1013 | if (this.$isNumber(value)) {
1014 | const __date = new Date(parseInt(value, 0));
1015 | return this.formatDate(format || 'yyyy-MM-dd', __date);
1016 | }
1017 | return '';
1018 | }
1019 |
1020 | /**
1021 | * 字符串转为日期类型
1022 | *
1023 | * @static * @param {string} value 日期
1024 | * @returns Date 或为 null
1025 | * @example
1026 | * Utility.$convertToDateByString('2013-10-10');
1027 | * @memberOf Utility
1028 | */
1029 | static $convertToDateByString(value) {
1030 | if (this.isDate(value)) {
1031 | return value.constructor.name === 'Date' ? value : new Date(value.replace('年', '-').replace('月', '-').replace('日', ''));
1032 | }
1033 | return null;
1034 | }
1035 |
1036 | /**
1037 | * 状态转换,将状态转为对应显示的名称
1038 | *
1039 | * @static * @param {object} obj 对象
1040 | * @param {string} status 状态
1041 | * @returns 返回状态对应的名称
1042 | *
1043 | * @memberOf Utility
1044 | */
1045 | static $statusConvert(obj, status) {
1046 | if (this.isUndefined(obj) || obj === null || obj === '') {
1047 | return this.isUndefined(status) ? '' : status;
1048 | }
1049 | if (this.isUndefined(status)) {
1050 | return '';
1051 | }
1052 | const __Value = obj[status];
1053 | return __Value || status;
1054 | }
1055 |
1056 | /**
1057 | * @param value
1058 | * @returns {*}
1059 | */
1060 | static $isNumber(value) {
1061 | if (typeof value === 'undefined' || value === null || value === '') {
1062 | return false;
1063 | }
1064 | return /^\+?[0-9]\d*$/.test(value);
1065 | }
1066 |
1067 | /**
1068 | * 格式化数字
1069 | *
1070 | * @static
1071 | * @param {any} number
1072 | * @returns
1073 | *
1074 | * @example Utility.$formatNumber(10000) ==> 10,000
1075 | * @memberOf Utility
1076 | */
1077 | static $formatNumber(number) {
1078 | if (!this.$isNumber(number)) {
1079 | return number;
1080 | }
1081 | const __value = this.$trim(number);
1082 | return String(__value).split('').reverse().join('')
1083 | .replace(/(\d{3})(?=[^$])/g, '$1,')
1084 | .split('')
1085 | .reverse()
1086 | .join('');
1087 | }
1088 |
1089 | /**
1090 | * 判断是否为空
1091 | *
1092 | * @static
1093 | * @param {string} value 要判断的值
1094 | * @returns true:是 ; false:否
1095 | *
1096 | * @memberOf Utility
1097 | */
1098 | static $isEmpty(value) {
1099 | if (!value) {
1100 | return true;
1101 | }
1102 | const __value = this.$trim(value);
1103 | if (__value === '') {
1104 | return true;
1105 | }
1106 | return false;
1107 | }
1108 |
1109 | static $clone(obj) {
1110 | if (!obj) {
1111 | return null;
1112 | }
1113 | const __temp = {};
1114 | Object.keys(obj).forEach((key) => {
1115 | if (key !== 'IsExistsNextData' && key !== '_timestamp') {
1116 | __temp[key] = obj[key] ? obj[key].toString() : '';
1117 | }
1118 | });
1119 | return __temp;
1120 | }
1121 |
1122 | /**
1123 | * 后退操作
1124 | *
1125 | * @static
1126 | *
1127 | * @memberOf Utility
1128 | */
1129 | static $goBack(times) {
1130 | this.toPage(this.constItem.UrlItem.GoBack, { times });
1131 | }
1132 | }
1133 |
--------------------------------------------------------------------------------