DOM本质就是用JS表示UI元素
DOM是浏览器提供的,虚拟DOM不是浏览器提供的,是手工实现的。
手动模拟DOM树的原理,使用JS创建一个对象,来模拟每个DOM节点,然后在每个DOM节点中,又提供了一个类似children这样的属性,来描述当前DOM的子节点,这样,当DOM节点兴城了嵌套关系,就模拟出了一个DOM树。
React算法核心:Diff算法
在React学习中需要安装两个包:react react-dom
react这个包是专门创建组件、组件声明周期的
react-dom封装了和DOM操作相关的包
cnpm i react react-dom -S
import React from 'react'
import ReactDOM from 'react-dom'
//创建DOM元素,需要使用React提供的JS API创建
var myDiv = React.createElement() //接受三个参数,1、字符串;2、属性对象,表示创建的元素身上有哪些属性,3、从第三个参数位置开始,后面可以放很多DOM对象
//通过RDOM将元素放置到页面上
ReactDOM.render(myDiv,document.getElementById('app'));
JSX语法:能够在JS中写入像HTML一样的代码
注意需要 @babel/preset-react插件,并在规则里如下配置方能生效
{test: /\.js|jsx$/, use:{loader:'babel-loader',options:{presets: ['@babel/preset-env','@babel/preset-react']}},exclude: /node_modules/},
var myDiv = <div>
这是使用jsx语法创建的div元素
</div>
ReactDOM.render(myDiv,document.getElementById('app'));
如果要在jsx内部写js代码,需要在内部用花括号括起来{}
注意如果要为元素添加class属性,那必须写成className属性
label标签中的for属性也要替换成htmlFor
如果要写注释,注释也要放进{}里面 {/* */}
在react中构造函数就是一个最基本的组件,如果想把组件放到页面中,以HTML标签形式引入页面中。
function Hello(){ //React在解析所有的标签的时候,如果标签首字母小写则是按照html标签解析,如果是大写则按照组件解析
return <div>
<h1>这是在组件中定义的元素</h1>
</div>
}
ReactDOM.render(<div>
<Hello></Hello>
</div>,$('#app')[0]);
如果想在组件中引用外部传递过来的数据,必须在构造函数参数列表中,定义props属性来接受,起别的名也行,arguments不行。
使用剩余参数...来进行参数扩散:
var person ={id:"6666",title:"hhhh"}
ReactDOM.render(<Hello {...person}></Hello>,$('#app')[0])
React项目搭建过程:
创建组件的两种方式:
function Hello(props){
return <p>haha,{props.id}</p>
}
//使用class创建的类通过extends关键字,继承了React.Component之后,这个类,就是一个组件的模板了
//在class组件内部必须定义一个render函数
class Hello2 extends React.Component{
render(){
return <h1>这是使用class创建的,{this.props.id}---{this.props.title}</h1>
}
}
//用class定义的组件可以直接调用this.props来获取属性
constructor(props){
super(props)
this.state = {
msg:'这是Hello2组件的私有msg数据',
info:'瓦塔西***'
}
} //在constructor中,如果想要访问props属性必须显式定义props
使用function状态创建的组件叫做无状态组件;
使用class创建的组件叫做有状态组件。
function创建的组件没有生命周期函数,class创建的组件有生命周期。
如果一个组件需要存放私有数据或者在组件的不同阶段执行不同的业务逻辑,那么用class。
如果一个组件只需要根据外接传递过来的props,渲染固定页面,那么用function,速度也会更快。
class CommentList extends React.Component{
constructor(props){
super(props)
this.state={
cmts:[
{user:'张三',content:'哈哈,沙发'},
{user:'张三2',content:'哈哈,板凳'},
{user:'张三3',content:'哈哈,凉席'},
{user:'张三4',content:'哈哈,砖头'},
{user:'张三5',content:'哈哈,山炮'},
]
}
}
render(){
return <div>
{this.state.cmts.map((item,i)=>{
return <div key={i}>
<h1>{item.user}</h1>
<h3>{item.content}</h3>
</div>
})}
</div>
}
}
把评论项转换成无状态组件:
function CommentItem(props){
return <div>
<h1>{props.user}</h1>
<h3>{props.content}</h3>
</div>
}
class CommentList extends React.Component{
constructor(props){
super(props)
this.state={
cmts:[
{user:'张三',content:'哈哈,沙发'},
{user:'张三2',content:'哈哈,板凳'},
{user:'张三3',content:'哈哈,凉席'},
{user:'张三4',content:'哈哈,砖头'},
{user:'张三5',content:'哈哈,山炮'},
]
}
}
render(){
return <div>
{this.state.cmts.map((item,i) =>{
return <CommentItem {...item} key={i}></CommentItem>
})}
</div>
}
}
开启css模块化:
{test:/\.css$/,use:['style-loader',{loader: 'css-loader',options: {modules:{
mode: 'local',
localIdentName: '[name]__[local]--[hash:base64:5]',
context: path.resolve(__dirname, 'src'),
hashPrefix: 'my-custom-hash',
}}}],exclude: /node_modules/}, //配置处理.css文件的第三方loader规则 并启用模块化
全局样式加上 :global(.class) 包起来就会变成全局样式,而且不会被模块化