爱前端 2018react 技术分享一

2018-06-27 15:12:53 +08:00
 aiqianduan

特点 1:这种项目几乎都是单页面应用( SPA,single page application ),整个项目就是一个 html 页面。 注意下面的两个页面的 URL 网址,只有#后面的内容在变化,而#之前的内容没有变化。

也就是说,网页没有发生跳转,而是 DOM 的整体上树、下树。这样的好处是,让本地变量可以在本地持久的时间变长。

特点 2,都是组件化的。 比如我们找到了两个页面上都用了这样的一个日期组件:

也就是说,这些日历,不管是 HTML、CSS 还是 JS 交互,都能复用的。

特点 3:所有的 DOM 元素都是动态上树的,页面上没有了 HTML 清单,所有的部件,都是组件,组件套组件,集体被 js 上树。 我们可以查看源代码,发现没有任何 DOM:

所以 React 和 Vue 包括已经过时的 Angular 是什么: 提供组件化开发的、单页面应用的、动态上树的模块化开发的框架。

二、webpack 基本使用 2.1 复习一下传统的前端开发多个 js 文件的关系 比如 yuan.js 中定义了一个函数: function mianji(r){ return 3.14 * r * r; } 然后 main.js 文件中调用了这个函数: alert(mianji(10));

在页面上引入(按顺序引入)这两个 js 文件:

<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="yuan.js"></script> <script src="main.js"></script> </body> </html> 能够弹出计算后的值:

yaun.js 中定义的函数,实际上是 window 对象的属性,因为这个函数是全局的函数。所以 main.js 中当然能够访问同一个 window 对象的函数。但是我们说,这两个 js 文件之间,没有“强的引入”关系。

如果两个 js 文件之间,能够像 nodejs 的多个 js 文件之间,有暴露、有引入那该多好? exports.mianji = mianji;

var yuan= require("./yuan.js");

我们试着写了 exports、require(),但是浏览器报错:

不认识这两个词语。

在 ES6 中新增了 js 文件的暴露和引入的新的写法(重点): W3C 那些老头想,我曹,Rynl Dahl 那个小孩子挺牛逼的啊,发明了 exports 和 require()挺好用的!我们也指定一个标准吧!于是研究出了这样的语法: 暴露: 引入:

W3C 的新的发明的词语,export 和 import 也不被浏览器支持。

搞毛啊????? 没事,webpack 解决了这一切!

小知识:实际上在 2005 年(比 nodejs 还早),就有美国的程序员发明了 commonjs,中国程序员阿里巴巴玉伯发明了 seajs,都解决了 export 和 require 的识别问题。因为这个规范是 commonjs 提出的,所以叫做 CMD 规范,common module definition,通用模块定义。即 nodejs 也遵循 CMD 规范,即 nodejs 并不是 CMD 规范的发明人。

2.2 webpack 的安装 在 2 月 26 日 webpack 除了 4 代,我们学习 4 代,基本变化不大。

webpack 是 nodejs 工作流工具,所以要通过-g 安装。安装之前,电脑中要有 nodejs 环境。 npm install -g webpack npm install -g webpack-cli

安装完毕之后,就要用 webpack -v 来确认安装成功

2.3 webpack 的基本使用(重点,也是分水岭) 项目是这样的:

其中两个 js 文件的代码符合 CMD 规范: main.js: yuan.js:

此时在这个文件夹中,打开命令行窗口,键入命令: webpack main.js -o all.js

我们的 index.html 要引入:

<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script src="all.js"></script> </body> </html>

此时打开浏览器,即可看见结果:

我们看一下 all.js 的源程序:

也就是说,webpack 进行了 3 个事情: 第一,从 main.js 出发,顺着 import 链儿寻找每一个 js 文件 第二,将每一个 js 文件智能打包。比如一个 export 暴露的函数没有被使用,将不会被打包; 第三,去 import、export 化,也就是说,all.js ,是 IE8 兼容的。

webpack 是一个构建工具。

2.4 使用 webpack.config.js 文件来指导 webpack 的工作(分水岭) 我们要在项目的根,创建一个 webpack.config.js 文件,就能指导 webpack 工作。

不要求背诵,但是要求能够根据 API 文档,写出来。

https://doc.webpack-china.org/configuration/ 加入收藏夹。

根据这个网页的中文说明,截取我们需要的配置: 最简单的配置如下(谁被谁没出席,谁直接用老师的,更没出息),必须自己会去官网配:

const path = require('path');

module.exports = { entry: "./app/main.js", //入口文件 output: { //出口文件 path: path.resolve(__dirname, "dist"), //打包到哪个文件夹中 filename: "bundle.js" //打包到哪个文件 } } 这个 webpack.config.js 文件,已经拥有了这个配置文件的最小要素:入口、出口。

文件架构:

有了 webpack.config.js 文件之后,我们现在要打包 js 文件,此时只需要运行 webpack 即可。

为了实时监控文件的变化,此时我们必须,加上一个 watch:true const path = require('path');

module.exports = { entry: "./app/main.js", //入口文件 output: { //出口文件 path: path.resolve(__dirname, "dist"), //打包到哪个文件夹中 filename: "bundle.js" //打包到哪个文件 }, watch : true , mode: "development" //要求写的,表示当前正在开发模式 } 此时就能够实时的监控文件变化,自动打包。 那个自动打包的 CMD 不能关闭!!

三、学习 ES6 中的暴露和导出 文件结构:

3.1 最简单的暴露和接收

如果想暴露多个函数,必须使用 export const 这样的词语配合: export const mianji = (r) => { return 3.14 * r * r; }

export const zhouchang = (r) => { return 2 * 3.14 * r; }

导入一个函数的时候,此时要使用 import {罗列,罗列} from "./文件名"的写法。

import {mianji,zhouchang} from "./yuan.js";

这里注意两个问题: 1 )接收的函数名字,必须等于暴露的名字。比如,暴露的是 mianji,此时必须用 mianji 来接收;而不能用 mj 来接收。 2 )路径必须./开头。

3.2 命名空间 比如我们增加一个 fang.js ,也向外暴露两个函数,叫做 mianji 和 zhouchang: export const mainji = (a) => { return a * a; }

export const zhouchang = (a) => { return 4 * a; }

此时主文件如果一成不变: import {mianji,zhouchang} from "./yuan.js"; import {mianji,zhouchang} from "./fang.js";

document.getElementById("box1").innerHTML = mianji(10); document.getElementById("box2").innerHTML = zhouchang(10); 会报错,因为函数的名字重复了:

解决的办法就是命名空间: import * as yuan from "./yuan.js"; import * as fang from "./fang.js";

alert(yuan.mianji(10)) alert(fang.mianji(10)) 此时我们的函数必须通过 yuan 继续打点,或者 fang 继续打点来调用,此时叫做命名空间。

也就是说,import * as 命名空间 from "./文件"的语法,可以有效避免函数的名字冲突。

注意,import * as 的这个名字,必须和文件名相同。

3.3 默认暴露 如果一个 js 文件是一个类,此时我们不希望有命名空间,此时要用 export default 来暴露。

比如我们写一个文件叫做 People.js 文件,这个文件仅仅向外暴露一个类,所以要用 export default 来进行暴露。 export default class People{ constructor(name,age,sex){ this.name = name; this.age = age; this.sex = sex; } changge(){ alert(啦啦啦啦啦,我是卖报的${this.name},我今年${this.age}岁啦!); } }

在主文件,就可以不用{}来引入这个类: import * as yuan from "./yuan.js"; import * as fang from "./fang.js"; import People from "./People.js";

alert(yuan.mianji(10)) alert(fang.mianji(10))

var xiaoming = new People("小明" , 12 , "男"); xiaoming.changge();

上午的知识自查,必须会以下的内容: 1 )后面学习什么知识? dashboard 是什么?有什么特点? 2 ) webpack 是干什么的,解决了什么问题? 3 ) webpack 如何安装到电脑里面? 4 ) webpack 如何启动? 5) webpack 用什么文件来指导它的工作,文件的名字是什么,里面大致有哪些属性?从哪个网页上去看这个配置。 6 )如何配置 webpack 的自动的监控文件,如何让 webpack 可以在文件变化的时候自动打包? 7 ) ES6 中的暴露和接收,有三种引入方法,有两种暴露方法,分别是什么?

四、webpack 高级使用(难点) 4.1 babel-loader 我们之前学习过 babel,babel 用来翻译高级语法。babel 是-g 安装的工具,需要用.babelrc 文件进行指导。 我们今天 webpack 打包之后的 dist/bundle.js 文件是没有进行翻译的:

所以,现在的任务是,在 webpack 打包过程中,对每一个.js 文件用 babel 进行翻译。 捎带脚儿 我们 webpack 提供了叫做 loader (加载器)的东西,可以让 webpack 在打包的时候捎带脚进行某些操作,比如 babel 的翻译。这个 loader 叫做 babel-loader。 babel-loader 三装一配: 安装依赖: cnpm install --save-dev babel-core cnpm install --save-dev babel-loader cnpm install --save-dev babel-preset-env babel-core:表示 babel 核心, babel-loader 表示 babel 的加载器 babel-preset-env 表示 babel 的预处理器,让 babel 对 ecmascript new version 进行翻译。

之前我们写.babelrc 文件,现在 webpack 在自己的 webpack.config.js 文件中提供了配置的位置: 配置 webpack.config.js:

下面的代码不需要背诵,但是也不能直接用老师的,而应该自己去 webpack 官方网站找配置: const path = require('path');

module.exports = { entry: "./app/main.js", //入口文件 output: { //出口文件 path: path.resolve(__dirname, "dist"), //打包到哪个文件夹中 filename: "bundle.js" //打包到哪个文件 }, watch : true, mode: "development", module : { rules: [ { test: /.js$/, //以.js 结尾的文件 include: [ path.resolve(__dirname, "app") //包括什么文件夹 ], exclude: [ path.resolve(__dirname, "node_modules") //不包括 ], loader: "babel-loader", options: { presets: ["env"] } } ] } }

module 是模块的意思,表示我们需要运行哪些外置的模块,也就是说 babel-loader 属于外置模块。
rules 表示规则,我们测试( test )所有以.js 文件结尾的文件,include、exclude 表示包括哪些文件夹、不包括哪些文件夹。
使用 babel-loader、选线格式 presets:["env"]

再次运行 webpack,此时就发现 ES6 的语法进行了翻译,我们的程序能够兼容到 IE8 了。

我们今天让 webpack 在打包的时候捎带脚儿翻译 js 文件,用的是 babel-loader 在 react 基础课第 5 天左右,我们要学习 css-loader、style-loader、less-loader,他们都是让 webpack 在打包的过程中捎带脚儿做的事情。

4.2 webpack-dev-server (重点) 这个东西不好讲,所以我们直接采用生猛教学法,告诉你怎么做,做完再回味。

在机器的全局,安装 webpack-dev-server cnpm install -g webpack-dev-server 字面叫做“ webpack 开发服务器”。

安装完毕可以用 webpack-dev-server --version 来查看版本号:

我们将项目的 app 文件夹和 index.html 文件放入 www 文件夹中,整个项目的结构:

改变 webpack.config.js 文件的一些配置: const path = require('path');

module.exports = { entry: "./www/app/main.js", //入口文件 output: { //出口文件 path: path.resolve(__dirname, "www/dist"), //打包到哪个文件夹中 filename: "bundle.js", //打包到哪个文件 publicPath : "/xuni" }, watch : true, mode: "development", module : { rules: [ { test: /.js$/, //以.js 结尾的文件 include: [ path.resolve(__dirname, "www/app") //包括什么文件夹 ], exclude: [ path.resolve(__dirname, "node_modules") //不包括 ], loader: "babel-loader", options: { presets: ["env"] } } ] } }

然后启动项目 webpack-dev-server --content-base ./www --port 8080 --content-base 表示以 www 文件夹作为一个根目录 --port 表示端口号。

启动项目的时候:

webpack-dev-server 在进行两个事情: 1 )在打包 js 文件(就是上午学习的 webpack 的事情) 2 )静态化 www 文件夹,说白了,就是说帮我们写了一个 app.use(express.static("www"));

注意!!我们的 index.html 文件,要改变 script 的 src:

<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body>
<script src="xuni/bundle.js"></script>
</body> </html>

项目中物理磁盘上没有 xuni 文件夹!!但是 webpack-dev-server 将 /xuni/bundle.js 文件路由到了打包的文件,不毁硬盘!!

我们以后起项目,都要 webpack-dev-server --content-base ./www --port 8080

此时我们可以在 package.json (身份证)文件中,进行配置: { "name": "test", "version": "1.0.0", "description": "", "main": "webpack.config.js", "scripts": { "dev" : "webpack-dev-server --content-base ./www --port 8080" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.4", "babel-preset-env": "^1.6.1" } }

以后起项目,就直接使用 npm run dev

以后看项目,就直接在 8080 端口的 URL 下看。不要直接双击打开 index.html 页面了。

五、React 配置和起步 React 需要建立在 webpack + babel-loader 上, 然后补充安装 npm install --save react npm install --save react-dom npm install --save-dev babel-preset-react

改变 webpack.config.js 文件,加一个 babel 的 preset,就是 babel 的预处理器: const path = require('path');

module.exports = { entry: "./www/app/main.js", //入口文件 output: { //出口文件 path: path.resolve(__dirname, "www/dist"), //打包到哪个文件夹中 filename: "bundle.js", //打包到哪个文件 publicPath : "/xuni" }, watch : true, mode: "development", module : { rules: [ { test: /.js$/, //以.js 结尾的文件 include: [ path.resolve(__dirname, "www/app") //包括什么文件夹 ], exclude: [ path.resolve(__dirname, "node_modules") //不包括 ], loader: "babel-loader", options: { presets: ["env" , "react"] } } ] } }

然后,写 main.js(其他的 JS 文件可以删除了):

import React from "react"; import ReactDOM from "react-dom";

ReactDOM.render(

你好!我是 React !

你好!我是 React !

你好!我是 React !

, document.getElementById("app") )

改变 index.html:

<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body>
<script src="xuni/bundle.js"></script> </body> </html>

npm run dev 打开 8080 端口,即可看见项目:

我们的项目的身份证,react 需要 6 个依赖(最少 6 个依赖)就可以运行: { "name": "test", "version": "1.0.0", "description": "", "main": "webpack.config.js", "scripts": { "dev": "webpack-dev-server --content-base ./www --port 8080" }, "author": "", "license": "ISC", "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.4", "babel-preset-env": "^1.6.1", "babel-preset-react": "^6.24.1" }, "dependencies": { "react": "^16.2.0", "react-dom": "^16.2.0" } }

家也可以加群实时技术交流:137503198

1752 次点击
所在节点    React
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/466290

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX