前言

  如果从来不了解React先看前篇React入门 (1)—使用指南(包括ES5和ES6对比)

  本文为了能将前篇学到的react知识学以致用,做了一个类似微博展示列表的demo。使用的是ES6+React+JSX+Webpack+Babel+NPM

设计思路

  图为截取的微博展示列表,我这么来划分组件:

  花括号括起来的是我要写的几个组件:

  • ContentImg组件:带图片的微博里的图片部分
  • CommentForm组件:点击评论后,弹出来的评论下拉框
  • OneWB组件:一条微博,这条微博可能是纯文字的,带一张图片的,带多张图片的,甚至是转发的。
  • ListWB组件:OneWB的集合,是一个页面要展示的所有微博的集合。

  最外层节点放在最上面,每个控件的数量通过后台给的数据控制,组件之间的关系用树状图表示:

  本文章只实现纯文字,带图片的微博。带视屏,转发的可以用类似的方法实现,就不赘述了。后端数据的结构设计为:

var dataList=[
{
headUrl:'http://img1.gtimg.com/tech/pics/hv1/238/85/1736/112905313.jpg',
nickName:'Robin',
content:'拿快递拿快递3号小邮局爆仓啦',
NoCollect:132,
NoForward:202,
NoComment:142,
NoPointGreat:423,
contentImgUrls:[
"http://img1.gtimg.com/tech/pics/hv1/238/85/1736/112905313.jpg",
"http://img1.gtimg.com/tech/pics/hv1/238/85/1736/112905313.jpg"
]
},
{
//内容同上
}
];
  • 必填

      headUrl:别人的头像链接,nickName:别人的昵称,content:微博文字内容,NoCollect:收藏数,NoForward:转发数,NoComment:评论数,NoPointGreat:点赞数。
  • 非必填

      contentImgUrls:微博图片内容,可以为空或不存在。

  图中组件的数量是根据后端给的数据来决定的,dataList的元素个数代表OneWB的个数,contentImgUrls的元素个数决定了微博带不带图片,以及展示几个。

搭建环境

  使用webpack+npm。

  我的工程目录结构如图:

  

  webpack以commonjs的形式来书写脚本,是现在很火的模块加载器+打包工具。使用方法:

1.创建package.json文件

  npm init

  参数可以不填,回车代替。

  执行完会生成package.json文件

2.在终端安装你需要的插件

  npm install 插件名 --save-dev.

  ('--save-dev' 一般在开发者开发项目的时候用,这个指令会把安装的包依赖写入package.json的devDependencies字段中。如果命令去掉'-dev',则会记录到dependencies字段中)。

  需要安装这么些个:

  npm install -save-dev webpack

  npm install -save-dev react

  npm install -save-dev react-dom

  npm install --save-dev babel-core

  npm install --save-dev babel-loader

  npm install --save-dev babel-preset-es2015 ,babel6才需要装

  npm install -save-dev babel-preset-react,babel6才需要装

  如果用的别人的工程,已存在package.json文件且内容完整,那么直接npm install不需要手动安装了。

3.创建webpack.config.js,并配置

  根据webpack.config.js文件来决定webpack要做哪些动作。

//webpack.config.js 文件内容
var path = require('path'); module.exports = {
entry: {
'index': './index.js' //key只是个名字,可以自由改
},
output: {
path: './build',
filename: 'entry.js',//也可以动态生成文件名 filename:'[name].js',将根据entry中的key生成名字
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'babel',
/* babel6 才需要配置这个,presets里面两个预编译插件,前一个用于编译es6,后一个用于编译react。按需配置。这个工程都需要。
query:{
presets: ['es2015','react']
}*/
}]
}
};

  这段代码主要告诉了webpack:

  • 哪个文件需要打包(entry字段),打包之后生成的新文件存到哪个路径(output中的path)、新文件叫什么名字(output中的filename);
  • 要使用哪些加载器(module.loaders)。这里要使用babel来编译jsx和es6的代码。

  总得来说,webpack从entry拿到目标文件,通过loaders进行编译,从output输出,其他功能由plugins引入。

  注:index.js:负责渲染组件到页面上。相当于一个总的出口。因为会自动加载依赖关系,所以webpack.config.js文件只需要配置这一文件即可。

  另外,这个工程比较简单,只需配置一个js文件。

  • 如果要打包多个js文件,这么配置:
entry: {
'file1': './index.js', //key只是个名字,可以自由改
'file2': './index2.js'
}
  • 如果需要打包css文件,或解析less文件,需要配置ExtractTextPlugin。详情看官方文档

4. 在终端执行命令:webpack

  会在build文件夹下生成编译后(未压缩)的js文件,entry.js。如果编译错误会在命令行提示错误原因,entry.js为上一版本的内容。

  你也可以使用其他命令,方便开发:

    webpack -w 监听你的代码修改,实施打包生成entry.js, 一般都直接使用这个命令。

    webpack -p 打包js文件,并压缩。

5. 开始编码

  完成以上四步,你就可以一边编写代码,用require(es6用import)来加载依赖的模块,一边在浏览器查看效果啦。并且如果以后有新的项目,直接拷贝package.json和webpack.config.js ,秒搭建环境。

编码阶段

  需要用的react特性有:事件,state,props。依然可以参见上一篇的详细介绍。

  • 每个组件文件都需要引入react import React from 'react';,以及依赖的其他组件。

    index.js还需要引入reactdom import ReactDOM from 'react-dom';,因为渲染页面的方法render()是reactdom的。
  • 用class定义组件,不要忘记使用module.exports = ListWB; 开放组件给其他文件引用。

index.html

  只需引入一个文件,编译后的文件entry.js。div#place为react组件的父容器。是不是看起来好像什么都没有呢?react中,通过js来插入组件,我们看index.js文件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>weibo-react</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="place">
<!-- 此处插入react插件 -->
</div>
<!-- dom定义 -->
<script src="build/entry.js"></script>
</body>
</html>

index.js - js入口文件

  使用自定义的react组件,渲染页面。

import React from 'react';
import ReactDOM from 'react-dom';
import ListWB from './components/list-wb.jsx';//微博列表组件 var dataList=[{},{}];//这里存储的是后端传来的数据。包括头像,内容,点赞数等等
ReactDOM.render(<ListWB data={dataList} />,
document.getElementById('place')
);

  ListWB是微博列表组件,通过自定义属性data传递后端数据,并set到子组件中,展示到页面上。

注意import ListWB from './components/list-wb.jsx';一定要记得引入自定义组件模块。

list-wb.jsx - 微博列表组件

import React from 'react';
import OneWB from './one-wb.jsx';//标签的名字根据这个变量名来决定 class ListWB extends React.Component{
render() {
// 遍历后端给的数据,并且插入
var oneWBNodes = this.props.data.map(function(aWB,index){
return <OneWB oneData={aWB} key={index}></OneWB>;
});
return <div>
{oneWBNodes}
</div>;
}
}
module.exports = ListWB;

笔记:

  • map方法会遍历数组中的所有元素,并执行匿名函数,当前元素aWB作为匿名函数第一个实参,当前元素索引index作为第二个实参。this.props.data存储的后端数据list,每个元素执行完匿名函数return的值会连接(相加)起来。所以oneWBNodes得到是OneWB的list。
  • 注意有一个自定义属性key。对于循环出的每个子组件,如果不定义key会报警。



      react中data-reactid的取名方式:



      左图为没有数组的“dom树”取名,右图为有数组的“dom树”取名。当图的.0.1是数组时,id会按照右图的虚线框那么取。

      react组件中,每个标签都会有一个唯一的编号data-reactid,如:data-reactid=".0.$0a.0.1.0.1.1"。这里的key是data-reactid的最后一个小数点后面的值。所以key只需要在自己兄弟节点内唯一即可。

      如果不按照要求,让多个子元素的key相同,那么只会识别展示第一个子元素。

one-wb.jsx - 单个微博组件

  该组件代表单条微博。要处理的有:

  • 属性

    存储了后端传过来的数据。正确分配给子组件或者set到自己的原生属性中。
  • 事件

    触发后使用react的state来自动渲染页面。点击“评论”展开评论块,点击其他(如“转发”,“赞”)收起评论。这里通过给react的state增加一个字段isComment来控制评论区块的展现。点击“评论”,isComment设为true,展示评论区块;否则isComment设为false。
  • JSX中的if-else

    JSX中是没有if-else的(因为jsx只是个语法糖,最终还是要翻译成原生js。比如:

    <div id={if (condition) { 'msg' }}>Hello World!</div>

    编译后是:
React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");

  然而我们还是有很多场景需要根据条件判断某些组件要不要展示。

  我们用这几种方式来实现:

  • 三元操作符
React.render(<div id={condition ? 'msg' : ''}>Hello World!</div>, mountNode);
  • 在jsx以外赋值给变量
  var vid='';
if(condition){
vid='msg';
}
React.render(<div id={vid}>Hello World!</div>, mountNode);
  • 立即执行的匿名函数
<div id={(()=>{
if(this.state.isComment){
return 4;
}
})()}>
</div>

  匿名函数这种方式也同样可以用在标签中间 <div>{(()=>{//函数内容})()}</div>

  我使用的是第二种方式,代码还是更易维护一些。

  这个文件的代码:

import React from 'react';
import CommentForm from './comment-form.jsx';
import ContentImg from './content-img.jsx'; class OneWB extends React.Component{
constructor(props){
super(props);
this.state={
isComment:false,
};
} render() {
var oneData=this.props.oneData;
var commentForm;
var contentImgs;
if(this.state.isComment) {
//控制评论框是否展现,因为是动态的,所以放在state而不是props
commentForm =<CommentForm data-my-head-img={oneData.headUrl}/>;
} if(oneData.contentImgUrls){
//若后端给的数据中有图片url,则展示
contentImgs = <ContentImg content-img-urls={oneData.contentImgUrls} />
}
return <div className="big-center" >
<div className="one-wb ">
<div className="clearfix">
<div className="ow-left">
<img className="nick-img" src={oneData.headUrl}/>
</div>
<div className="ow-right">
<div className="ow-nick row">
<span>{oneData.nickName}</span>
</div>
<div className="ow-content row">{oneData.content}</div>
{contentImgs}
</div>
</div>
<div className="ow-footer row ">
<ul className="clearfix" onClick={this.handlerForwardClick.bind(this)}>
<li className="li-side-border"><span>收藏</span> {oneData.NoCollect}</li>
<li className="li-side-border"><span>转发</span> {oneData.NoForward}</li>
<li className="li-side-border"><span>评论</span> {oneData.NoComment}</li>
<li><span>赞</span> {oneData.NoPointGreat}</li>
</ul>
</div>
</div>
{commentForm}
</div>;
}
handlerForwardClick(event) {
if(event.target.innerText == '评论'){
this.setState({isComment:true});
}else{
this.setState({isComment:false}); }
}
}
module.exports = OneWB;

content-img.jsx - 微博图片组件

  因为子组件放在一个数组里,同样需要注意配置key

import React from 'react';

class ContentImg extends React.Component{

  render() {
var imgNodes=this.props['content-img-urls'].map(function(oneImg,index){
return <li key={index} ><img src={oneImg} alt="微博配图" /></li>;
});
return <div className="row extra-content clearfix">
<ul>
{imgNodes}
</ul>
</div>
}
}
module.exports = ContentImg;

comment-form.jsx - 评论框组件

import React from 'react';

class CommentForm extends React.Component{
render() {
var imgUrl=this.props['data-my-head-img'];
return <div className="row comment-form clearfix" >
<div className="ow-left">
<img src={imgUrl} alt="头像" className="little-head" />
</div>
<div className="ow-right" >
<textarea name="name" rows="8" cols="40" className="comment-box"></textarea>
<input className="comment-btn" type="submit" value="评论"/>
</div>
</div>;
}
}
module.exports = CommentForm;

效果展示

总结

  看完这篇文章,相信能够快速在工作当中实践了吧 (≧▽≦)/ 。希望以后能出一些深刻的文章。

React入门 (2)—实现微博展示列表的更多相关文章

  1. React入门 (1)—使用指南(包括ES5和ES6对比)

    前言 本篇会简明扼要的介绍一下React的使用方法.代码会用JSX+ES5和JSX+ES6两种方式实现. React简介 React来自Facebook,于2013年开源.至今不断修改完善,现在已经到 ...

  2. react入门学习及总结

    前言 不知不觉一年又过去了,新的一年又到来,2019应该要好好思考,好好学点有用的东西,规划下自己今后的学习方向,不要再像以前那样感觉很迷茫. react简单介绍 官网及中文文档 https://re ...

  3. react 入门与进阶教程

    react 入门与进阶教程 前端学习对于我们来说越来越不友好,特别是随着这几年的发展,入门门槛越来越高,连进阶道路都变成了一场马拉松.在学习过程中,我们面临很多选择,vue与react便是一个两难的选 ...

  4. React入门看这篇就够了

    摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...

  5. [转]React入门看这篇就够了

    摘要: 很多值得了解的细节. 原文:React入门看这篇就够了 作者:Random Fundebug经授权转载,版权归原作者所有. React 背景介绍 React 入门实例教程 React 起源于 ...

  6. 【React】学习笔记(一)——React入门、面向组件编程、函数柯里化

    课程原视频:https://www.bilibili.com/video/BV1wy4y1D7JT?p=2&spm_id_from=pageDriver 目录 一.React 概述 1.1.R ...

  7. react入门之使用webpack搭配环境(一)

    react入门之搭配环境(一) 如果你想直接上手开发,而跳过这些搭配环境的繁琐过程,推荐你使用官方的create-react-app命令 npm install -g create-react-app ...

  8. react入门之使用react-bootstrap当轮子造车(二)

    react入门之使用react-bootstrap当轮子造车(二) 上一篇我们谈了谈如何配置react的webpack环境 react入门之搭配环境(一) 可能很多人已经打开过官方文档学习了react ...

  9. React 之容器组件和展示组件相分离解密

    Redux 的 React 绑定库包含了 容器组件和展示组件相分离 的开发思想.明智的做法是只在最顶层组件(如路由操作)里使用 Redux.其余内部组件仅仅是展示性的,所有数据都通过 props 传入 ...

随机推荐

  1. Angular 2018 All in One

    Angular 2018 https://cli.angular.io/ v7.0.6 https://angular.io/ https://angular.cn/ v7.0.4 $ npm i - ...

  2. Hibernate映射关系之_多对多

    多对多关系由于效率的原因,实际中会拆成相互的一对多的关系,不再累述

  3. 【心情】HNOI2018游记

    Day 0. 全机房的人好像都在做题.然而下午是社团节的游园会,身为社干的我风风雨雨在外面各种搬凳子搬椅子换场地招待外校同学……就这样我好像什么都没有复习. 晚上就一起去酒店了.大概因为是高一的缘故, ...

  4. POJ3261 Milk Patterns 【后缀数组】

    牛奶模式 时间限制: 5000MS   内存限制: 65536K 提交总数: 16796   接受: 7422 案件时间限制: 2000MS 描述 农夫约翰已经注意到,他的牛奶的质量每天都在变化.经进 ...

  5. fastjson解析服务端返回的数据

    1.配置依赖 //fastjson api 'com.alibaba:fastjson:1.2.44' 2.设计服务端返回的数据 {},{},{}]} 3.编写bean类,特别注意,要和服务端返回的类 ...

  6. 取消eslint对指定代码进行代码检测

    eslint配置了不允许使用alert,但是有个需求需要用到. //eslint-disable-next-line alert('测试'); 如上,即可跳过当前行代码检查了

  7. iOS 控制台打印unicode 转中文汉字 UTF8String

    今天查看代码数据结构,就在控台直接打印了,soGa,我看到了什么!!!! 于是乎想到了不对劲,不对呀,之前打印都是 UTF8String的呀,怎么会这样,百思不得其姐,看了一下封装的网络类,SoGa, ...

  8. React 开发常见报错解决方法

    1. 使用 redux 的异步 action 时浏览器报错: Error: Actions must be plain objects. Use custom middleware for async ...

  9. Maven环境搭建、调试、打包

    1.配置Maven环境 将下载文件解压,然后设置maven环境 新建环境变量M2_HOME 变量名:M2_HOME 变量值:F:\maven\apache-maven-3.0.3 追加path环境变量 ...

  10. js点亮星星评分并获取参数的js代码

    点亮星星评分后,点击按钮,立即获得分数参数值,方便不想使用ajax传参的朋友 http://demo.jb51.net/js/2014/jsxxdf/demo2.html <!DOCTYPE h ...