(二)使用npm搭建React项目

一.在内地npm预设是连线到国外的registry,我们可已更改为taobao代理的registry,这样安装包的速度可已加快

二.使用npm建立项目package.json

 

 

 

 

 

 

 

  • 切换到项目的目录下,直接下 npm init,输入相关资料,若不输入则使用预设即可

三.使用npm安装开发用的依赖包

  • 安装全域使用的包,npm install 命令后加入 -g

    npm install npm webpack -g

  • 安装项目依赖包,项目发布所依赖的包,需在 npm install 命令后加入 --save
    我们主要使用react、redux、jquery和antd等相关js库进行开发,需安装如下的包:

    npm install antd history jquery react react-dom redux react-redux react-router redux-promise-middleware redux-thunk redux-logger --save

  • 安装开发用的依赖包,此依赖包只有在项目打包时会用到,需在 npm install 命令后加入 --save-dev
    在这里我们主要用到的依赖包webpack、babel、es6、css-loader、file-loader和jsx-loader等相关的编译用的包,命令如下:

    npm install autoprefixer babel babel-cli babel-core babel-loader babel-plugin-antd babel-plugin-import babel-plugin-transform-runtime babel-polyfill babel-preset-es2015 babel-preset-react babel-preset-stage-0 babel-runtime clean-webpack-plugin console-polyfill copy-webpack-plugin css-loader es3ify-loader es6-promise eventsource-polyfill extract-text-webpack-plugin file-loader html-webpack-plugin jsx-loader less less-loader object-assign postcss-loader react-hot-loader sass-loader style-loader url-loader webpack webpack-dev-server --save-dev

    在此针对介绍 webpack 和 bebal 进行基本介绍

    Webpack 是当下最热门的前端资源模块化管理和打包工具。

    Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:entry.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个浏览器可识别的JavaScript文件。

    它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源,还可以将按需加载的模块进行代码分隔,等到实际需要的时候再异步加载。

    通过 loader 的转换,任何形式的资源都可以视作模块,比如 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。


    其中Webpack的Loaders是webpack中最让人激动人心的功能之一了。

    通过使用不同的loader,webpack通过调用外部的脚本或工具可以对各种各样的格式的文件进行处理,比如说分析JSON文件并把它转换为JavaScript文件,或者说把新一代的JS文件(ES6,ES7)转换为现代浏览器可以识别的JS文件,或者说对React的开发而言,合适的Loaders可以把React的JSX文件转换为JS文件。 

    Babel其实是一个编译JavaScript的平台,它的强大之处表现在可以通过编译帮你达到以下目的:

     

    • 新一代的JavaScript标准(ES6,ES7),这些标准目前并未被当前的浏览器完全的支持;
    • 使用基于JavaScript进行拓展的语言编译,比如React的JSX; 

    Webpack参考学习网站 http://webpackdoc.com/index.html

四.建构开发的相应目录和档案

  • src 【源码目录】
    • components 【jsx控件存放目录】
    • styles 【css存放目录】
    • templates 【index.html模板目录】
    • entry.js 【主应用程式】
  • build 【打包后的源码目录】
  • webpack-config.js 【webpack项目管理配置档】
  • package.json 【npm init 自动产生的包管理配置档案】 
    基本目录如下图:

五.建立webpack.config.js配置档

  • webpack基本的项目配置如下:
/**
 * 载入webpack需要的js模组
 **/
var path = require('path');
var webpack = require('webpack');

//设定项目的根目录
var ROOT_PATH = path.resolve(__dirname);

//设定 source path
var SRC_PATH = path.resolve(__dirname, './src');

//设定应用程式进入JS档案
var APP_PATH = path.resolve(__dirname, './src/entry.js');

//设定打包结果目录
var BUILD_PATH = path.resolve(__dirname, './build');

//使用 extract-text-webpack-plugin 可以把 css 从 js 中独立抽离出来
var ExtractTextPlugin=require("extract-text-webpack-plugin");

//使用 CommonsChunkPlugin 抽取公共代码
var CommonsChunkPlugin=require("webpack/lib/optimize/CommonsChunkPlugin");

//使用 HtmlWebpackPlugin 可以帮助生成HTML文件,在body元素中,使用 script 来包含所有你的 webpack bundles
var HtmlWebpackPlugin = require('html-webpack-plugin'); //依模板生成html

// 使用 CleanPlugin 删除你以前build过的文件
var CleanPlugin = require('clean-webpack-plugin');

// 使用 CopyWebpackPlugin 拷贝资源文件到 BUILD_PATH中
var CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {
  /* 提供source-map方便Debug用,若要部署至正式机,请关闭此选项 */
  devtool: 'eval-source-map',

  /* 配置应用程式进入js档案 */
  entry: {
    main:[APP_PATH]
  },

  /* 配置输出预设的路径,和依需载入打包【将每个组件打包成自己的js,在使用时才进行载入】 */
  output: {
    path:BUILD_PATH,
    filename:'[name].js',
    chunkFilename:'components/[name].[chunkhash:5].min.js'
  },

  /* 表示这个依赖项是外部lib,遇到require 或 import它不需要编译,且在浏览器端对应window.React*/
  externals: [{
    'antd': 'window.antd',
    'react': 'window.React',
    'react-dom': 'window.ReactDOM',
    'jquery': 'window.jQuery',
  }],

  /* 设定打包时查找的类型,增加查询打包速度 */
  resolve:{
    root:['js','jsx','css','scss','less']
  },

  /* 配置开启 Debug 模式,暂不知到如何使用 */
  debug: true,

  /* 模组Loader配置 */
  module: {
    loaders: [
      /* 档案匹配 .js 进行 babel es6转换 */
      { test: /\.js$/,
        loader: "babel", include: /src/,exclude: /node_modules/
      },
      /* 档案匹配 .jsx 进行 babel es6转换,然后再进行 jsx 语法转换【转换规则由右至左】*/
      { test: /\.jsx$/,
        loader: "jsx!babel", include: /src/,exclude: /node_modules/
      },
      /* 档案匹配 .css 进行 【css样式加前缀】语法转换,【转换规则由右至左】*/
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract("style", "css!postcss")/*,include: /src/,exclude: /node_modules/*/
      },
      /* 档案匹配 .sass 进行 sass 语法转换为 css,【转换规则由右至左】*/
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract('style', 'css!postcss!sass'),include: /src/,exclude: /node_modules/
      },
      /* 档案匹配 .less 进行 less 语法转换为 css,【转换规则由右至左】*/
      {
        test:/\.less$/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader"),include: /src/,exclude: /node_modules/
      },
      /* url-loader 的配置,将小于80K的静态图片转为Base64字符串,减少网路请求压力 */
      {
        test:/\.(png|jpg)$/,
        loader:'url?limit=8192&name=images/[hash:8].[name].[ext]',include: /src//*,exclude: /node_modules/*/
      }],

    /* 项目兼容IE8时,需要进行 ES3的语法转换
    postLoaders: [{
        test: /\.js$/,
        loaders: ['es3ify-loader']
      },{
        test: /\.jsx$/,
        loaders: ['es3ify-loader']
    }]*/

  },

  /* presets字段设定转码规则,官方提供以下的规则集,你可以根据需要安装 【预设使用 ES2015(ES6)转码规则、ES7第0阶段的转码规则和react转码规则】*/
  babel: {
    presets: ['es2015', 'stage-0', 'react'],
  },

  /* 调用autoprefixer插件,css3自动补全 */
  postcss: [
    require('autoprefixer')
  ],

  /* 配置webpack开发服务器设定的Port */
  devServer:{
    port:8080,
    host:"0.0.0.0",
    colors: true,  //终端中输出结果为彩色
    historyApiFallback: true,  //不跳转
    inline: true,  //实时刷新
    outputPath:BUILD_PATH,
    /* 代理服务器的配置 */
    proxy:{
      '/api/*': {
        target: 'http://192.168.4.208:8083',
        pathRewrite: {'^/api' : '/'},
        changeOrigin: true
      },
      '/api/*': {
        target: 'ws://192.168.4.208:8083',
        pathRewrite: {'^/api' : '/'},
        ws:true,
        changeOrigin: true
      }
    }
  },

  /**
   * webpack 常用插件配置
  **/
  plugins: [
    new CleanPlugin(BUILD_PATH),

    new CommonsChunkPlugin({
       name: 'vendor',
       filename: '[name]-[hash].min.js'
    }),

    new ExtractTextPlugin('[name].css'),

    new HtmlWebpackPlugin({  //根据模板插入css/js等生成最终HTML
      filename: './index.html', //生成的html存放路径,相对于 path
      template: './src/templates/index.html', //html模板路径
      hash: false,
    }),

    new webpack.optimize.UglifyJsPlugin(),

    new webpack.ProvidePlugin({
      Moment: 'moment', //直接从node_modules中获取
      $:"jquery",
      jQuery:"jquery",
      "window.jQuery":"jquery"
    }),

    new CopyWebpackPlugin([{
        from: 'node_modules/jquery/dist/jquery.min.js',
        to: ROOT_PATH + '/build/js'
      },{
        from: 'node_modules/react/dist/react.min.js',
        to: ROOT_PATH + '/build/js'
      },{
        from: 'node_modules/react-dom/dist/react-dom.min.js',
        to: ROOT_PATH + '/build/js'
      },{
        from: 'node_modules/antd/dist/antd.min.css',
        to: ROOT_PATH + '/build/styles'
      },{
        from: 'node_modules/antd/dist/antd.min.js',
        to: ROOT_PATH + '/build/js'
      }
    ])
  ]
};



六.修改package.json的配置

  • package的配置如下:
    {
    "name": "webpack_react_example",
    "version": "1.0.0",
    "description": "",
    "main": "entry.js",
    "scripts": {
      /** 请增加 build 和 dev 的配置 【注意:此文档不可有注解,需将注解删除】**/
      "build": "webpack -p",
      "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build",
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
      "antd": "^2.5.3",
      "history": "^4.5.0",
      "jquery": "^3.1.1",
      "react": "^15.4.1",
      "react-dom": "^15.4.1",
      "react-redux": "^5.0.1",
      "react-router": "^3.0.0",
      "redux": "^3.6.0",
      "redux-logger": "^2.7.4",
      "redux-promise-middleware": "^4.2.0",
      "redux-thunk": "^2.1.0"
    },
    "devDependencies": {
      "autoprefixer": "^6.6.0",
      "babel": "^6.5.2",
      "babel-cli": "^6.18.0",
      "babel-core": "^6.21.0",
      "babel-loader": "^6.2.10",
      "babel-plugin-antd": "^0.5.1",
      "babel-plugin-import": "^1.1.0",
      "babel-plugin-transform-runtime": "^6.15.0",
      "babel-polyfill": "^6.20.0",
      "babel-preset-es2015": "^6.18.0",
      "babel-preset-react": "^6.16.0",
      "babel-preset-stage-0": "^6.16.0",
      "babel-runtime": "^6.20.0",
      "clean-webpack-plugin": "^0.1.14",
      "console-polyfill": "^0.2.3",
      "copy-webpack-plugin": "^4.0.1",
      "css-loader": "^0.26.1",
      "es3ify-loader": "^0.2.0",
      "es6-promise": "^4.0.5",
      "eventsource-polyfill": "^0.9.6",
      "extract-text-webpack-plugin": "^1.0.1",
      "file-loader": "^0.9.0",
      "html-webpack-plugin": "^2.24.1",
      "jsx-loader": "^0.13.2",
      "less": "^2.7.1",
      "less-loader": "^2.2.3",
      "object-assign": "^4.1.0",
      "postcss-loader": "^1.2.1",
      "react-hot-loader": "^1.3.1",
      "sass-loader": "^4.1.1",
      "style-loader": "^0.13.1",
      "url-loader": "^0.5.7",
      "webpack": "^1.14.0",
      "webpack-dev-server": "^1.16.2"
      }
    }


七.建立 index.html 的范本样例档案

  • index.html 基本样例如下

    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8"/>
      <meta name="viewport" content="width=device-width, initial-scale=1"/>
      <meta http-equiv="x-ua-compatible" content="ie=edge"/>
      <title>Hello World</title>
      <!--[if lt IE 10]>
        <script src="./js/matchMedia.js"></script>
        <script src="./js/matchMedia.addListener.js"></script>
        <script src="./js/respond.min.js"></script>
      <![endif]-->
    
      <!-- <link rel="stylesheet" href="./styles/antd.min.css"> -->
      <meta name="viewport" content="width=device-width, initial-scale=1"/>
    </head>
    <body>
      <!-- 公用的Javascript library -->
      <script src="./js/jquery.min.js"></script>
      <script src="./js/react.min.js"></script>
      <script src="./js/react-dom.min.js"></script>
      <script src="./js/antd.min.js"></script>
    
      <div id="app"></div>
    
    </body>
    </html>

八.撰写 src/entry.js 的应用进入的javascript程序

entry.js 代码如下:

import React from 'react';
import ReactDOM from 'react-dom';
import HelloWorld from './components/HelloWorld/helloworld.jsx';

ReactDOM.render((
<div>
  HelloWorld组件范例:<p></p>
  <HelloWorld name="React"/>
</div>
),document.getElementById('app'));



九.建立 Hello World 组件

  • 什么是React,其实React只能算是一个前端UI的渲染引擎,只是这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。
    衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。
    如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机,有兴趣的同事可以到 http://www.ruanyifeng.com/blog/2015/02/future-of-dom.html 看看。 

下面我们先建立一个 HelloWorld 的组件:

  • 在src/components资料夹中,建立Helloworld的组件资料夹和一个helloworld.jsx档案,如下图:

  • 添加helloworld.jsx代码,如下范例:

/**
* 使用 ES6 的语法,撰写 HelloWorld 组件代码
**/
import React from 'react';
import ReactDOM from 'react-dom';

export default class HelloWorld extends React.Component{

  /**
   * 组件的构造函数
   **/
  constructor(props){
    super(props);
    this.state={name:props.name};
  }

  /**
   * componentWillMount 在组件出现前,html的dom还未被渲染前,被调用的方法
  **/
  componentWillMount(){
    console.log('React 组件初次加载,最先呼叫 componentWillMount...',this.state);
  }

  /**
   * componentDidMount 在html的dom被组件渲染完成后,被调用的方法
  **/
  componentDidMount(){
    console.log('React 组件初次加载且渲染完成后被呼叫 componentDidMount...',this.state);
  }

  /**
   * componentWillReceiveProps 组件被加载后,收到新的参数时被调用的方法
  **/
  componentWillReceiveProps(nextProps){
    console.log('React 组件收到上层传下来的props时调用 componentWillReceiveProps...',this.state);
    this.setState({name:nextProps.name});
  }

  /**
   * 组件发生改变时执行,应该将this.props和nextProps、this.stats和nextState进行比较,返回true或false决定组件是否更新
  **/
  // shouldComponentUpdate(nextProps, nextState){}

  /**
   * 组件更新前执行 【不能在此处调用this.setState()】
  **/
  componentWillUpdate(nextProps, nextState){
    console.log('React 组件更新前执行调用 componentWillUpdate...',this.state);
  }

  /**
   * 组件更新后执行
  **/
  componentDidUpdate(nextProps, nextState){
    console.log('React 组件更新后执行调用 componentDidUpdate...',this.state);
  }

  /**
   * 组件被移除前执行
  **/
  componentWillUnmount(){
    console.log('React 组件被移除前执行 componentWillUnmount...');
  }

  /**
   * 使用ES6箭头函数,撰写handleClick
  **/
  handleChange = (event) => {
    console.log('呼叫 handleChange 传入值:',event.target.value);
    this.setState({name:event.target.value});
  }

  /**
   *
  **/
  handleClick = (value) => {
    console.log('呼叫 handleClick 传入值:',this);
    this.setState({name:value});
  }

  /**
   * HelloWorld组件渲染
   * render的语法使用的是JSX
   **/
  render(){
    return (
      <div>
        Hello World, {this.state.name} <p></p>
        <input type="text" value={this.state.name} onChange={this.handleChange.bind(this)}/>
        &nbsp;&nbsp;
        <button onClick={this.handleClick.bind(this,'小灯鱼')}>小灯鱼</button>

    </div>
    );
  }

}
  • 针对 React 组件的生命周期可分为三种状态
    Mounting:已插入真实 DOM
    Updating:正在被重新渲染
    Unmounting:已移出真实 DOM
  • 针对React的props和state在此进行说明基本的说明 需要理解的是,props是一个父组件传递给子组件的数据流,这个数据流可以一直传递到子孙组件。
    而state代表的是一个组件内部自身的状态(可以是父组件、子孙组件)。
    改变一个组件自身状态,从语义上来说,就是这个组件内部已经发生变化,有可能需要对此组件以及组件所包含的子孙组件进行重渲染。
    而props是父组件传递的参数,可以被用于显示内容,或者用于此组件自身状态的设置(部分props可以用来设置组件的state),不仅仅是组件内部state改变才会导致重渲染,父组件传递的props发生变化,也会执行。
    既然两者的变化都有可能导致组件重渲染,所以只有理解pros与state的意义,才能很好地决定到底什么时候用props或state。

  • 针对JSX语法进行基本说明 JSX语法,像是在Javascript代码里直接写XML的语法,实质上这只是一个语法糖,每一个XML标签都会被JSX转换工具转换成纯Javascript代码,React 官方推荐使用JSX, 当然你想直接使用纯Javascript代码写也是可以的,只是使用JSX,组件的结构和组件之间的关系看上去更加清晰。

注意:在JSX中若需要使用 class 指定 css的class,需要改成 className,才可正常使用,class是JSX的保留字。

JSX语法的范例如下:

//使用JSX
React.render(
    <div>
        <div>
            <div>content</div>
        </div>
    </div>,
    document.getElementById('example')
);

//不使用JSX
React.render(
    React.createElement('div', null,
        React.createElement('div', null,
            React.createElement('div', null, 'content')
        )
    ),
    document.getElementById('example')
);

十.执行npm启动开发服务器

  • 使用 npm run dev 即可启动,预设的访问路径为 http://localhost:8080

  • 至此React基本介绍到此结束

猜你喜欢

转载自bigdragon.iteye.com/blog/2373398