又快到了本周的结束,最近公司很忙,只有周末才会有自己的一点时间,所以赶紧趁着短暂的私人时间把我的学习过程写下来。通过上一篇文章有可能很多读者会觉得我的大部分过程跟网上的差不多,我在这里声明一下,我就是从网上各种教程里面学来的,再者我需要强调的是我虽然是学习别人的代码但是我是把自己的学习过程体现出来的,特别是对之前没有什么开发经验的程序员来说比较实用,因为我就是从一点没有接触到现在可以一点一点写出来把开发框架搭建好,通过刻意练习来提高巩固自己的所学。
接下来我进入正题:上一篇文章写了基本的webpack结合ES6搭建的项目开发框架,也提到过这一次会对上一次的一些代码或是文件进行精细的解读,现在我们开始吧!
顺序还是按照上一次的文章结构来,首先我们解析package.json中的数据:
我就从头开始来说明这些对象里面的键值对对应的每一种功能或是作用(比较简单的我就不再赘述了):
其中第一个大家比较迷惑的有可能是"scripts"中的内容,其实在这里我要说明一下就是在开发这个react之前需要读者掌握一定程度的webpack的知识(当然了看我的教程我也会在这里面进行一些详细的说明足够你用来开发这个react工程了)。在这里这个package.json其实就是针对webpack的一种方便快捷的打包方式,在这个"script"中就是利用npm 来对webpack构建的工程进行打包的命令语句,其中第一个"start"对应的就是我们经常碰见的run项目中的npm start 的来历,这个是可以自定义的,比如说你用的不是"start"而是"dev"的话你的run项目命令就会变成npm run dev。这样说还是比较好理解的,大家有可能会问这个后面对应的这么多横杠一个一个的是什么这里面就是我们需要借助的webpack的模块来对我们自己的项目进行简单的打包封装以至于可以运行跑起来,后面的类似。
接着往下走就是"repository"了,其实用过git代码管理的读者都会对这个不陌生,因为他就是我们在git中提到的代码仓库用来存储代码的,大家有的可以写上没有的就算了.
接着后面的几个都不是什么关键我就漏掉不说了,当然最后两个是必须得说的,其中"devDependencies"是用于开发阶段完成集成测试等功能模块依赖的,说的直白一点就是我们在项目进行展示的时候需要这里面的工具进行编译我们才能保证浏览器能够读懂我们写的代码这样才能不报错的情况下进行页面渲染。每个依赖项后面的是对应的版本号,最后一"dependencies "是需要发布到生产环境的,其实在一开始我也像大家一样对这两个有点模糊分不清楚,但是我经过查阅资料之后也有了大致的了解以及区分:devDependencies下列出的模块,是我们开发时用的依赖项,像一些进行单元测试之类的包,比如grunt-contrib-uglify,我们用它混淆js文件,它们不会被部署到生产环境。dependencies下的模块,则是我们生产环境中需要的依赖,即正常运行该包时所需要的依赖项。这样的话大家有可能好理解一点。
接下来我们进行下一项的解析说明。第二项就是我们的webpack.config.js的配置了:
在这里Webpack执行的时候,除了在命令行传入参数,还可以通过指定的配置文件来执行。默认情况下,会搜索当前目录的webpack.config.js,这里面就是webpack要做的一些处理操作:
entry:指定打包的入口文件;entry可以是个字符串或数组或者是对象。 当entry是个字符串的时候,用来定义入口文件:entry: './js/main.js';当entry是个数组的时候,里面同样包含入口js文件,另外一个参数可以是用来配置webpack提供的一个静态资源服务器,webpack-dev-server。webpack-dev-server会监控项目中每一个文件的变化,实时的进行构建,并且自动刷新页面:我们的例子中用的就是这一种;当entry是个对象的时候:每有一个键值对,就是一个入口文件。
output:配置打包结果,path定义了输出的文件夹,filename则定义了打包结果文件的名称(其中filename后面的值可以写成'[name].js'这样的话当webpack在处理打包时就会将[name]用entry中的文件名来替换,以我自己的例子来说就是用react来替换)
module:定义了对模块的处理逻辑,这里可以用loaders定义了一系列的加载器,以及一些正则。当需要加载的文件匹配test的正则时,就会调用后面的loader对文件进行处理,这正是webpack强大的原因。比如这里定义了凡是.js结尾的文件都是用react-hot跟babel做处理,而.css结尾的文件会经过style!css处理。当然这些loader也需要通过npm install安装,在之前的package.json中都有提到。另外在这个module中还有一个就是exclude了,这个大家从字面意思也应该看得出来就是排除了node_modules中的.js文件不处理。
resolve:定义了解析模块路径时的配置,常用的就是extensions,可以用来指定模块的后缀,这样在引入模块时就不需要写后缀了,会自动补全plugins: 这里定义了需要使用的插件,比如在我们这个例子中的new webpack.NoErrorsPlugin()只是为了执行在出错的时候不打断程序运行
当然Webpack还有很多其他的配置,具体可以参照它的配置文档
接下来就是index.html了这里面比较重要的就是外部文件的引入,bundule.js这个是必须要引入的,不然我们的页面就无法进行渲染,还有就是可以自定义一个标签用来承接需要动态加载进来的虚拟DOM结构,在我们的例子中就是一个拥有id=react的div来包裹加载进来的数据.
接下来就是项目最重要的部分项目入口文件了,在这里面其实就是我们的一些业务逻辑的处理操作:
之前有用过node开发的小伙伴有可能看到这些代码后会有点诧异就是这不是定义模块规范的import代码吗,对这就是react用了ES6的module来替代AMD开发的模块加载机制赖实现模块按需加载的要求(也就是说在学习react之前我们还需要对ES6有所了解,不然学起来也会很吃力)。
在这个demo中我用了简单的路由模块,有可能一开始就发现我在我的package.json中就安装了这个reat-router的模块,这个项目就是一个简单的页面路由demo。接下来就是自定义组件了,在这里自定义组件有多种方式,我选择了最常用的一种就是调用后台的createClass({})来创建自定义组件,react还有一些其他的创建组件的方式,我会在后来的学习过程中进行总结展示的。在这个组件中会有一个render方法这个方法返回一个固定的DOM结构,这个就是我们自定义的组建创建方法。在这里还需要说明的就是我们看到我们在render中返回的Dom中会有一个属性className这个其实就是我们在之前的html中的class因为要区分ES6中的关键字class 创建类的方法所以react中统一用className来代替之前的class,在里层的则是我们从react-router中引入的路由标签了,这个可以理解为react底层自定义的组件我们只是直接拿过来用了,Link 组件可以认为是ReactRouter提供的对 a标签进行封装的组件,你可以查看 Link 组件渲染到 DOM 上其实就是 a 标签。它接受的 props 有 to、params 和 query。to 可以是一个路由的名称(下文会讲到),也可以是一个完整的 http 地址(类似 href 属性);params 和 query 都是这个链接带的参数,以后会细讲。接下来就是这一部分最重要的了就是这个<RouteHandler/>组件,他是用来干嘛的呢?RouteHandler 组件是 ReactRouter 的核心组件之一,它代表着当前路由匹配到的 React 组件。假设当前的路由为 /hello,那么 App 这个组件里的 RouteHandler 其实就是 HelloHandler组件,通俗地说其实他就是用来展示我们路由跳转时的内容存放的,大家可以试着删除一下看看页面有什么反应。
接下来就是页面中的路由了:
这里面就是引用了react-router中的Route组件其中会有这么几个属性name、path、handler等等我在这里就用了这几个,当然还有其他的我就先不提了后期会有介绍。其中name就是我刚才在定义APP的时候的link标签中的to的对应的名称,对应上了就会跳转到对应的组件;path 指明的是当前路由对应的 url,如果不指定,那么默认就是 name对应的值;handler对应的则是我们的路由被激活时需要加载的组件的名称(后期还会用更复杂的路由嵌套或者是路由传值什么的希望大家能跟着我的步伐一起进行更多的学习)。
接下来就是把我们的路由渲染到页面上了,用的是Router.run()方法,run中有两到三个参数,我们的项目中就用到了两个我就对这两个进行解释,第一个就是我们需要渲染进页面的路由,第二个就是回掉函数,函数的第一个参数是 ReactRouter 判断出当前路由中需要渲染的根节点组件,在这里就是 <App />这个组件(虽然名字叫做 Handler,但在本例中 Handle指的就是 App)。最后通过Router.render()将对应组件渲染到页面就完事了。后面的就只剩下Hello.js了这个就没有什么难度了大家就当作是我留下得一个作业吧,自己分析一下这里面的一些语法逻辑就行了,这样有助于提升对react的理解。
这就是本周的对上一周的总结,下一次我就会给大家带来更复杂的路由或是更复杂的自定义组件编写,还有就是一些这里面提到的没解决的问题进行整理解答。