安装 html-webpack-plugin 的原因
1、帮我们把代码生成到内存中去,因为webpack自动打包的文件是生成在物理磁盘上的,这样很消耗性能
2、在浏览器中输入localhost:8080默认不会打开首页
3、需要在首页中引入打包好的js文件
将html-webpack-plugin 在 webpack.config.js 文件中去配置

配置完成之后,在index.html中不需要引入打包好的js文件
在浏览器中输入localhost:8080之后,会默认自动打开首页
在项目中使用react
-
运行
npm i react react-dom -S安装包- react:专门用于创建组件和虚拟DOM的,同时组件的生命周期都包在这个包中
- react-dom:专门用于DOM操作,最主要的场景就是
ReactDOM.render()
-
在
index.html页面中,创建容器:-
使用React创建的虚拟DOM元素,都会被渲染到这个指定的容器中 <div id="app"></div>
-
-
在
index.js中导入包


如果要在h1标签外面嵌套div该怎么实现呢?

JSX语法
什么是JSX语法:就是符合xml规范的js语法(语法格式相对来说,要比HTML严谨很多)
- 如何启用jsx语法?
- 安装
babel插件- 运行
npm i babel-core babel-loader babel-plugin-transform-runtime -D - 运行
npm i babel-preset-env babel-preset-stage-0 -D - 在webpack.config.js文件中添加第三方匹配规则

- 运行
- 安装能够识别转换jsx语法的包
babel-preset-react- 运行
npm i babel-preset-react -D
- 运行
- 添加
.babelrc配置文件 *
- 安装
JSX语法注意事项
- 在jsx中写注释:推荐使用
{ /*注释内容*/ } - 为jsx中的元素添加class类名:需要使用
className来代替classhtmlFor替换label 的for属性(注意:是标签上面的for属性) - 在jsx创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹
- 在jsx中标签必须成对出现,如果是单标签需要自闭和
当编译引擎,在编译jsx代码的时候,如果遇到了 < 那么就把它当作html代码去编译,如果遇到 {} 就把{}内部的代码当作普通js代码去编译

创建组件,并为组件传递props数据
方式一:(注意:组件的名称都需要以大写字母开头)
// 创建组件的第一种方式
function Hello(props) {
console.log(props);
return <div>这是Hello组件==== {props.name} </div>
}
let data = {
name:'aaa',
age:30
}
ReactDOM.render(<div>
{/* 直接把组件的名称,以标签的形式丢到页面上就好 */}
<Hello name={data.name} age={data.age}></Hello>
</div>,document.getElementById('app'))
方式二:(将组件抽离为单独的.jsx文件)
// Hello.jsx文件
// 创建组件的第二种方式
export default function Hello(props) {
console.log(props);
return <div>这是Hello组件==== {props.name} </div>
}
// 在index.js 文件中引入
import Hello from './components/Hello.jsx';
ReactDOM.render(<div>
{/* 直接把组件的名称,以标签的形式丢到页面上就好 */}
<Hello name={data.name} age={data.age}></Hello>
</div>,document.getElementById('app'))
-
注意一:
-
文件引入的时候,默认不能省略
.jsx后缀,如果想要省略,则需要事先在webpack.config.js文件中去配置
-

class讲解:(使用es6中新增的class关键字)
-
首先创建一个
.jsx的文件 -
class Animal { // 类的构造器,每一个类中都有一个构造器 // 如果程序员没有手动指定构造器,那么则可以认为,类内容中有个隐形,的看不见的空构造器 类似于 constructor(){} // 构造器的作用:每当 new这个类的时候,必然会优先执行构造器中的代码 // 在构造器中通过this分配的属性,可以称为实例属性 // 注意1:在class的 {} 区间内,只能写构造器,静态属性,静态方法,实例方法 // 不能 var a = 10 这样的语法会报错 // 注意2:class关键字内部,还是用原来的构造函数来实现的 constructor(name,age) { this.name = name; this.age = age; } // 静态属性【在class内部,通过static修饰的属性,就是静态属性】 static info = '我是静态属性' // 实例方法 sihli() { console.log('我是挂载到原型对象上的实例方法'); } // 静态方法 static s_shili() { console.log('我是静态方法'); } } const a1 = new Animal('小黄',30); // 创建一个实例对象,并且传递参数 console.log('class创建的组件',a1) console.log('访问静态属性',Animal.info) // console.log('实例方法的访问',a1.sihli) a1.sihli() // 访问静态方法 Animal.s_shili();
extends与super介绍
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
sayHi() {
console.log('你好,我是Person类中的方法')
}
}
class Child extends Person{
constructor(name,age) {
// 问题一:为什么一定要在constructor中调用super
// ------ 如果一个子类,通过extends关键字继承父类,那么在子类的constructor构造函数中,必须优先调用一下super()
// 问题二:super是什么?
// ------- super是一个函数,而且,它是父类的构造器,子类的super其实就是父类中,constructor构造器中的一个引用
// 问题三:为什么调用super之后,child实例的name和age都变成了underfined
super()
}
}
const child = new Child('Jacqui',21);
child.sayHi();
console.log('===',child.name,child.age)
方法二:(使用class关键字,创建组件,并接收外界传递过来的参数)
// 使用class关键字,创建组件
class Movie extends React.Component {
// render 函数的作用是渲染当前组件 对应的虚拟DOM元素
// 另一个问题:render属于class的实例方法
// 在class关键字,创建的组件中,如果想使用外界传递过来的 props参数,不需要接收,直接this.props.xxx访问即可
render() {
// 注意:在class组件内部,this表示当前组件的实例对象
return <div>我是使用class关键字创建的组件--- { this.props.name } </div>
}
}
ReactDOM.render(<div>
{/* 这里的Movie标签,其实就是Movie 类 的一个实例对象 */}
<Movie {...data}></Movie>
</div>,document.getElementById('app'))
class关键字创建的组件,接收外界传递过来的参数,不需要接收,直接使用 this.props.xxx
两种创建组件方式对比
注意一:使用class关键字创建的组件,有自己的私有数据**(this.state)**和生命周期函数
注意二:使用function创建的组件,没有自己的私有数据和生命周期函数
- 用构造函数创建出来的组件,叫做 无状态组件
- 用 class关键字 创建出来的组件,叫做 有状态组件
- 组件中的
props和state/data之间的区别- props中的数据是只读的,不能重新赋值
- state/data中的数据,都是可读可写的
- props中的数据,都是外界传递过来的
- state/data中的数据,都是组件私有的(通过Ajax获取回来的数据,一般都是私有数据)
- 什么情况下使用有状态组件,什么情况下使用无状态组件?
- React官方说:无状态组件,由于没有自己的state和生命周期函数,所以运行效率会比有状态组件稍微高一些
有状态组件和无状态组件的本质区别
有无state属性 有无生命周期函数
应用案例:
-
function Child_cmList(props) { return <div> <h1>评论人:{props.user}</h1> <div>评论内容:{props.content}</div> </div> } class CmtList_parent extends React.Component { constructor() { super() this.state = { CommonList: [ {id:1, user:'张三',content:'内容1'}, {id:2, user:'李四',content:'内容2'}, {id:3, user:'王五',content:'内容3'}, {id:4, user:'麻子',content:'内容4'}, {id:5, user:'sss',content:'内容5'}, {id:6, user:'Jack',content:'内容6'} ] } } render() { return <div> <h1>评论列表标题</h1> {this.state.CommonList.map(item => // <div key={item.id}> // <h1>评论人:{item.user}</h1> // <div>评论内容:{item.content}</div> // </div> <Child_cmList {...item} key={item.id}></Child_cmList> )} </div> } } ReactDOM.render(<div> <CmtList_parent></CmtList_parent> </div>,document.getElementById('app'))
React行内样式的写法
// 方式一:
<h1 style={{ color:'#f00',textAlign:'center',fontSize:'35px' }}>评论列表标题</h1>
// 方式二:
const h1Style = { color:'#f00',textAlign:'center',fontSize:'35px' }
<h1 style={h1Style}>评论列表标题</h1>
// 方式三:抽离为单独的 样式表 模块 ==》把样式单独封装成一个样式对象 .jsx 文件
export default item = {
h1Style:{color:'#f00',textAlign:'center',fontSize:'35px' }
}
import Style from 'style.jsx'
<h1 style={Style.h1Style}>评论列表标题</h1>
webpack默认无法打包 .css 文件
- 安装插件
npm i style-loader css-loader -D
React样式表作用域冲突的问题
为普通样式表通过modules参数启用模块化

css模块化 只针对
类选择器和id选择器生效css模块化 不会将标签选择器模块化
使用 localIdentName 自定义生成的类名的格式,可选的参数有:
-
[path] 表示样式表
相对于项目根目录所在的路径 -
[name] 表示样式表文件名称
-
[local] 表示样式的类名定义名称
-
[hash:length] 表示32位的hash值
-
{ test: /\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']},
元素有多个类名
// 方式一
<h1 className={变量 + ' text'}></h1>
// 方式二
<h1 className={[变量, 'text'].join(' ')}></h1>
// 后面写 .join(' '); 的原因,因为在页面上渲染的时候,类和类之间使用 , 分割的,
如何让类名不被模块化(:global())
注意一:被
:global()包裹起来的类名,不会被模块化,而是全局生效注意二:被
:local() 包裹起来的类名,会被模块化,默认所有的类名和Id选择器,都被模块化了
// 方式一:在 xx.css
:global(.test) {
color:#0f0;
}
使用第三方样式表
- 安装
Bootstrapnpm i bootstrap@3.3.7 -S
在项目中启用模块化,并同时使用Bootstrap,会出现问题,如果模块化启用,第三方样式文件类名也会被模块化,所以为了避免这种情况,自己的样式文件写 scss 或者 less
React中绑定事件注意点
-
事件的名称都是React提供的,因此名称的首字母
必须大写onClickonMouseOver -
为事件提供的处理函数,必须是如下格式
onClick = {function} // 方式一: <button onClick={this.myClick}>My Name Is Button</button> // 与render平级,定义一个 myClick 方法 myClick() { console.log('点击了按钮') } // 注意:方式一的写法,没办法传递参数 // 方式二 <button onClick={() => {this.myClick('张三')}}>My Name Is Button</button> myClick(name) { console.log(name+'点击了按钮') } // 方式三:将箭头函数简化 <button onClick={ () =>this.myClick('张三') }>My Name Is Button</button> myClick =(name)=>{ console.log(name+'点击了按钮') }
修改state上的数据
// 注意:在React中想要修改state中的值,不能用下面的写法
this.state.msg = name; // 错误写法
// 正确写法: this.setState({msg:'123'})
this.setState({ // 这个方法是异步的
msg:name
})
this.setState({ // 这个方法是异步的
msg:name
},()=> {
console.log('因为this.setState这个方法的执行是异步的,如果想要获取最新的值:',this.state.msg)
})
代码一旦被注释,无法折叠,使用下面的写法能解决这一问题
//#region
// 被注释的内容
//#endregion