WEBPACK+ES6+REACT入门(4/7)-评论列表DEMO以及CSS样式

本文介绍了使用React、Webpack和ES6构建评论列表DEMO的详细步骤,包括组件化、引入CSS样式、CSS模块化以及使用第三方库如Bootstrap。在组件拆分、样式优化和引入外部样式表过程中,详细讲解了如何处理样式冲突和模块化,以及如何处理字体文件和引入第三方样式库。
摘要由CSDN通过智能技术生成

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效果图

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值