hello world
, document.getElementById('root'));
复制代码
这个代码不难,我想关键是,这个代码写完了,突然就开服务器了,突然就打包成功了,突然就可以运行了,这个对于一些同学有点玄幻,这里就有必要说一下这里的webpack了
webpack
我们说框架的脚手架,其实说白了就是工程化一块的配置,最初几年的工程化主要集中在压缩和优化、到requireJS时代后工程化变得必不可少,当时主要依赖grunt和gulp这类工具,后续为了把重复的工作杀掉工程化就越走越远了,但是和最初其实变化不大,都是一点一点的将各种优化往上加,加之最近两年typescript一击es6新语法需要编译进行,我们就进入了编译时代
webpack已经进入了4.X时代,一般一个团队会有一个同事(可能是架构师)对webpack特别熟悉,将脚手架进行更改后,就可以很长时间不改一下,这个同事有时候主要就做这么一件事情,所以我们偶尔会称他为webpack配置工程师,虽然是个笑话,从侧门也可以看出,webpack至少不是个很容易学习的东西,造成这个情况的原因还不是其本身有多难,主要是最初文档不行,小伙伴想实现一个功能的时候连去哪里找插件,用什么合适的插件只能一个个的试,所以文档是工程化中很重要的一环
这里再简单介绍下webpack,webpack是现在最常用的JavaScript程序的静态模块打包器(module bundler),他的特点就是以模块(module)为中心,我们只要给一个入口文件,他会根据这个入口文件找到所有的依赖文件,最后捆绑到一起,这里盗个图:
这里几个核心概念是:
① 入口 - 指示webpack应该以哪个模块(一般是个js文件),作为内部依赖图的开始
② 输出 - 告诉将打包后的文件输出到哪里,或者文件名是什么
③ loader - 这个非常关键,这个让webpack能够去处理那些非JavaScript文件,或者是自定义文件,转换为可用的文件,比如将jsx转换为js,将less转换为css
test就是正则标志,标识哪些文件会被处理;use表示用哪个loader
④ 插件(plugins)
插件被用于转换某些类型的模块,适用于的范围更广,包括打包优化、压缩、重新定义环境中的变量等等,这里举一个小例子进行说明,react中的jsx这种事实上是浏览器直接不能识别的,但是我们却可以利用webpack将之进行一次编译:
复制代码
// 原 JSX 语法代码
return Hello,Webpack
// 被转换成正常的 JavaScript 代码 return React.createElement('h1', null, 'Hello,Webpack') 复制代码 这里我们来做个小demo介绍webpack的低阶使用,我们先建立一个文件夹webpack-demo,先建立一个文件src/index.html 复制代码 复制代码 然后我们建立一个js文件src/index.js以及src/data.js以及style.css 复制代码 import data from './data' console.log(data); 复制代码 复制代码 export default { name: '叶小钗' } 复制代码 复制代码 * { font-size: 16px; } 复制代码 复制代码 . ├── package.json └── src ├── data.js ├── index.html ├── index.js └── style.css 复制代码 这个时候轮到我们的webpack登场,以及会用到的几个加载器(这里不讲安装过程): npm install webpack webpack-cli webpack-serve html-webpack-plugin html-loader css-loader style-loader file-loader url-loader --save-dev ① webpack-cli是命令行工具,有了他我们就需要在他的规则下写配置即可,否则我们要自己在node环境写很多文件操作的代码 ② loader结尾的都是文件加载器,读取对应的文件需要对应的加载器,比如你自己定义一个.tpl的文件,如果没有现成的loader,你就只能自己写一个 ③ 其中还有个node服务器,方便我们调试 因为我们这里的import是es6语法,浏览器不能识别,所以需要安装babel解析语言: npm install babel-core babel-preset-env babel-loader --save-dev 然后我们在package.json中加入一行代码: 复制代码 "babel": { "presets": ["env"] } 复制代码 这个时候就可以创建webpack文件了: webpack.config.js 然后执行webpack命令便构建好了我们的文件: 复制代码 . ├── dist │ ├── index.html │ ├── index.js │ └── index.js.map ├── package-lock.json ├── package.json ├── src │ ├── data.js │ ├── index.html │ ├── index.js │ └── style.css └── webpack.config.js 复制代码 可以看到,只要找到我们的入口文件index.js,便能轻易的将所有的模块打包成一个文件,包括样式文件,我们关于webpack的介绍到此为止,更详细的介绍请看这里:https://juejin.im/entry/5b63eb8bf265da0f98317441 我们脚手架中的webpack配置实现相对比较复杂,我们先学会基本使用,后面点再来怎么深入这块,因为现有的配置肯定不能满足我们项目的需求 页面实现 这里为了更多的解决大家工作中会遇到到问题,我们这里实现两个页面: ① 首页,包括城市列表选择页面 ② 列表页面,并且会实现滚动刷新等效果 页面大概长这个样子(因为这个页面之前我就实现过,所以样式部分我便直接拿过来使用即可,大家关注逻辑实现即可): 我们这里先捡硬骨头坑,直接就来实现这里的列表页面,这里是之前的页面,大家可以点击对比看看 组件拆分 react两个核心第一是摆脱dom操作,第二是组件化开发,这两点在小型项目中意义都不是十分大,只有经历过多人维护的大项目,其优点才会体现出来,我们这里第一步当然也是拆分页面 这里每一个模块都是一个组件,从通用性来说我们可以将之分为: ① UI组件,与业务无关的组件,只需要填充数据,比如这里的header组件和日历组件以及其中的列表模块也可以分离出一个组件,但看业务耦合大不大 ② 页面组件,页面中的元素 工欲善其事必先利其器,所以我们这里先来实现几个组件模块,这里首先是对于新人比较难啃的日历模块,我们代码过程中也会给大家说目录该如何划分 日历组件 日了组件是相对比较复杂的组件了,单单这个组件又可以分为: ① 月组件,处理月部分 ② 日部分,处理日期部分 能够将这个组件做好,基本对组件系统会有个初步了解了,我们这里首先来实现日历-日部分,这里我们为项目建立一个src/ui/calendar目录,然后创建我们的文件: 复制代码 . ├── index.js └── ui └── calendar └── calendar.js 复制代码 复制代码 import React from 'react'; import ReactDOM from 'react-dom'; import Calendar from './ui/calendar/calendar'; ReactDOM.render(日历
)
}
}
复制代码
这个时候再执行以下命令便会编译运行:
npm run start
虽然不知为什么,但是我们的代码运行了,大概就是这么一个情况:),接下来我们开始来完善我们的代码,日历组件,我们外层至少得告诉日历年和月,日历才好做展示,那么这里出现了第一个问题,我们怎么将属性数据传给组件呢?这里我们来简单描述下react中的state与props
state是react中的状态属性,定义一个正确的状态是写组件的第一步,state需要代表组件UI的完整状态集,任何UI的改变都应该从state体现出来,判断组件中一个变量是不是该作为state有以下依据:
① 这个变量是否是从父组件获取,如果是,那么他应该是一个属性
② 这个变量是否在组件的整个生命周期不会变化,如果是,那么他也是个属性
③ 这个变量是否是通过其他状态或者属性计算出来的,如果是,那么他也不是一个状态
④ 状态需要在组件render时候被用到
这里的主要区别是state是可变的,而props是只读的,如果想要改变props,只能通过父组件修改,就本章内容,我们将年月等设置为属性,这里先忽略样式的处理,简单几个代码,轮廓就出来了,这里有以下变化:
① 新增common文件夹,放了工具类函数
② 新增static目录存放css,这里的css我们后续会做特殊处理,这里先不深入
于是,我们目录变成了这样:
复制代码
.
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── index.html
│ └── static
│ └── css
│ ├── global.css
│ └── index.css
├── src
│ ├── common
│ │ └── utils.js
│ ├── index.js
│ └── ui
│ └── calendar
│ ├── calendar.js
│ ├── day.js
│ └── month.js
复制代码
我们将calendar代码贴出来看看:
复制代码
import React from 'react';
import dateUtils from '../../common/utils'
export default class Calendar extends React.Component {
render() {
let year = this.props.year;
let month = this.props.month;
let weekDayArr = ['日', '一', '二', '三', '四', '五', '六'];
//获取当前日期数据
let displayInfo = dateUtils.getDisplayInfo(new Date(year, month, 0));
return (
- {data} }) }
-
{
weekDayArr.map((data, i) => {
return
6
9
13 )
14 }
15 }
复制代码
于是header部分的框架就出来了,这个时候我们来将之加强,这里也不弄太强,就将后退的事件加上,以及左边按钮加上对应的按钮和事件,这里改造下index和header代码:
index.js
复制代码
import React from 'react';
export default class Header extends React.Component {
_renderRight() {
let html = [];
let arr = this.props.right;
if(!arr) return;
for(let i = 0, len = arr.length; i < len; i++) {
let item = arr[i];
html.push(
{item.value ? item.value : }
)
}
return html;
}
onClick() {
if(this.props.backaction) {
this.props.backaction();
}
}
render() {
return (
10 {this.props.title} 11
12
{this._renderRight()}
)
}
}
复制代码
就这样按钮和点击时候的事件回调都做好了,这里图标有点丑这个事情大家就别关注了,注意这里是一种规则,设定了规则后按照规则写代码后续会极大提高工作效率,到此我们header部分的代码就完成了,很是轻松加愉快啊!!!
列表组件
列表组件这里涉及到部分业务代码了,因为存在请求后端数据了,于是我们就比较尴尬了,因为我一点点都不想去为了写一个demo而去写建立数据库或者写代码,于是我们这里使用mock搞定数据部分,工欲善其事必先利其器,我们这里首先将数据部分解决掉(PS:因为原来项目的接口不能访问,所以直接胡乱mock数据,这样也许会造成之前做的日历没有多大的意义,事实上数据应该是用日期参数请求的)
现在想做假数据已经有很多成熟的平台了,比如这个:https://www.easy-mock.com,使用起来非常简单,大家去看看他的教程就行,我们这里直接使用之:
现在访问这个url就能看到我们的列表数据:https://www.easy-mock.com/mock/5c29d45956db174d47ce162a/example_copy/train/list#!method=get
在react中我们使用fetch获取数据,这里直接上代码了:
复制代码
fetch(
'https://www.easy-mock.com/mock/5c29d45956db174d47ce162a/example_copy/train/list'
)
.then(res => res.json())
.then(data => {
console.log(data)
})
复制代码
这样就会将我们的数据打印到控制台,但是实际项目中我们不会这样请求数据,而会对他进行两层封装,第一层封装隐藏fetch,让我们无论是ajax或者fetch都可以,第二层是要给他加上缓存功能比如我们的localstorage,包括一些公告参数处理撒的,所以我们会在我们的目录中新增data目录专门用来处理数据请求部分,甚至我们会为没一个数据请求建立一个“实体”,让各个页面重复调用,我这里偷懒就直接将之前微信小程序的请求模块和换成模块拿过来使用即可:
复制代码
import listModel from './data/demo';
listModel.setParam({
a: 1,
b: 'aa'
});
listModel.execute(function (data) {
console.log(data)
})
复制代码
view code
View Code
View Code
这里data目录是,然后可以看到数据请求成功,并且localstrage中有数据了:
复制代码
data
├── abstractmodel.js
├── abstractstore.js
└── demo.js
复制代码
有了数据后,我们来完善我们的列表,因为数据原因,我们这里便不做滚动分页功能了,一般来说列表类组件特点还是比较突出的:需要提供一个数据请求模块以及一个数据处理器,最后加一个模板就可以完成所有功能了,这里还是先来实现列表部分代码,这个列表组件因为涉及的业务比较多而且每个页面的列表变化也比较大,我们暂且将之放到ui目录,后续看看这块怎么处理一下,我们依然先在这里建立list目录:
复制代码
class PageMain extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
// today = new Date(today.getFullYear(), today.getMonth(), 1);
return (
