GVKun编程网logo

dva+react+antd+webpack 项目开发配置(react dva介绍)

15

本文将为您提供关于dva+react+antd+webpack项目开发配置的详细介绍,我们还将为您解释reactdva介绍的相关知识,同时,我们还将为您提供关于create-react-app脚手架创

本文将为您提供关于dva+react+antd+webpack 项目开发配置的详细介绍,我们还将为您解释react dva介绍的相关知识,同时,我们还将为您提供关于create-react-app脚手架创建react项目,暴露webpack配置文件,如何引入less支持+antd按需加载+自定义主题、React 简单实例 (React-router + webpack + Antd )、React+dva+webpack+antd-mobile 实战分享(一)、React+dva+webpack+antd-mobile 实战分享(二)的实用信息。

本文目录一览:

dva+react+antd+webpack 项目开发配置(react dva介绍)

dva+react+antd+webpack 项目开发配置(react dva介绍)

如何搭建一个dva项目如何搭建一个dva项目

后期项目会在github上进行书写,同时也会在segmentfault上进行同步~3Q拜读~

create-react-app脚手架创建react项目,暴露webpack配置文件,如何引入less支持+antd按需加载+自定义主题

create-react-app脚手架创建react项目,暴露webpack配置文件,如何引入less支持+antd按需加载+自定义主题

使用 create-react-app 脚手架创建项目后,默认是不支持 less 的。所以我们需要手动添加。

第一步 暴露webpack配置文件

使用 create-react-app 创建的项目,默认情况下是看不到 webpack 相关的配置文件,我们需要给它暴露出来,使用下面命令即可

yarn eject

运行之后,我们发现多了一个config文件夹,这样就可以修改 webpack 相关配置了。

第二步 添加less 在项目根目录 使用 npm 或者 yarn 来安装antd less 和 less-loader

  1. yarn add babel-plugin-import
  2. yarn add antd
  3. yarn add less less-loader

 

第三步 修改package.json:添加antd库的样式

"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": "css"
        }
      ]
    ]
  }

第四步 复制代码修改配置环境(webpack.config.js) 定义全局变量

// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;

const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;


第五步 复制代码配置less-loader

//在大概466行会看到如下代码
      {
                test: sassModuleRegex,
                use: getStyleLoaders(
                  {
                    importLoaders: 2,
                    sourceMap: isEnvProduction && shouldUseSourceMap,
                    modules: true,
                   getLocalIdent: getCSSModuleLocalIdent,
                 },
                ''sass-loader''
               ),
            },
 
 
 //在此代码后添加如下代码
 
 {
               test: lessRegex,
               exclude: lessModuleRegex,
               use: getStyleLoaders(
                 {
                   importLoaders: 2
                 },
                 ''less-loader''
               ),
            },

             {
               test: lessModuleRegex,
               use: getStyleLoaders(
                 {
                   importLoaders: 2,
                   modules: true,
                   getLocalIdent: getCSSModuleLocalIdent,
                 },
                 ''less-loader''
               ),
            },

 

第六步 复制代码定义全局样式

//注释掉大概114行

// if (preProcessor) {
    //   loaders.push({
    //     loader: require.resolve(preProcessor),
    //     options: {
    //       sourceMap: isEnvProduction && shouldUseSourceMap,
    //     },
    //   });
    // }
    // return loaders;

//替换为如下
    if (preProcessor) {
      let loader = require.resolve(preProcessor)
      if (preProcessor === "less-loader") {
        loader = {
          loader,
          options: {
            modifyVars: { //自定义主题
              ''primary-color'': '' #1890ff '',
            },
            javascriptEnabled: true,
          }
        }
      }
      loaders.push(loader);
    }
    return loaders;

 

第七步 复制代码修改package.json

"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": true  //修改处
        }
      ]
    ]
  }

大概执行完以上代码之后,及支持less,同时也支持antd按需加载。

其实个人觉得没必要暴露webpack,当然我个人不了解webpack,我不是专业做前端的,因为公司用到这个,所以学习一下,

我觉得antd里使用文件的方式支持按需加载,更加简单方便。直接按照高级配置一步一步做就好了。也很方便。webpack太麻烦了,

哈哈,回头也要补充一下webpack方面的知识。

React 简单实例 (React-router + webpack + Antd )

React 简单实例 (React-router + webpack + Antd )

 

React Demo  Github 地址

经过React Native 的洗礼之后,写了这个 demo ;React 是为了使前端的V层更具组件化,能更好的复用,同时可以让你从操作dom中解脱出来,只需要操作数据就会改变相应的dom; 而React Native 是希望我们能够使用前端的技术栈就可以创建出能够在不同平台运行的一个框架,性能可能比原生app差一点点。

ReactJs和React Native的原理是相同的,都是由js实现的虚拟dom来驱动界面view层渲染。只不过ReactJs是驱动html dom渲染; React Native是驱动android/ios原生组件渲染。

React基于组件(component)开发,组件和组件之间通过props传递值,每个组件都有一个状态(state),当某个方法改变了这个状态值时,整个组件就会重新渲染,从而达到刷新(这里的刷新是指state的属性与之前的相比较,发生改变了就重绘,否则不变,相当于Vue里边的 watch函数)。另外,说到重新渲染就要提到虚拟dom了,就是用js模拟dom结构,等整个组件的dom更新完毕,才渲染到页面,简单来说只更新了相比之前改变了的部分,而不是全部刷新,所以效率很高。

目录我就不多介绍了,可以查看 github 中源码,主要实现了如下:

1,React JSX 语法实际使用

2,React 的生命周期,初始化,Rander 函数的渲染机制

3,React 常用的框架 Antd,图表插件 echarts 的使用

4,网络请求使用的 axiso  ,请求的封装,拦截,后端接口的统一管理封装 等

5,模块化,组件化 

具体功能点有: 表格,标签页 ,表单 ,轮播 ,网络请求实践 ,列表渲染, 图表, 富文本 等 . . . . . /

 

查看 : React-Antd-demo-one 

React+dva+webpack+antd-mobile 实战分享(一)

React+dva+webpack+antd-mobile 实战分享(一)

再看本篇文章之前,本人还是建议想入坑react的童鞋可以选有create-react-app来创建react的项目,因为现在dva和roadhog还不成熟,坑相对要多一些,当然如果你已经做好跳坑的准备,那么请继续往下走;

本文适合对 ES6+webpack 有一定了解的人。没有的了解的同学可以先看看下面的我分享的链接,

ES6: http://www.jianshu.com/p/ebfe...
Webpack: https://doc.webpack-china.org...
react: https://facebook.github.io/re...
antd-mobile:https://mobile.ant.design/doc...

扯完啦,接下来就是正题啦,先看效果

今天主要是想给大家说一下怎么用dva来搭建react的项目

第一步

安装 dva 和 roadhog;
    npm i dva-cli roadhog -g 
好啦~现在你已经学会了怎么安装dva和roadhog啦,接下来就可以创建项目啦

第二步

创建项目
dva new projectName
npm install
npm start

打开浏览器输入localhost:8000,看到欢迎界面证明第二步已经成功啦

第三步

添加配置文件和安装webpack

安装 lodash babel-plugin webpack-plugin shim 并添加到package.json文件中

npm install --save-dev webpack 安装本地webpack配置文件

webpack 文件
    // webpack配置
    import glob from 'glob';
    import webpack from 'webpack';
    import { isRegExp } from 'lodash';
    import pxtorem from 'postcss-pxtorem';
    import HtmlWebpackPlugin from 'html-webpack-plugin';
    import ExtractTextPlugin from 'extract-text-webpack-plugin';
    import LodashModuleReplacementPlugin from 'lodash-webpack-plugin';
    
    
    const path = require('path');
    export default ( webpackConfig,env ) => {
    
      const loaders = webpackConfig.module.loaders;
      const postcss = webpackConfig.postcss;
      webpackConfig.postcss = function () {
        const postcssArray = postcss();
        postcssArray.push( pxtorem( {
          rootValue: 100,propWhiteList: []
        } ) );
        return postcssArray;
      };
      const svgDirs = [
        require.resolve( 'antd-mobile' ).replace( /warn\.js$/,'' ),// antd-mobile 内置svg    // 引入antd-mobile
        path.resolve(__dirname,'src/assets/icon'),];
    
      loaders.forEach( ( loader ) => {
        if ( loader.test && loader.test.toString() === '/\\.svg$/' ) {
          loader.exclude = svgDirs;
        }
      } );
    
      loaders.unshift( {
        test: /\.svg$/,loader: 'svg-sprite',include: svgDirs
      } );
      const noparse = webpackConfig.module.noparse;
      if ( Array.isArray( noparse ) ) {
        noparse.push( /moment.js/ );
      }
      else if ( noparse ) {
        webpackConfig.module.noparse = [ noparse,/moment.js/ ];
      }
      else {
        webpackConfig.module.noparse = [ /moment.js/ ];
      }
    
      // lodash
      webpackConfig.babel.plugins.push( 'lodash' );
      webpackConfig.plugins.push( new LodashModuleReplacementPlugin() );
    
      loaders.push( {
        test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i,loader: 'file'
      } );
    
      // 打包配置
      if ( env === 'production' ) {            
         //添加hash
        webpackConfig.output.filename = '[name].[chunkhash:6].js';
        webpackConfig.output.chunkFilename = '[name].[chunkhash:6].js';
    
        webpackConfig.plugins.forEach( ( plugin,index,plugins ) => {
          if ( plugin instanceof ExtractTextPlugin ) {
            plugins[ index ] = new ExtractTextPlugin( '[name].[chunkhash:6].css',{
              disable: false,allChunks: true
            } );
          }
          else if ( plugin instanceof webpack.optimize.CommonsChunkPlugin ) {
            plugins[ index ] = new webpack.optimize.CommonsChunkPlugin(
                'common','common.[chunkhash:6].js'
            );
          }
        } );
    
      }
      //HTML
      webpackConfig.module.loaders = loaders.filter(
              loader => isRegExp( loader.test ) && loader.test.toString() !== '/\\.html$/'
      );
      webpackConfig.plugins.push(
          new HtmlWebpackPlugin( {
            // favicon: './src/logo/logo.ico',template: './src/index.html',filename: 'index.html',inject: true
          } )
      );
    
      return webpackConfig;
    };

到现在你已经完成了一半啦 是不是觉得很简单。对啦 这里有一点要注意,复制 es5-shim.min.js es5-sham.min.js console-polyfill/index.js 文件到 public 文件夹console-polyfill/index.js 改名为 console-polyfill.js

第四步 roadhog、proxy配置和antd-mobile引入

废话不说 这步直接上代码(对应的是目录中的.roadhogrc.js,大学按步骤下来的话这应该是.roadhogrc.json的文件,但是本人还是比较喜欢js语法,所以做了修改,此处因人而异)
     import path from 'path';
    
    export default {
     '/api': {
        target:'localhost',//这里是你的接口地址,我随便写的
        changeOrigin: true
      },multipage: true,theme: 'antd.config.js',entry: [ 'src/common.js','src/index.js' ],env: { //下面是在开发环境和生产环境都引入antd-mobile
        development: {
          extraBabelPlugins: [
            'dva-hmr','transform-runtime',[ 'import',{ libraryName: 'antd-mobile',style: true }]
          ]
        },production: {
          extraBabelPlugins: [
            'transform-runtime',style: true }]
          ]
        }
      }
    };

好啦,以上四步差不多就可以用dva把react的项目架子搭建起来,再有就是eslint的配置啦,此处不做讲解(http://eslint.org/docs/user-g...),接下来你可以在src中尝试着运行一下Hello World啦

还有一个点需要注意的是,dva 建项目的时候会默认安装redux和react-router,所以在开发中千万不要在去安装,会因为版本不兼容而导致项目无法运行;

最后给大家分享一些用到的资料
antd主题制定: https://ant.design/docs/react...
roadhog: https://github.com/sorrycc/ro...
webpack中proxy配置: https://webpack.github.io/doc...
redux: http://www.redux.org.cn/
react-router: http://react-guide.github.io/...

项目地址:https://github.com/tengwei30/...

更多精彩敬请期待。。。

React+dva+webpack+antd-mobile 实战分享(二)

React+dva+webpack+antd-mobile 实战分享(二)

第一篇 https://segmentfault.com/a/11...

在上一篇文章中教给大家了怎么搭建项目的架子;那么今天我们就来说一下项目里的导航和列表的实现

导航

图片描述

废话不说啦 下面直接给大家讲一下代码
项目用的antd-mobile的框架 应该没什么难度,我相信大家认真看文档的都能布局出来;

TabButton.js

import React, { Component } from ''react'';
import { Tabs, WhiteSpace,ListView,Toast} from ''antd-mobile'';
import { routerRedux } from ''dva/router'';
import { connect } from ''dva'';
import Request from ''../common/fetch''
import {width,height} from ''../common/style'';

const TabPane = Tabs.TabPane;

class TabButton extends Component {
  constructor(props) {
    super(props);
    this.state = {
      channels: []
    }
  }
 
  componentDidMount() {
  // 这个地方是封装的fetch请求;
    Request(''/api/article/channel'',{
      secret:1111,
    },((res) => {
      this.setState({
        channels: res.result.channels
      })
      // 请求过来的数据全部存下来,以便后期调用,同时可以减少请求
      this.props.dispatch({
        type: ''indexList/TabData'',
        payload: res.result.channels,
      });
    }))
  }
//这个点需要注意:此处是将click事件传递给子组件,另一界面 <TabButton ButtonClick ={this.ButtonClick.bind(this)} />就可以取到此组件传递过去的click事件;
  _handleTabClick(key){
    this.props.ButtonClick(key);
  }

  _renderList() {
    let result = [];
    const channels = this.state.channels;
    for(let i in channels) {
      if(channels[i].attval == 1 || channels[i].attval == 2){
        result.push(
          <TabPane tab={`${channels[i].title}`} key={`${parseInt(channels[i].ID)}`}>
            <div style={{ display: ''flex'', alignItems: ''center'', justifyContent: ''center'',border:''none'' }}>
            </div>
          </TabPane>
        )
      }
    }
    return result
  }

  _getMore() {
    this.props.dispatch(
      routerRedux.push(''/moreChannel'')
    )
  }

  render() {
    return(
      <div style={{position:''fixed'',top:44,zIndex:999,backgroundColor:''#fff'',width:(width/7)*6}}>
        <Tabs defaultActiveKey="1"
              pageSize={7}
              onTabClick={(key) => {this._handleTabClick(key)}}
              swipeable = {false}
          >
          {this._renderList()}
        </Tabs>
        <p style={styles.moreChannel} onClick={() => this._getMore()}>
          <img style={{width:26,height:26,marginTop:8,marginLeft:14}} src={require(''../../assets/list/addchannel@2x.png'')} alt=""/>
        </p>
      </div>
    )
  }
}

const styles = {
  moreChannel:{
    position:''absolute'',
    top:0,
    right:-width/7,
    zIndex:9999,
    width:width/7,
    height:42,
    backgroundColor:''#fff'',
    alignItems:''center'',
    justifyContent:''center''
  }
}


function indexList({indexList}) {
  return { indexList };
}

export default connect(indexList)(TabButton);

fetch.js

export default function Request(url,body,callback){
  fetch(url,{
    method: ''POST'',
    mode: "cors",
    headers: {
      ''Content-Type'': ''application/json'',
      ''Accept'': ''application/json''
    },
    body: JSON.stringify(body)
  }).then((res) => res.json()).then((res) => {
    callback(res)
  }).catch((err) => {
    console.log(err)
  })
}

列表

indexTab.js

import React, { Component,PureComponent,PropTypes } from ''react'';
import { Tabs, WhiteSpace,ListView,Toast} from ''antd-mobile'';
import { routerRedux } from ''dva/router'';
import { connect } from ''dva'';
import ReactPullLoad,{ STATS } from ''react-pullload'';
import TabButton from ''./TabButton'';
import {width,height} from ''../common/style'';

let devicenum = localStorage.getItem(''devicenum'')
const loadMoreLimitNum = 10;

const defaultStyle ={
  width: "100%",
  textAlign: "center",
  fontSize: "14px",
  lineHeight: "1.5",
  paddingTop:"12px",
  color:''#ccc''
}

class HeadNode extends PureComponent{

  static propTypes = {
    loaderState: PropTypes.string.isRequired,
  };

  static defaultProps = {
    loaderState: STATS.init,
  };

  render(){
    const {
      loaderState
      } = this.props

    let content = ""
    if(loaderState == STATS.pulling){
      content = "下拉刷新"
    } else if(loaderState == STATS.enough){
      content = "松开刷新"
    } else if(loaderState == STATS.refreshing){
      content = "正在刷新..."
    } else if(loaderState == STATS.refreshed){
      content = "刷新成功"
    }

    return(
      <div style={defaultStyle}>
        {content}
      </div>
    )
  }
}


class FooterNode extends PureComponent{
  static propTypes = {
    loaderState: PropTypes.string.isRequired,
    hasMore: PropTypes.bool.isRequired
  };

  static defaultProps = {
    loaderState: STATS.init,
    hasMore: true
  };

  render(){
    const {
      loaderState,
      hasMore
      } = this.props
    let content = ""
    if(loaderState == STATS.loading){
      return(
        <div style={defaultStyle}>
          <img src={require(''../../assets/state/fail@2x.png'')} alt="" style={{width:32,height:40}} />
          <span>正在加載喔~</span>
        </div>
      )
    } else if(hasMore === false){
      content = "没有更多"
    }

    return(
      <div style={defaultStyle}>
        {content}
      </div>
    )
  }
}


class indexTab extends Component {
  constructor(props) {
    super(props)
    this.state = {
      channels : [],
      channelid : 1,
      showT:false,
      loading : false,
      hasMore: true,
      data: [],
      action: STATS.init,
      index: loadMoreLimitNum,
      newsLength:''''
    }
  }

  componentDidMount() {
    this.getListData(this.state.channelid);
  }

  getListData(channelid) {
    // List
    fetch(''/api/article'',{
      method: ''POST'',
      mode: "cors",
      headers: {
        ''Content-Type'': ''application/json'',
        ''Accept'': ''application/json''
      },
      body: JSON.stringify({
        channelID: channelid,
        type: 0,
        pageSize: 10,
        dt : 2,
        action: 1,
        devicenum:devicenum
      })
    }).then((res) => res.json()).then((res) => {
      this.setState({
        data: res.result.news,
        newsLength:res.result.news.length
      })
      this.props.dispatch({
        type: ''indexList/detailData'',
        payload: res.result.news,
      });
    }).then(() => {
      setTimeout(() => {
        this.setState({
          showT : true
        })
      },1900)
    }).then(() => {
      setTimeout(() => {
        this.setState({
          showT : false
        })
      },2900)
    }).catch((err) => {
      console.log(err)
    })
  }

  handleAction = (action) => {
    console.info(action, this.state.action,action === this.state.action);
    if(action === this.state.action){
      return false
    }
    if(action === STATS.refreshing){//刷新
      this.handRefreshing();
    } else if(action === STATS.loading){
      this.handLoadMore();
    } else{
      this.setState({
        action: action
      })
    }
  }
  handRefreshing = () =>{
    if(STATS.refreshing === this.state.action){
      return false
    }
    this.getListData(this.state.channelid)
    setTimeout(()=>{
      this.setState({
        action: STATS.refreshed,
        index: loadMoreLimitNum
      });
    }, 3000)

  }
  handLoadMore = () => {
    if(STATS.loading === this.state.action){
      return false
    }
    setTimeout(()=>{
      if(this.state.index === 0){
        this.setState({
          action: STATS.reset,
          hasMore: false
        });
      } else{
        fetch(''/api/article'',{
          method: ''POST'',
          headers: {
            ''Content-Type'': ''application/json;charset=UTF-8'',
            ''Accept'': ''application/json''
          },
          body: JSON.stringify({
            channelID: this.state.channelid,
            type: 0,
            pageSize: 10,
            dt : 2,
            action: 1,
            devicenum:devicenum
          })
        }).then((res) => res.json()).then((res) => {
          this.setState({
            data: [...this.state.data,...res.result.news],
              action: STATS.reset,
              index: this.state.index - 1
          })
          this.props.dispatch({
            type: ''indexList/detailData'',
            payload: [...this.state.data,...res.result.news],
          });
        }).then(() => {
          console.log(this.state.showT)
          setTimeout(() => {
            this.setState({
              showT : true
            })
          },1900)
        }).then(() => {
          setTimeout(() => {
            this.setState({
              showT : false
            })
          },2900)
        }).catch((err) => {
          console.log(err)
        })
      }
    }, 3000)
    this.setState({
      action: STATS.loading
    })
  }

  //跳转到详情页
  _routerDetail(index) {
    localStorage.setItem(''detailid'',index)
    this.props.dispatch(
      routerRedux.push(`/detail/${index}`)
    )
  }

  //Tab 切换重新调取
  ButtonClick(key) {
    this.getListData(key);
    this.setState({
      channelid:key
    })
  }

  _renderShow() {
    if(this.state.showT == true){
      if(this.state.newsLength != 0){
        return(
          <p style={styles.more}>更新了{this.state.newsLength}条内容</p>
        )
      }else{
        return(
          <p style={styles.more}>暂無更新推送</p>
        )
      }
    }else{
      return(
        <p></p>
      )
    }
  }

  render(){
    const {data,hasMore} = this.state
    return (
      <div>
        <TabButton
          ButtonClick = {this.ButtonClick.bind(this)}
          />
        <p style={{width:100,height:80}}></p>
        <ReactPullLoad
          downEnough={50}
          action={this.state.action}
          handleAction={this.handleAction}
          hasMore={hasMore}
          distanceBottom={10}
          HeadNode={HeadNode}
          FooterNode={FooterNode}
          >
          <ul className="test-ul">
            {
              data.map( (str, index )=>{
                if(str.images[0] != ''''){
                  return <li key={index}>
                    <div style={styles.news} onClick = {() => this._routerDetail(index)}>
                      <img src={str.images[0]} style={styles.imgStyle} />
                      <p style={styles.newsTitle}>{str.title}</p>
                      <p style={{fontSize:12,color:''#ccc'',borderWidth:1}}><span style={{color:''#03D7FF''}}>{str.source}</span> | {str.publishTime}</p>
                    </div>
                  </li>
                }else{
                  return <li key={index}>
                    <div style={styles.news} onClick = {() => this._routerDetail(index)}>
                      <p style={styles.newsTitle}>{str.title}</p>
                      <p style={{fontSize:12,color:''#ccc'',borderWidth:1}}><span style={{color:''#03D7FF''}}>{str.source}</span> | {str.publishTime}</p>
                    </div>
                  </li>
                }
              })
            }
          </ul>
        </ReactPullLoad>
        <div>
        </div>
        {this._renderShow()}
      </div>
    )
  }

}


const styles = {
  more: {
    width:width,
    backgroundColor:''#FFDB01'',
    position:''absolute'',
    zIndex:9999,
    top:86,
    textAlign:''center'',
    padding:5,
    fontSize:14,
    display:''block'',

  },
  news: {
    padding:15,
    justifyContent:''center'',
    alignItems:''center''
  },
  imgStyle: {
    width:width-30,
    //height:100
  },
  newsTitle: {
    fontSize:18,
    marginTop:10,
    marginBottom:10
  },
  moreTab: {
    width:width-(width/7)*6,
    height:43,
    backgroundColor:''#fff'',
    position: ''absolute'',
    justifyContent:''center'',
    alignItems:''center'',
    top:44,
    right:0,
    zIndex:9999
  }
}
function indexList({ indexList }) {
  return { indexList };
}
export default connect(indexList)(indexTab);

好啦 上述就是整个首页的主要代码,知道如何创建项目的你们可以尝试啦~~~

关于dva+react+antd+webpack 项目开发配置react dva介绍的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于create-react-app脚手架创建react项目,暴露webpack配置文件,如何引入less支持+antd按需加载+自定义主题、React 简单实例 (React-router + webpack + Antd )、React+dva+webpack+antd-mobile 实战分享(一)、React+dva+webpack+antd-mobile 实战分享(二)等相关知识的信息别忘了在本站进行查找喔。

本文标签: