WEBPACK+ES6+REACT入门4/7-评论列表DEMO以及CSS样式
使用Dependencies版本
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"css-loader": "^0.28.11",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.0.6",
"node-sass": "^4.7.2",
"sass-loader": "^6.0.7",
"style-loader": "^0.20.3",
"url-loader": "^1.0.1",
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12",
"webpack-dev-server": "^3.1.1"
},
"dependencies": {
"bootstrap": "^3.3.7",
"react": "^16.2.0",
"react-dom": "^16.2.0"
}
DEMO效果图
实现步骤
1、在index.js中使用class关键字,定义父组件,代码如下:
//1、引入react和react-dom。接受的成员名称,必须这么写
import React from 'react' //创建组件、虚拟dom元素、生命周期
import ReactDOM from 'react-dom'//把创建好的组件和虚拟dom放到页面展示
//2、创建虚拟dom元素
//使用class 关键字,定义父组件
class CmtList extends React.Component{
constructor(){
super()
this.state = {
CommentList: [
{ id: 1, user: '张三', content: '哈哈,沙发' },
{ id: 2, user: '李四', content: '哈哈,二楼' },
{ id: 3, user: '王五', content: '哈哈,三楼' },
{ id: 4, user: '赵六', content: '哈哈,四楼' },
]
}
}
render(){
return <div>
<h1>这是评论列表组件</h1>
{this.state.CommentList.map(item=><div key={item.id}>
<h1>评论人:{item.user}</h1>
<p>评论内容:{item.content}</p>
</div>)}
</div>
}
}
//3、使用reactdom把虚拟dom渲染到页面上
ReactDOM.render(
<div>
<CmtList></CmtList>
</div>,
document.getElementById('app')
)
2、对代码进行修改,修改代码后如下:
//1、引入react和react-dom。接受的成员名称,必须这么写
import React from 'react' //创建组件、虚拟dom元素、生命周期
import ReactDOM from 'react-dom'//把创建好的组件和虚拟dom放到页面展示
//2、创建虚拟dom元素
//使用function 构造函数,定义普通的无状态组件
function CmiItem(props){
return <div>
<h1>评论人:{props.user}</h1>
<p>评论内容:{props.content}</p>
</div>
}
//使用class 关键字,定义父组件
class CmtList extends React.Component{
constructor(){
super()
this.state = {
CommentList: [
{ id: 1, user: '张三', content: '哈哈,沙发' },
{ id: 2, user: '李四', content: '哈哈,二楼' },
{ id: 3, user: '王五', content: '哈哈,三楼' },
{ id: 4, user: '赵六', content: '哈哈,四楼' },
]
}
}
render(){
return <div>
<h1>这是评论列表组件</h1>
{this.state.CommentList.map(item=><CmiItem {...item} key={item.id}></CmiItem>)}
</div>
}
}
//3、使用reactdom把虚拟dom渲染到页面上
ReactDOM.render(
<div>
<CmtList></CmtList>
</div>,
document.getElementById('app')
)
说明:由于在class的render的div中,使用了div以外的item数据,所以,适合被定义为function组件而非class组件。定义后,在方法内部需要用到各个属性,其是在方法外部传入,所以使用props。此时,key加给了div,而在map中并非直接控制,所以需要给item添加key。
3、抽离组件。在components下创建CmtItem.jsx文件。引入React,将CmtItem方法在index.js中剪切。并创建、导出。代码如下:
import React from 'react'
//使用function 构造函数,定义普通的无状态组件
export default function CmiItem(props){
return <div>
<h1>评论人:{props.user}</h1>
<p>评论内容:{props.content}</p>
</div>
}
4、继续抽离CmtList方法。在components下创建CmtIList.jsx文件。引入React,将CmtList方法在index.js中剪切。在index.js中剪切CmtItem的引入到CmtIList.jsx,因为CmtIList.jsx和CmtItem.jsx同级,所以注意修改引入路径。代码如下:
import React from 'react'
//导入CmtItem
import CmtItem from './CmtItem'
//使用class 关键字,定义父组件
export default class CmtList extends React.Component{
constructor(){
super()
this.state = {
CommentList: [
{ id: 1, user: '张三', content: '哈哈,沙发' },
{ id: 2, user: '李四', content: '哈哈,二楼' },
{ id: 3, user: '王五', content: '哈哈,三楼' },
{ id: 4, user: '赵六', content: '哈哈,四楼' },
]
}
}
render(){
return <div>
<h1>这是评论列表组件</h1>
{this.state.CommentList.map(item=><CmtItem {...item} key={item.id}></CmtItem>)}
</div>
}
}
5、在引入组件时,可对引入路径使用@进行优化,避免代码块挪动后的路径引用问题。首先对其进行配置,在webpack.config.json中添加以下配置:
resolve:{//省略后缀名
extensions:['.js','.jsx','.json'],
alias:{
'@':path.join(__dirname,'./src') //@表示src这一层的目录
}
},
修改CmtList.jsx如下:
//导入CmtItem
import CmtItem from '@/components/CmtItem'
修改index.js如下:
//引入CmtList
import CmtList from '@/components/CmtList'
6、从此步开始进行样式美化。在jsx中。行内样式不能为style设置字符串值。正确示例:style={{color:red}}
。外层花括号为js代码,内层为对象。为满足需求,应修改CmtList.jsx代码如下:
<h1 style={
{color:'red',fontSize:'35px',zIndex:3,fontWeight:200,textAlign:'center'}
}>这是评论列表组件</h1>
修改CmtItem.jsx代码如下:
<div style={
{border:'1px dashed #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'}
}>
<h1 style={{fontSize:'15px'}}>评论人:{props.user}</h1>
<p style={{fontSize:'12px'}}>评论内容:{props.content}</p>
</div>
注意:在行内样式中,如果是数值类型的样式,可以不用引号包裹,如果是,必须使用。
7、可对style样式进行优化。修改CmtItem.jsx代码如下:
import React from 'react'
//封装 style
const styles = {
item:{border:'1px dashed #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'},
user:{fontSize:'15px'},
content:{fontSize:'12px'}
}
//使用function 构造函数,定义普通的无状态组件
export default function CmtItem(props){
return <div style={styles.item}>
<h1 style={styles.user}>评论人:{props.user}</h1>
<p style={styles.content}>评论内容:{props.content}</p>
</div>
}
8、可将style单独作为文件在ComItem.jsx文件中引用。components下创建styles.js文件后剪切ComItem.jsx文件中的styles,styles.js代码如下:
//封装 style
export default {
item:{border:'1px dashed #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'},
user:{fontSize:'15px'},
content:{fontSize:'12px'}
}
9、使用css样式表美化组件。在src文件夹下新建css文件夹,然后在css文件夹中新建CmtList.css文件,CmtList.css代码如下:
.title{
color:red;
text-align: center;
font-weight: 200;
}
10、在CmtList.jsx中引入CmtList.css,代码如下:
//导入CmtList所需要的样式表
import cssobj from '@/components/css/CmtList.css'
在index.js文件引入当前CmtList.css文件时,.css后缀不能被识别,此时需要安装style-loader和css-loader,命令为:npm install style-loader@0.20.3 css-loader@0.28.11 -D
。
11、在webpack.config.js中添加如下配置:
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
{
test:/\.jsx?/,
use:'babel-loader',
exclude:/node_modules/
},
{
test:/\.css/,
use:[
'style-loader',
'css-loader'
]
} ]},
12、修改CmtList.jsx代码,如下所示:
<h1 className="title">这是评论列表组件</h1>
注意:通过以上操作导入的css样式表,默认全局生效,缺少作用域,造成冲突。
13、为普通样式表通过modules参数启用模块化,解决样式全局生效问题。webpack.config.js文件代码修改如下:
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
{
test:/\.jsx?/,
use:'babel-loader',
exclude:/node_modules/
},
{
test:/\.css/,
use:[
'style-loader',
'css-loader?modules'
]
} ]},
14、修改当前CmtList.jsx:
<h1 className={cssobj.title}>这是评论列表组件</h1>
15、在css文件夹下创建CmtItem.css,添加代码如下:
.title{
font-size: 15px;
}
.content{
font-size: 12px;
}
.cmtbox{
border:1px dashed #ccc;
margin:10px;
padding:10px;
box-shadow:0 0 10px #ccc
}
注意:css模块化,只针对类选择器和ID选择器生效,不会将标签选择器模块化。
16、在CmtItem.jsx中导入css,修改代码如下:
import React from 'react'
//引入css
import cssobj from '@/css/CmtItem.css'
console.log(cssobj)
//使用function 构造函数,定义普通的无状态组件
export default function CmtItem(props){
return <div className={cssobj.cmtbox}>
<h1 className={cssobj.title}>评论人:{props.user}</h1>
<p className={cssobj.content}>评论内容:{props.content}</p>
</div>
}
17、使用localIdentName自定义生成类名及类名格式。为方便此效果显示,代码中打印导入的cssobj。代码位置如下:
import cssobj from '@/css/CmtItem.css'
console.log(cssobj)
此时的浏览器console,发现名称为乱码。
18、修改webpack.config.js的modules配置如下:
module:{//所有第三方模块的配置规则
rules:[//第三方匹配规则
{
test:/\.jsx?/,
use:'babel-loader',
exclude:/node_modules/
},
{
test:/\.css/,
use:[
'style-loader',
'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]'
]
}
]
},
此时的浏览器console:
被global()包裹起来的类名,不会被模块化,而是会全局生效
被bocal()包裹起来的类名,会被模块化,默认情况下,所有的类名和ID 都被模块化了
19、通过local和global设置类名是否被模块化。在CmtList.css中添加以下代码:
/*被:global()包裹起来的类名,不会被模块化,而是会全局生效*/
:global(test){
font-style: italic;
}
20、修改CmtList.jsx代码如下:
render(){
return <div>
{/* <h1 className={cssobj.title}>这是评论列表组件</h1> */}
{/* 第一种方式实现::global */}
{/* <h1 className={cssobj.title + ' test'}>这是评论列表组件</h1> */}
{/* 第二种方式实现::global */}
<h1 className={[cssobj.title,'test'].join(' ')}>这是评论列表组件</h1>
{this.state.CommentList.map(item=><CmtItem {...item} key={item.id}></CmtItem>)}
</div>
}
```
21、在项目中安装第三方样式表。安装bootstrap,命令为:`npm install bootstrap@3.3.7 -S`
22、以button为例。在CmtList.jsx中添加按钮,代码如下:
```js
render(){
return <div>
{/* <h1 className={cssobj.title}>这是评论列表组件</h1> */}
{/* 第一种方式实现::global */}
{/* <h1 className={cssobj.title + ' test'}>这是评论列表组件</h1> */}
{/* 第二种方式实现::global */}
<h1 className={[cssobj.title,'test'].join(' ')}>这是评论列表组件</h1>
<button className="btn btn-primary">这是一个按钮</button>
{this.state.CommentList.map(item=><CmtItem {...item} key={item.id}></CmtItem>)}
</div>
}
23、在CmtList.jsx中导入bootstrap,代码如下:
//导入bootstrap
//如果在引用一个包时,这个包被安装在了node_modules目录,
//则可以省略node_modules这层目录,直接以包名开始引入
import bootcss from 'bootstrap/dist/css/bootstrap.css'
之前,规定了css样式文件必然会被模块化,无法使用bootstrap.css中的bootstrap样式直接添加样式到标签中。
此时,也会警告报错,提示需要合适的loader处理bootstrap中对应的字体文件类型。为此做以下操作:
24、在webpack.config.js文件中添加如下配置:
rules:[//第三方匹配规则
{
test:/\.jsx?/,
use:'babel-loader',
exclude:/node_modules/
},
{//打包处理css样式表的第三方loader
test:/\.css/,
use:[
'style-loader',
'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]'
]
},
{//打包处理字体文件的loader
test:/\.ttf|woff|woff2|eot|svg$/,
use:'url-loader'
}
]
25、执行安装url-loader操作,命令为:npm install url-loader@1.0.1 -D
。及url-loader依赖的file-loader,命令为:npm install file-loader@1.1.11 -D
。
注意:此时按钮样式并不能生效,通过打印log发现此时btn在node_nodules下生成。如下图所示:
26、修改按钮className,代码如下所示:
{/* <button className="btn btn-primary">这是一个按钮</button> */}
<button className={bootcss.btn}>这是一个按钮</button>
注意:当添加多个样式时,此修改按钮的方式造成书写繁琐,可使用以下方式解决:
约定:已知第三方的样式表都以.css结尾,我们不再为普通的.css启用模块化。 个人定义的样式表,以.scss或.less结尾,只为.scss和.less启用模块化。
27、修改CmtItem.css和CmtList.css文件名称为CmtItem.scss和CmtList.scss,并修改相应位置导入文件的后缀名。
28、安装对应loader。命令为:npm install sass-loader@6.0.7 node-sass@4.7.2 -D
。
29、修改webpack.config.js代码如下:
module: { // 所有第三方 模块的配置规则
rules: [ // 第三方匹配规则
{ test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }, // 千万别忘记添加 exclude 排除项
// 可以在 css-loader 之后,通过 ? 追加参数,
// 其中,有固定的参数,叫做 modules , 表示为 普通的 CSS 样式表,启用模块化
{ test: /\.css$/, use: ['style-loader', 'css-loader']}, // 打包处理 CSS 样式表的第三方loader
{ test: /\.ttf|woff|woff2|eot|svg$/, use: 'url-loader' }, // 打包处理 字体文件 的loader
{ test: /\.scss$/, use: ['style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]', 'sass-loader'] } // 打包处理 scss 文件的 loader
]
},
上一篇:WEBPACK+ES6+REACT入门(3/7)-react组件以及props
下一篇:WEBPACK+ES6+REACT入门(5/7)-在React中为按钮绑定点击事件
END