React基础
React.js是全球最火的前端框架(Facebook推出的前端框架),衍生出了reactnative(移动端),reactAR(虚拟现实)。
安装nodejs好,再安装脚手架create-react-app,官方推出的。
npm install -g create-react-app
再用脚手架创建一个demo
D: //进入D盘
mkdir ReactDemo //创建ReactDemo文件夹
create-react-app demo01 //用脚手架创建React项目
cd demo01 //等创建完成后,进入项目目录
npm start //预览项目,如果能正常打开,说明项目创建成功
进入项目根目录后(就是第一眼看到的目录)
- src : 主要代码编写文件,这个文件夹里的文件对我们来说最重要。
- node_modules :这个文件夹就是我们项目的依赖包,脚手架已经都给我们下载好了,你不需要单独安装什么。
- gitignore : 这个是git的选择性上传的配置文件,比如
node_modules
文件夹,就需要配置不上传。 - package.json: 这个文件是
webpack
配置和项目包管理文件,项目中依赖的第三方包(包的版本)和一些常用命令配置都在这个里边进行配置。 - package-lock.json:这个文件用一句话来解释,就是锁定安装时的版本号,并且需要上传到git,以保证其他人再
npm install
时大家的依赖能保证一致。 - README.md :这个文件主要作用就是对项目的说明,已经默认写好了一些东西,编写这个文件可以使用
Markdown
的语法来编写。
src文件夹简介:
- index.js : 这个就是项目的入口文件。
- index.css :这个是
index.js
里的CSS文件。 - app.js : 这个文件相当于一个方法模块。
- serviceWorker.js: 这个是用于写移动端开发的,PWA必须用到这个文件,有了这个文件,就相当于有了离线浏览的功能。
入口文件的编写:
在src目录
下,新建一个文件index.js
,然后编写最简单的代码。
import React from 'react' //一二行是必须要引入的
import ReactDOM from 'react-dom' //DOM(DOM—Document Object Model)是W3C国际组织的一套Web标准。DOM的本质是建立网页与脚本语言或程序语言沟通的桥梁。也叫浏览器对象,是一个分层结构。
import App from './App' //在引入app组件,现在还没写
ReactDOM.render(<App />,document.getElementById('root')) //APP组件渲染到了root ID上面,rootid在public/index.html
写app组件:
import React, {Component} from 'react' //安插件Simple React Snippets,快捷键imrc
class App extends Component{
render(){
return (
<div>
Hello JSPang
</div>
)
}
}
export default App; //暴露出组件
npm start 启动,可以查看一下效果。
JSX简介:
JSX就是Javascript和XML结合的一种格式。React发明了JSX,可以方便的利用HTML语法来创建虚拟DOM,当遇到<
,JSX就当作HTML解析,遇到{
就当JavaScript解析.大量了简化工作。
component与JSX的区别:
自定义的组件必须首字母大写,jsx是小写字母开始。
使用自己定义的组件:把入口文件的<App />
组件换成自己组件名字。
现在新建一个Xiaomeimei.js文件,打出如下代码:简单的列表。
import React,{Component} from 'react'
class Xiaomeimei extends Component{
render(){
return (
<div>
<div><input /> <button> 增加服务 </button></div>
<ul>
<li>头部按摩</li>
<li>精油推背</li>
</ul>
</div>
)
}
}
export default Xiaomeimei
组件外层包裹原则:写一个组件的时候,组件的最外层都需要有一个包裹
。若在布局中,真的用不上最外层的标签怎么办,没关系,react已经考虑到这个问题,用,去浏览器中看,发现没有了最外层的包裹。
响应式设计和数据绑定:
无需直接操作dom元素,只需要关注数据的操作就可以了,数据驱动(这也是React如此受欢迎的主要原因,大大加快了我们的开发速度)。
数据定义在组件的构造函数中即可
//js的构造函数,由于其他任何函数执行
constructor(props){
super(props) //调用父类的构造函数,固定写法
this.state={
inputValue:'' , // input中的值
list:[] //服务列表
}
}
数据绑定到输入框:但这样会把数据绑死。
<input value={this.state.inputValue} />
如果想要改变,需要绑定响应事件
<input value={this.state.inputValue} onChange={this.inputChange} />
绑定个inputChange()
inputChange(e){
// console.log(e.target.value);
// this.state.inputValue=e.target.value;
this.setState({
inputValue:e.target.value
}) //只能用这个setstate来改变值,直接赋值是错的。
}
列表在页面上循环输出:map循环函数,里面的箭头函数带两个参数item,index。关于箭头函数,这是es6语法新增的一种新的函数,因为长得像箭头,所以叫箭头函数,相当于匿名函数。这里为了按照react的要求,我们在每个循环的li元素里,再加上key值,通常是item+index(一个index也行)。
<ul>
{
this.state.list.map((item,index)=>{
return <li key={index+item}>{item}</li>
})
}
</ul>
当然数据还是绑死在构造函数里面:添一个列表。
constructor(props){
super(props) //调用父类的构造函数,固定写法
this.state={
inputValue:'jspang' , // input中的值
//----------主要 代码--------start
list:['基础按摩','精油推背']
//----------主要 代码--------end
}
}
增加添加服务功能:在按钮上绑定一个this.addList()方法。
<button onClick={this.addList.bind(this)}> 增加服务 </button>
补充响应的方法:这里的三个点,是扩展运算符,也是es6的新语法,用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中,有点展开数组的意思,当然还有其他用法,这里就不展开,以后有机会写到这块儿时再展开。
//增加服务的按钮响应方法
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue]
}) //之前的内容循环拷贝,加上输入的内容,得到想要的。
}
增加删除功能:首先要得到要删的东西的下标,然后添加删除方法,若用纯js代码,确实需要点技术,我现在说实话是没学过js的,我是直接上手的react。此外,现在的typescript有取代js的趋势,所以我学的话是会“双管齐下”的。
说到这里,我就忍不住想补充点我的学习心得:
这个特殊的寒假,我会好好肝博客的,说点题外话,这个假期是我自学的第二个假期,第一个是大一下的暑假,现在是大二上的寒假。这个寒假因为武汉肺炎事件,寒假过成了暑假,在家自学前端,javaspringboot等。比起第一个假期,这个假期显然是学的东西更充实,大一下的暑假自学了Python,当时是在中国大学mooc上找的课,学了一段时间,后来在新生群里闲逛的时候,看到了一个学长提到淘宝上可以买教程来学,于是当晚便找到了了心仪的教程,立刻买下,下完客服让下的资源,就开始兴致勃勃的看,当时看的挺爽的,感觉学了很多不管是基础还是简单的骚操作,对我来说,开启了一个新世界。随后开始刷这些培训班的教程,也加了交流群。后来在群里了,我又发现了一座新大陆,就是大名鼎鼎的blibli,b站,当时是一位管理员提到了一位b站的up主的视频,于是我去搜,发现,哎呦,这个up主讲的东西很多啊,还很有体系。当时就想能不能在b站上找到更多类似的教程,结果让我喜出望外,果然是有的,天哪而且还免费,天哪,真香,于是我的**“面向b站编程之路”**便开始了。也不是说我当时不知道b站这个东西,其实早就知道的,但我一直以为这是看动漫的一个视频播放器而已,还没发现有学习的奇效。也理解了为什么许多人叫b站为当代大学生学习平台。嘿嘿,围绕b站的学习资源也是多的让我头大,不仅学到知识和技巧,也学到了不少巨佬的学习经验。
//删除单项服务
deleteItem(index){
let list = this.state.list //这里有个坑,react是禁止直接操作state的,要另外在赋到一个变量上,然后再进行处理。
list.splice(index,1)
this.setState({
list:list
})
}
注释方面用快捷键:ctrl+/,因为代码这个东西也是很有讲究的。
要自定义类的话,推荐用classname,怕和js的class重名。
jsx中HTML的解析问题,文本框里输入HTML代码,并不会被解析,只会原样打印出,这里用dangerouslysetinnerhtml属性解决,如下。
<ul>
{
this.state.list.map((item,index)=>{
return (
<li
key={index+item}
onClick={this.deleteItem.bind(this,index)}
dangerouslySetInnerHTML={{__html:item}}
>
</li>
)
})
}
</ul>
label标签:原思想label里直接for,这里也是怕和js的for循环搞在一起,用htmlfor,这样点击标签就可以输入了。
<div>
<label htmlFor="jspang">加入服务:</label>
<input id="jspang" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
<button onClick={this.addList.bind(this)}> 增加服务 </button>
</div>
父对子组件传值:通过属性传值,子组件用this.props.xxx来接收(全局参数接收)**
传递值是需要加类型限制的,不然大型项目会崩,在报错时也可以快速找出错误。通过import PropTypes from ‘prop-types’导入,在子组件中编写类型限制。使用isRequired
关键字了,它表示必须进行传递该属性值。
XiaojiejieItem.propTypes={
content:PropTypes.string,
deleteItem:PropTypes.func,
index:PropTypes.number
}
子对父组件传值:比如说删除功能,子组件绑定方法handleclick(),通过this.props调用父组件方法,同样用this.props调用父组件的参数。
子组件构造函数中,绑定方法,在开发高级组件时性能会高很多。
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}
handleClick(){
this.props.deleteItem(this.props.index)
}
函数式编程:
- 函数式编程让我们的代码更清晰,每个功能都是一个函数。
- 函数式编程为我们的代码测试代理了极大的方便,更容易实现前端自动化测试
单向数据流:
React developer tools:调试工具,`有三种颜色,三种颜色代表三种状态:
灰色:不是用react编写的;
红色:是react编写,处于调试环境;
黑色:是react编写的,处于生产环境;
打开浏览器,然后按F12
,打开开发者工具,然后在面板的最后一个,你会返现一个React
,这个就是安装的插件了。
代码语义化:增加代码可读性,就算重要成员离开,也不会导致整个项目的卡死。ref是个不错的选择。
这里面的e.target.value我看不懂很不爽
inputChange(e){
this.setState({
inputValue:e.target.value
})
}
然后,这ref就出来
<input
id="jspang"
className="input"
value={this.state.inputValue}
onChange={this.inputChange.bind(this)}
//关键代码——----------start
ref={(input)=>{this.input=input}}
//关键代码------------end
/>
最终效果
inputChange(){
this.setState({
inputValue:this.input.value
})
}
这样就知道是thisinput的值传递过来的。
ref的一个坑:
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue],
inputValue:''
})
//关键代码--------------start
console.log(this.ul.querySelectorAll('div').length)
//关键代码--------------end
}
这样写的目的是求一个无序列表的长度,但打印出来的数量却总是少一个,因为setstate是一个异步函数,虽写在关键代码的前面,但是却是后执行。每次都是先打印在添加项目。
但天无绝人之路,把关键代码放入setstate中即可,第二个函数为回调函数
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue],
inputValue:''
//关键代码--------------start
},()=>{
console.log(this.ul.querySelectorAll('div').length)
})
//关键代码--------------end
}
生命周期函数:就是设计代码的人,自定义了一些有固定使用顺序的一些函数。
分四个阶段:初始化;挂载;更新;不挂载(销毁)。注意构造函数不算生命周期函数,但心里可以当做一个初始化的生命周期函数。
挂载:
componentWillMount
: 在组件即将被挂载到页面的时刻执行。render
: 页面state或props发生变化时执行。componentDidMount
: 组件挂载完成时被执行。
更新:
shouldComponentUpdate():返回ture才能进行他后面的钩子函数。在性能优化方面,也有大作用。减少dom渲染次数。只有当内容变化时,才进行渲染。
- nextProps:变化后的属性;
- nextState:变化后的状态;
shouldComponentUpdate(nextProps,nextState){
if(nextProps.content !== this.props.content){
return true
}else{
return false
}
}
还有两个,一个是组件更新前且接到shouldcomponentupdate()返回true才能执行;一个是组件更新后。
componentWillReceiveProps():子组件接收父组件props时触发。
销毁:componentWillUnmount()当组件从页面消失时执行。
Axios:ajax框架集成的远程请求数据的模块。强烈推荐组件挂载后使用axios请求远程数据。
componentDidMount(){
axios.post('https://web-api.juejin.im/v3/web/wbbr/bgeda')
.then((res)=>{console.log('axios 获取数据成功:'+JSON.stringify(res)) })
.catch((error)=>{console.log('axios 获取数据失败'+error)})
}
三元表达式实现简单动画:
一个按钮控制一段文字的出现和消失;
按钮:
<div><button onClick={this.toToggole}>召唤Boss</button></div
文字:
<div className={this.state.isShow ? 'show' : 'hide'}>BOSS级人物-孙悟空</div>
转换功能:通过点击按钮,控制isshow值的真假变换
toToggole(){
this.setState({
isShow:this.state.isShow ? false : true
})
}
真的话一个样式,假的话一个样式;
.show{ opacity: 1; transition:all 1.5s ease-in;}
.hide{opacity: 0; transition:all 1.5s ease-in;}
当然,isshow要设置一个初始值,方法要绑定在构造器中,这样能提高效率;
constructor(props) {
super(props);
this.state = {
isShow:true
}
this.toToggole = this.toToggole.bind(this);
}
当然,使用关键帧能更细致的来调节样式动画。大概就是下面的那个方式。
@keyframes hide-item{
0% {
opacity:1;
color:yellow;
}
50%{
opacity: 0.5 ;
color:red;
}
100%{
opacity:0;
color: green;
}
}
react官方也提供了一些动画组件库:react-transition-group
动画组件,有完善的API。这里不做深入,想研究可以读读文档或书,来深入了解。