提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- sass
- React
sass
一、什么是CSS预处器
CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。通俗的说,CSS预处理器用一种专门的编程语言,进行Web页面样式设计,然后再编译成正常的CSS文件,以供项目使用。CSS预处理器为CSS增加一些编程的特性,无需考虑浏览器的兼容性问题,例如你可以在CSS中使用变量、简单的逻辑程序、函数等等在编程语言中的一些基本特性,可以让你的CSS更加简洁、适应性更强、可读性更佳,更易于代码的维护等诸多好处。
1.1 Sass背景介绍
Sass是对CSS(层叠样式表)的语法的一种扩充,诞生于2007年,最早也是最成熟的一款CSS预处理器语言,它可以使用变量、常量、嵌套、混入、函数等功能,可以更有效有弹性的写出CSS。Sass最后还是会编译出合法的CSS让浏览器使用,也就是说它本身的语法并不太容易让浏览器识别,因为它不是标准的CSS格式,在它的语法内部可以使用动态变量等,所以它更像一种极简单的动态语言。
其实现在的Sass已经有了两套语法规则:一个依旧是用缩进作为分隔符来区分代码块的;另一套规则和CSS一样采用了大括号({})作为分隔符。后一种语法规则又名SCSS,在Sass3之后的版本都支持这种语法规则。
注:Sass官网地址:http://sass-lang.com
二、把Sass编译成css
2.1 安装
安装推介B站良心up主:Sass windows安装教程
2.2 创建项目
-
在你需要的地方创建项目,然后在编辑器中打开该目录
-
这里我创建的项目是,ninghao-sass
-
在ninghao-sass目录下创建一个文件夹sass,在该文件夹下新建文件style.scss 该目录用于存放项目所有的sass文件
-
在ninghao-sass目录下创建一个文件夹css,在该文件夹下新建文件style.scss 该目录用于存储编译好的css文件
-
然后我们在style.scss中输入
body{
font-size: 15px;
}
2.3 打开命令行工具,把这个sass文件编译成普通的css文件
首先要进入到项目 目录下 也就是ninghao-sass
输入命令: sass (要编译的文件):(要输出的css文件)
sass sass/style.scss:css/style.css
- 完成以后,css文件夹下会出现编译好的css文件
2.4 自动编译
- sass --watch (要监视的目录):(指定编译后的目录)
- sass --watch sass:css
- ctrl+c 可以取消自动编译
2.5 Sass编译方式
- 更改Sass编译方式的方法 --style [compact,expanded,compressed]
- 更改编译方式命令:sass --watch sass:css --style compact
2.5.1nested 嵌套 (默认)
2.5.2compact 紧凑
2.5.3expanded 扩展
2.5.4compressed 压缩
三、Sass 与 less的区别
- 扩展名不一样
- Sass 是 .sass
- less 是 .scss (常用)
四、Scss的变量
- 使用 $符号+名称 可以定义变量
- 变量里可以使用另外一个变量
4.1 嵌套写法
-
效果和注释掉的一模一样
-
不过如果在写伪类的时候这样写的话会出现下面这种情况
-
可以看到编译过后的css文件会多出一个空格
-
这个时候我们只需要在伪类标签前添加 & 符号即可
4.2 引用父选择器
Scss
/* 嵌套时调用父类选择器*/
.nav{
height: 100px;
& &-item{
font-size: 10px;
}
}
Css
.nav .nav-item{
font-size: 10px;
}
五、嵌套属性
对于同一个选择器下,相同的属性名称,我们可以提取出来。例如:
.nav{
border:1px solid #000;
border-left: 0;
border-right: 0;
}
可以写成
.nav{
border:1px solid #000{
left:0;
right: 0;
}
}
可以发现,编译后的css文件四一模一样的。
六、mixin (类似JS函数)
可以把它想象成是,有名字的、定义好的样式
可以在任何地方,重复使用,可以把它当作是JS的函数
你可以使用使用@符号定义它,例如:
@mixin 名字(参数1,参数2){
...
}
mixin 可以嵌套使用变量,子样式、或者其他mixin 例如:
@mixin alert {
color: #8a8a8a;
background-color: #fcf8e3;
@include test;
a{
color: green($color: #000000);
@include test;
}
}
@mixin test {
font-weight: 15px;
}
.alert-waring{
@include alert;
}
- 第一:我们首先定义了一个alert,然后在里边添加了一些样式,
- 第二:我们引入了另外的一个mixin
- 第三:我们在alert这个mixin下,又定义了一个a的样式。接下来我们看看会编译成什么样子
可以看到,效果是非常不错的,不仅嵌套的test编译出来了,而且子级的a样式,也成功编译。
6.1 darken (加深指定的颜色)
darken(参数1,参数2)
- 参数1:要加深的颜色
- 参数2:百分比加深多少
6.2 调用mixin
默认我们调用mixin的时候,参数需要对应。
但是当我们指定参数的时候,就可以不用对应。例如:
注意:指定参数的时候需要使用 : 号 来紧跟对应的值
七、@extend 继承或者扩展
在Sass中我们可以使用@extend来减少重复的动作
继承相当于把继承类的类名换成当前类的类名。并且样式是继承类的样式。
简单来说,就是我把你的变成我们共同的。
当我们使用@extend继承的时候,右边编译后的css文件会出现群组选择器。它们会同时拥有在群组选择器里边的样式。
八、 @import 与 Partials
Partials文件名要以 _ (下划线开头)
那么如何引入Partials文件呢?
在文章开头,我们使用 @import + “文件名;” 的方式即可,
不需要写下划线,也不需要写扩展名,在同级目录下不需要写路径
九、注释
9.1、多行注释
- 会在编译输出的结果中保留 但在压缩方式的编译情况下会去掉
/*
这是多行注释
天王盖地虎
*/
9.2、单行注释
- 不会出现在编译输出之后的文件里面。
//这是单行注释
9.3、强制注释
- 这样注释的内容,会一直出现在css里边
/*!这是强制注释*/
十、Data Type
-
在命令行中我们输入 sass -i
-
这是sass提供的交互功能,在这之后你输入的内容回车之后会立刻看到结果。
-
判断数据的类型 可以使用 type-of()
-
数据类型的数字还可以包含单位 例如:
当然还有很多其他用法 例如:
十一、number 运算
- 在sass交互模式下,试一下数字的运算
十二、数字函数
- abs() 取绝对值
- round() 四舍五入
- ceil() 向上取整
- floor() 向下取整
- percentage() 取百分比
- min(1,2,3) 取最小的
- max(1,2,3) 取最大的
十三、String 字符串
带引号:可以包含空格,和一些其他特殊字符
不带引号:不能有空格
- 号 - 号 / 号 都可以连接字符串
>> "ning" + hao
"ninghao"
>> ning + "hao"
"ninghao"
十四、字符串函数
在Sass中有一些函数可以处理字符串类型的数据。
14.1 to-upper-case() 全部转为大写
在这里我们先定义了一个变量 $greeting,然后把该变量作为to-upper-case()函数的参数,可以发现,该字符串的英文全部转化为大写了。
PS F:\Node.js\Node_project\ninghao-sass> sass -i
>> $greeting:"hello,world"
"hello,world"
>> $greeting
"hello,world"
>> to-upper-case($greeting)
"HELLO,WORLD"
>>
14.2 to-lower-case() 全部转为小写
用法同上。
PS F:\Node.js\Node_project\ninghao-sass> sass -i
>> $greeting:'Hello,World'
"Hello,World"
>> to-upper-case($greeting)
"HELLO,WORLD"
>> to-lower-case($greeting)
"hello,world"
>>
14.3 str-length() 返回字符串长度
用法同上。
>> str-length($greeting)
11
>>
14.4 str-index() 返回指定字符在字符串中首次出现的位置
注意:索引是从1开始的
>> $greeting:'Hello,World'
>
>> str-index($greeting,'world')
null
>> str-index($greeting,'World')
7
>>
14.5 str-insert() 插入字符串
语法: str-insert(要往那个字符串插入,插入的是什么,插入的位置)
>> str-insert($greeting,',Good morning',12)
"Hello,World,Good morning"
你也可以在str-insert函数中嵌套使用其他函数,比如:
>> str-insert($greeting,',Good morning',str-length($greeting)-5)
"Hello,Good morning,World"
>>
十五、颜色
在css里边表示颜色的方式有很多种,
例如:
#FF0000 16进制
rgb(255,0,0) RGB方式 红,绿,蓝
还有一些常用的字符类型的 比如 red black white blue
15.1 颜色函数 RGB与RGBA
rgb(红,绿,蓝)
rgba(红,绿,蓝,透明度(0-1));
a:完全透明-完全不透明
body{
background-color: rgba(255, 255, 0,1);
}
15.2 颜色函数 hsl与hsla
hsl语法:色相,饱和度,明度
色相:0°-360°
饱和度:0-100%
明度:0-100%
hsla语法:基本同上,和rgba差不多
15.3颜色函数 adjust-hue
adjust-hue(),可以调整色相的值。
语法:adjust-hue(要调整的对象,参数)
15.4 颜色函数 lighten与darken
lighten与darken可以改变颜色的明度
lighten可以让颜色更白,越大越接近白色
darken可以让颜色更黑,越大越接近黑色
15.5 颜色函数saturate与desaturate
saturate 增加颜色的纯度,也就是饱和度
desaturate 减少颜色的纯度。
15.6 颜色函数 opacify与transparentize 透明度
opacify:增加不透明度
opacify语法:opacify(要设置的对象,增加多少不透明度)
transparentize:减少不透明度
transparentize语法:基本同上
15.7 list 列表类型数据
sass里边的list可以使用空格、逗号、括号()、等分隔开
例如:
border:1px solid #000;
font-family: Courier, Lucida Console", monospace
padding:(5px 10px)(5px 0)
列表里边可以包含其他列表,比如:
padding里边是一个列表包含了两个列表。
padding:5px 10px,5px 0
15.8 列表函数
15.8.1 length() 返回列表项目个数
length()用于返回列表里有多少个项目:
例如:
PS F:\Node.js\Node_project\study> sass -i
>> length(5px 10px)
2
>> length(5px 10px 5px 0)
4
15.8.2 nth() 得到对应序号里边的数据
nth()用于得到指定位置的列表项目
PS F:\Node.js\Node_project\study> sass -i
>> nth(5px 10px,2)
10px
15.8.3 index()判断指定项目在列表里的位置
index() 用于判断指定项目在列表里的位置
>> index(1px solid red,solid)
2
15.8.4 append() 向列表追加项目
>> append(5px 10px,5px)
(5px 10px 5px)
这个函数还有第三个参数,用于指定列表的分隔符
例如:
>> append(5px 10px,5px,comma)
(5px, 10px, 5px)
15.8.5 join() 组合列表
join()用于组合列表
>> join(5px 10px,5px 5px)
(5px 10px 5px 5px)
这个函数也有第三个参数,用于指定分隔符 例如:
>> join(5px 10px,5px 5px,comma)
(5px, 10px, 5px, 5px)
十六、Map与相关函数
Map就是列表项目带名字的列表,例如:
$map: (key1: valuel, key2: value2, key3: value3)
16.1定义Map类型数据
PS F:\Node.js\Node_project\ninghao-sass> sass -i
>> $colors:(light:#ffffff,dark:#000000)
(light: #ffffff, dark: #000000)
用在列表上边的函数同样可以处理Map类型的数据。
例如:
length() 查看变量中有,几个变量
>> length($colors)
2
16.2 map-get(参数1,参数2) 可以根据键来得到值
例如:
>> map-get($colors,dark)
#000000
16.3 map-keys(参数1) 返回对象当中的所有key
例如:
>> map-keys($colors)
("light", "dark")
16.4 map-values(参数1) 返回对象当中所有的value
例如:
>> map-values($colors)
(#ffffff, #000000)
16.5 map-has-key(参数1,参数2) 判断对象当中是否有指定的key
例如:
>> map-has-key($colors,test)
false
>> map-has-key($colors,dark)
true
16.6map-merge(参数1,参数2) 把两个Map合并到一起
>> map-merge($colors,(light-gray:#e5e5e5))
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
合并之后我们可以把这个变量交给 $colors :
>> $colors:map-merge($colors,(light-gray:#e5e5e5))
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
>> $colors
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
>>
16.7 map-remove(参数1,参数2,…) 移除指定的键值对
例如:
>> map-remove($colors,light,light-gray)
(dark: #000000)
>>
注意:移除过后很少 $colors并没有减少,例如:
>> $colors
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
>> map-remove($colors,light,light-gray)
(dark: #000000)
>> $colors
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
可以看到$colors 还是原来的3个键值对
如果需要真正的移除需要对它赋值:
例如:
>> $colors
(light: #ffffff, dark: #000000, light-gray: #e5e5e5)
>> $colors:map-remove($colors,light,light-gray)
(dark: #000000)
>> $colors
(dark: #000000)
十七、boolean 布尔值
取值: true false
PS F:\Node.js\Node_project\ninghao-sass> sass -i
>> 5px > 3px
true
>> 5px > 10px
false
>> (5px < 10px) and (5px > 6px)
false
>> (5px < 10px) and (5px < 6px)
true
>> (5px < 10px) or (5px > 6px)
true
>> 5px > 3px
true
>> not (5px > 3px)
false
>> not (5px < 3px)
true
十八、Interpolation 可以把一个值插入到另一个值里边
简单点来说,就是在 特殊的地方(注释、属性名)等地方使用变量。
语法: #{} 花括号中间放变量名即可。
例如:
十九、流程控制语句
19.1 @if 判断
例如:
19.2 @for 循环
在Sass中,我们可以使用“@for”来实现循环操作。其中,Sass中的@for循环有2种方式。
语法:
方式1:@for $i from 开始值 through 结束值
方式2:@for $i from 开始值 to 结束值
说明:
这2种方式是相似的,唯一的区别是:方式1包括结束值,方式2不包括结束值。
其中“开始值”和“结束值”都是正整数。
举例:
分析:
如果将“@for $i from 1 through 3”改为“@for $i from 1 to 3”,则编译出来的CSS代码如下:
19.3 @each in 循环
就是去遍历一个列表,然后从列表中取出对应值;
19.4 @while 循环
只要条件为真,就执行语句体
二十、用户自定义函数
语法:
@function 函数名称(参数1,参数2,…){
…
}
这里我们定义一个函数 color ,用于根据map的key返回map的value
React
01-react概述
React
是一个用于构建用户界面的JavaScript库
。
用户界面: HTML页面(前端)
React主要用来写HTML页面,或构建Web应用
如果从MVC的角度来看, React仅仅是视图层(V ) , 也就是只负责视图的渲染,而并非提供了
完整的M和C的功能。
-
声明式
-
基于组件
-
学习一次,随处使用
声明式
只需要描述UI(HTML)是什么样,React负责渲染UI,并在数据变化时更新UI
const jsx = <div className="app">
<h1>React动态变化:{count}</h1>
</div>
基于组件
-
组件时React
最重要
的内容 -
组件表示页面中的部分内容
-
组合、复用多个组件,可以实现完成的页面功能
学习一次,随处使用
-
使用React可以开发Web应用
-
使用React可以开发移动端原生应用( react-native )
-
使用React可以开发VR(虚拟现实)应用(react360)
React的安装
安装命令:npm i react react-dom
-
react 包是核心,提供创建元素、组件等功能
-
react-dom 包提供DOM相关功能等
React的使用
1、引入react和react-dom 两个js文件
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
2、创建React元素
<script>
const title = React.createElement('h1',null,'Hello React')
</script>
3、渲染React元素
ReactDOM.render(title,document.getElementById('root'))
方法说明:
React.createElement
参数1:元素名称
参数2:元素属性
参数3…:元素的子节点(文本、标记…)
ReactDOM.render
参数1:要渲染的React元素
参数2:DOM,渲染的挂载位置
【案例:实现多个元素嵌套显示】
02-react脚手架
React脚手架意义
- 脚手架是开发现代Web应用的必备。
- 充分利用Webpack、 Babel、 ESLint等I具辅助项目开发。
- 零配置,无需手动配置繁琐的工具即可使用。
- 关注业务,而不是工具配置。
使用React脚手架初始化项目
1、初始化项目,命令:npx create-react-app 项目名称( my-app)
2、启动项目,在项目根目录执行命令:npm start (yarn start)
npx命令介绍
-
npm v5.2.0 引入的一 条命令
-
目的:提升包内提供的命令行工具的使用体验
-
以前:先安装脚手架包,再使用这个包中提供的命令
-
现在:无需安装脚手架包,就可以直接使用这个包提供的命令
补充:
1.推荐使用: npx create-react-app my-app
2.npm init react-app my-app
3.yarn create react- app my-app
-
yarn 是Facebook发布的包管理器,可以看做是npm的替代品,功能与npm相同
-
yarn具有快速、可靠和安全的特点
-
初始化新项目: yarn init
-
安装包: yarn add包名称
-
安装项目依赖项: yarn
-
其他命令,请参考yarn文档
在脚手架中使用React
1.导入react和react-dom两个包。
import React from 'react'
import ReactDOM from 'react-dom'
2.调用React.createElement(方法创建react元素。
3.调用ReactDOM.render(方法渲染react元素到页面中。
react基础阶段总结
-
React是构建用户界面的JavaScript库
-
使用react时,
推荐使用脚手架方式
。 -
初始化项目命令:
npx create-react-app my-app
。 -
启动项目命令:
yarn start
(或npm start
)。【案例】(关于模块化知识的使用)外部组件的定义
03-JSX的基本使用
createElement的问题:
1.繁琐不简洁。
2.不直观,无法一眼看出所描述的结构。
3.不优雅,用户体验不爽。
JSX简介
JSX是JavaScript XML的简写,表示在JavaScript代码中写XML ( HTML )格式的代码。
优势:声明式语法更加直观、与HTML 结构相同,降低了学习成本、提升开发效率
JSX使用步骤
1、使用JSX语法创建react元素
const title = <h1>Hello JSX</h1>
2、使用ReactDOM.render() 方法渲染react元素到页面
ReactDOM.render(title,root)
为什么脚手架中可以使用JSX语法
-
JSX不是标准的ECMAScript语法,它是
ECMAScript的语法扩展
。 -
需要使用
babel
编译处理后,才能在浏览器环境中使用。 -
create-react-app脚手架中已经默认有该配置,无需手动配置。
-
编译JSX语法的包为: @babel/preset-react。
JSX的注意点
- React元素的属性名使用
驼峰命名法
- 特殊属性名: class ->
className
、for -> htmlFor、tabindex -> tabIndex - 没有子节点的React元素可以用
/>
结束 - 推荐:使用
小括号包裹JSX
,从而避免JS中的自动插入分号陷阱
在JSX中使用JavaScript表达式
-
数据储存在JS中
-
语法:
{JavaScript表达式}
JSX的条件渲染
-
场景:loading效果
-
条件渲染:根据条件渲染特定的JSX结构
-
可以使用
if/else
或三元运算符
或逻辑与运算符
来实现
JSX的列表渲染
-
如果要渲染一组数据,应该使用数组的
map()
方法 -
注意:渲染列表时应该添加key属性,
key属性的值要保证唯一
-
原则:
map()
遍历谁,就给谁添加key属性 -
注意:
尽量避免使用索引号作为key
const students = [
{id:1,name:'张三'},
{id:2,name:'李四'},
{id:3,name:'王五'},
]
const list = {
<ul>
{students.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
}
JSX的样式处理
1、行内样式-style
<h1 style={{color:'red',backgroundColor:'blue'}}> JSX行内样式 </h1>
2、类名-className(推荐)
需要引入css
import './css/index/css'
【案例:将指定json数据渲染至网页中】
fetch(url)
.then(response => { response.json(()=>{}).then(...).then(...) })
JSX阶段总结
- JSX React的核心内容。
- JSX 示在JS代码中写HTML结构,是React声明式的体现。
- 使用JSX配合嵌入的JS表达式、条件渲染、列表渲染,可以描述任意UI结构。
- 推荐使用className的方式给JSX添加样式。
- React 完全利用JS语言自身的能力来编写UI ,而不是造轮子增强HTML功能。
04-React组件介绍
-
组件是React的
一等公民
,使用React就是在用组件 -
组件表示React实现的部分功能
-
组合多个组件实现完整的页面功能
-
特点:可复用、独立、可组合
组件的两种创建方式(1函数组件)
-
函数组件:使用JS的函数(或箭头函数)创建的组件
-
注意:函数名称必须以
大写字母开头
-
注意: 函数组件必须有
返回值
,表示该组件的结构 -
注意:返回值为null,就不显示任何内容
function Hello(){
return (
<div>函数组件</div>
)
}
-
渲染函数组件:用函数名作为组件标签名
-
组件标签可以是单标签,也可以是双标签
ReactDOM.render(<Hello />,root)
组件的两种创建方式(2类组件)
-
类组件:使用ES6的class创建的组件
-
注意:类名称必须以
大写字母开头
-
注意:类组件应该继承
React.Component
父类,从而可以使用父类中提供的方法或者属性 -
注意:类组件必须提供
render()
方法 -
注意:render() 方法必须用
return返回值
,表示该组件的结构
class Hello extends React.Component{
render(){
return <div>Hello Class Component!</div>
}
}
ReactDOM.render(<Hello />,root)
组件的两种创建方式(3抽离为独立js文件)
1、创建Hello.js
2、在Hello.js中导入React
3、创建组件(函数 或 类)
4、在Hello.js 中导出该组件
5、在index.js 中导入Hello 组件
6、渲染组件
import React from 'react'
class Hello extends React.Component{
render(){
return <div>Hello Class Component!</div>
}
}
export default Hello
React事件处理(1事件绑定)
-
React事件绑定语法与DOM事件语法很相似
-
语法:
on+事件名称 = {事件处理程序}
,比如:onClick = {()=>{}} -
注意:
React事件采用驼峰法命名
, 比如:onMouseEnter,onFocus -
如果在函数组件中绑定事件,则调用事件函数不加this
class App extends React.Component {
handleClick(){
console.log('被点击了')
}
render(){
return (
<button onClick={this.handleClick()}></button>
)
}
}
React事件处理(2事件对象)
-
可以通过
事件处理程序参数
获取到事件对象 -
React中的事件对象叫做:
合成事件
(对象) -
合成事件:兼容所有浏览器,无需担心跨浏览器兼容性问题
function handleClick(e){
e.preventDefault()
console.log('事件对象',e)
}
<a onClick={handleClick}>点击跳转</a>
有状态组件和无状态组件
-
函数组件又叫做
无状态组件
,类组件又叫做有状态组件
-
状态(state)即
数据
-
函数组件没有自己的状态,只负责
数据展示
(静态) -
类组件有自己的状态,
负责更新UI
(动态)
state的基本使用
-
状态(state)即数据,是组件内部的私有数据,只能在组件内部使用
-
state的值是对象
,表示一个组件中可以有多个数据 -
通过this.state 来获取状态
class Hello extends React.Component {
constructor(){
super()
this.state = {
count:0
}
}
render(){
return (
<div>有状态组件</div>
)
}
}
ES6简化语法
class Hello extends React.Component {
state = {
count:0
}
render(){
return (
<div>有状态组件</div>
)
}
}
【案例】有状态组件中的state可以定义哪些数据,如何调用
组件中的state和setState()(1setState()修改状态)
-
状态时可变的
-
语法:this.setState({要修改的数据})
-
注意:
不能直接修改state中的值
-
setState()作用:1、
修改state
2、更新UI
-
数据驱动视图
class Hello extends React.Component {
state = {
count:0
}
render(){
return (
<div>计数器:{this.state.count}</div>
<button onClick={()={
this.setState({
count:this.state.count + 1
})
}}>+1</button>
)
}
}
组件中的state和setState()(2从JSX中抽离事件处理程序)
-
JSX中有太多的JS逻辑代码,会使程序混乱
-
推荐:将逻辑抽离到单独的方法中,保证JSX结构清晰
class Hello extends React.Component {
state = {
count:0
}
onIncrement(){
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<div>计数器:{this.state.count}</div>
<button onClick={this.onIncrement()}>+1</button>
)
}
}
尝试将事件函数剥离JSX,我们会有:
TypeError:Cannot read property 'setState' of undefined
原因:事件处理程序中this的值为undefined
希望:this指向组件实例(render方法中的this即为组件实例)
无状态组件的state
const [count,setCount] = React.useState(0)
const [number,setNumber] = React.useState(1)
事件绑定this指向(1箭头函数)
- 利用箭头函数自身不绑定this的特点
class Hello extends React.Component {
state = {
count:0
}
onIncrement(){
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<div>计数器:{this.state.count}</div>
<button onClick={()=>this.onIncrement()}>+1</button>
)
}
}
事件绑定this指向(2bind)
- 利用ES5中的bind() 方法,将事件处理程序中的this与组件实例绑定到一起
class Hello extends React.Component {
state = {
count:0
}
constructor(){
super()
this.onIncrement = this.onIncrement.bind(this)
}
onIncrement(){
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<div>计数器:{this.state.count}</div>
<button onClick={()=this.onIncrement()>+1</button>
)
}
}
事件绑定this指向(3class的实例方法)
-
利用箭头函数形式的class实例方法
-
注意:改语法是实验性的,但babel可以转化该语法
class Hello extends React.Component {
state = {
count:0
}
onIncrement = ()=>{
this.setState({
count:this.state.count + 1
})
}
render(){
return (
<div>计数器:{this.state.count}</div>
<button onClick={this.onIncrement}>+1</button>
)
}
}
事件绑定this指向-总结
1、推荐:使用class的实例方法
2、箭头函数
3、bind
表单处理(1受控组件概念)
-
HTML中的表单元素是可输入的,也就是有自己的可变状态
-
而React中可变状态通常保存在state中,并且只能通过setState() 方法来修改
-
React将state与表单元素值value绑定到一起,
由state的值来控制表单元素的值
-
受控组件:其值受到React控制的表单元素
表单处理(2受控组件使用步骤)
受控组件设置步骤:
1、在state中添加一个状态,作为表单元素的value值(控制表单元素值的来源)
2、给表单元素绑定change事件,将表单元素的值,设置为state的值(受控表单元素值的变化)
state = {txt:''}
<input type="text" value={this.state.txt} onchange={e =>
this.setState({txt : e.target.value})} />
表单处理(3受控组件的示例)
富文本框textarea
state = {content:''}
handleContent = e=>{
this.setState({
content:e.target.value
})
}
<textarea value={this.state.content} onChange={this.handleCOntent}>
</textarea>
下拉框select
state = {city:'bj'}
handleCity = e=>{
this.setState({
city:e.target.value
})
}
<select value={this.state.city} onChange={this.handleCity}>
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="gz">广州</option>
</select>
复选框
state = {
isChecked:false
}
handleCheck = e => {
this.setState({
isChecked:e.target.value
})
}
<input type="checkbox" checked={this.state.isChecked}
onChange={this.handleCheck}/>
表单处理(4多表单元素优化)
每个表单元素都有一个单独的事件处理程序处理太繁琐
使用一个事件处理程序同时处理多个表单元素
多表单元素优化步骤
1、给表单元素添加name属性,名称与state相同
<input type="text" \
name="txt"
value={this.state.txt}
onChange={this.handleForm}/>
2、根据表单元素类型获取对应值
const value = target.type === 'checkbox' ? target.checked : target.value
this.setState({
[name]:value
})
表单处理(5非受控组件)
1、调用React.createRef() 方法创建一个ref对象
constructor(){
super()
this.txtRef = React.createRef()
}
2、将创建好的ref对象添加到文本框中
<input type="text" ref={this.txtRef} />
3、通过ref对象获取到文本框的值
console.log(this.txtRef.current.value)
【案例:取消购物车选中】
【作业:多表单控制】
React组件基础总结
1、组件的两种创建方式:函数组件和类组件
2、无状态(函数)组件,负责静态结构展示
3、有状态 (类) 组件,负责更新UI,让页面动起来
4、绑定事件注意this指向问题
5、推荐使用受控组件来处理表单
6、完全利用JS语言的能力创建组件,这是React的思想
05-React组件基础综合案例(1案例需求分析)
【案例】评论列表
1)渲染评论列表(列表渲染)
2)没有评论数据时渲染:暂无评论(条件渲染)
3)获取评论信息,包括评论人和评论内容(受控组件)
4)发表评论,更新评论列表(setState() )
【作业】表格控制(要求使用bootstrap 控制表单样式)
React组件进阶学习目标
06-组件通讯介绍
组件
是独立且封闭的单元,默认情况下,只能使用组件自己的数据。在组件化过程中,我们将个完整的功能拆分成多个组件,以更好的完成整个应用的功能。而在这个过程中,多个组件之间不可避免的要共享某些数据。为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通讯
。
组件的props(1基本使用)
-
组件是封闭的,要接收外部数据应该通过props来实现
-
props的作用:接收传递给组件的数据
-
传递数据:给组件标签添加属性
-
接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据
<Hello name="jack" age={19} />
function Hello(props){
console.log(props)
return (
<div>接收到数据:{props.name}</div>
)
}
class Hello extends React.Component{
render(){
return (
<div>接收到的数据:{this.props.name}</div>
)
}
}
组件的props(2特点)
1、可以给组件传递任意类型的数据 (除了常见的数值、字符串、数组之外,还可以传递函数和标记等等)
2、props是只读的对象,只能读取属性的值,无法修改对象
(注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props)
组件通讯的三种方式(1父组件传递数据给子组件)
1、父组件提供要传递的state数据
2、给子组件标签添加属性,值为state中的数据
3、子组件中通过props接收父组件中传递的数据
class Parent extends React.Component{
state = { name:'zhangsan' }
render(){
return (
<div>
传递给子组件:<Child name={this.state.name} />
</div>
)
}
}
function Child(props){
return <div>子组件接收到数据:{props.name}</div>
}
组件通讯的三种方式(2子组件传递数据给父组件)
1、附件提供一个回调函数(用于接收数据)
2、将该函数作为属性的值,传递给子组件
3、子组件通过props调用回调函数
class Parent extends React.Commponent{
getChildMsg = msg =>{
console.log('接收到子组件数据',msg)
}
render(){
return (
<div>
子组件:<Child getMsg={this.getChildMsg} />
</div>
)
}
}
class Child extends React.Component {
state = { childMsg: 'React'}
handleClick(){ this.props.getMsg(this.childMsg) }
return (<button onClick={this.handleClick}></button>)
}
组件通讯的三种方式(3兄弟组件通讯)
-
将共享状态提升到最近的公共组件中,由公共父组件管理这个状态
-
思想:状态提升
-
公共父组件职责:1、提供共享状态 2、提供操作共享状态的方法
-
要通讯的子组件只需要通过props接收状态或操作状态的方法
【作业:组件封装】
【作业:秒表】
07-Context的基本使用
问题:如果需要Parent层层将数据传递给子组件中的子组件,该如何处理
-
处理方式:使用props一层层往下传递(繁琐)
-
更好的方式:使用Context,实现跨组件传递数据(比如:主题、语言等)
使用步骤:
1、调用React.createContext() 创建Provider (提供数据)和Consumer(消费数据)两个组件。
const {Provider,Consumer} = React.createContext()
2、使用Provider组件作为父节点
<Provider>
<div className="App">
<Child1 />
</div>
</Provider>
3、 设置value属性,表示要传递的数据
<Provider value="blue">
4、调用Consumer 组件接收数据
<Consumer>
{data => <span>data参数表示接收到的数据 -- {data}</span>}
</Consumer>
总结:
-
如果两个组件是远方亲戚(比如,嵌套多层)
-
可以使用Context实现组件通讯
-
Context提供 了两个组件: Provider和ConsumerProvider组件 :用来提供数据
-
Consumer组件 :用来消费数据
08-props深入
props深入(1children属性)
-
children 属性:表示组件标签的子节点。当组件标签由子节点时,props就会有该属性
-
children属性与普通的props一样,值可以时任意值(文本、React元素、组件、甚至是函数)
function Hello(props){
return (
<div>
组件的子节点:{props.children}
</div>
)
}
<Hello>子节点</Hello>
props深入(2props校验)
-
对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据
-
如果传入的数据格式不对,可能会导致组件内部报错
-
关键问题:组件的使用者不知道明确的错误原因
function App(props){
const arr = props.colors
const lis = arr.map((item,index) => <li key={index}>{item.name}</li>)
return (
<ul>{lis}</ul>
)
}
<App colors={19}/>
-
props校验:允许在创建组件的时候,就指定props的类型、格式等
-
作用:捕获使用组件时因为props导致的错误,给出明确的错误提示,添加组件的健壮性。
App.propTypes = {
colors:PropTypes.array
}
使用步骤:
1、安装包prop-types (yarn add prop-types / npm i prop-types)
2、导入prop-types包
3、使用组件名.propTyps = {}
给组件的props添加校验规则
4、校验规则通过PropTypes 对象来指定
import PropTypes from 'prop-types'
function App(props){
return (
<h1>Hi,{props.colors}</h1>
)
}
App.propTypes = {
colors:PropTypes.array
}
props深入(3props校验-约束规则)
约束规则
1、常见类型:array、bool、func、number、object、string
2、React元素类型:element
3、必填项:isRequired
4、特定结构的对象: shape({ })
//常见类型
optionalFunc: PropTypes.func,
// 必选
requiredFunc: PropTypes.func.isRequired,
//特定结构的对象
optionalObjectwithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
})
使用 PropTypes 进行类型检查 – React (reactjs.org)
练习:
添加props校验
属性a的类型:数值(number)
属性fn的类型:函数(func)并且为必填项
属性tag的类型:React元素(element )
属性filter的类型:对象({area:‘上海’,price: 1999})
App.propTypes = {
a: PropTypes.number,
fn: PropTypes.func.isRequired ,
tag: PropTypes.element ,
filter: PropTypes.shape({
area: PropTypes.string,
price: PropTypes.number
})
props深入(4props的默认值)
-
场景:分页组件 -> 每页显示条数
-
作用:给props设置默认值,在未传入props时生效
App.defaultProps = {
pageSize : 10
}
09-组件的生命周期
组件的生命周期(1概述)
-
意义:组件的生命周期有助于理解组件的运行方式、完成更复杂的组件功能,分析组件错误原因等
-
组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程
-
生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数。
-
钩子函数的作用:为开发人员在不同阶段操作组件提供了时机。
-
只有类组件才有生命周期
组件的生命周期三个阶段(1创建时)
-
执行时刻:组件创建时(页面加载时)
-
执行顺序:constructor -> render -> componentDidMouunt
钩子函数 | 触发时机 | 作用 |
---|---|---|
constructor | 创建组件时,最先执行 | 1、初始化state 2、为事件处理程序绑定this |
render | 每次组件渲染都会触发 | 渲染UI(注意:不能调用setState()) |
componentDidMount | 组件挂载(完成DOM渲染) | 1、发送网络请求 2、DOM操作 |
组件的生命周期三个阶段(2更新时-1触发时机)
1、有新的props传入
2、setState方法被调用
3、forceUpdate执行
组件的生命周期三个阶段(2更新时-2钩子函数说明)
更新时的执行顺序:render -> componentDidUpdate
钩子函数 | 触发时机 | 作用 |
---|---|---|
render | 每次组件渲染都会触发 | 渲染UI(注意:不能调用setState()) |
componentDidUpdate | 组件更新(完成DOM渲染) | 1、发送网络请求 2、DOM操作 (setState必须放置在if条件中,默认参数preProps) |
组件的生命周期三个阶段(3卸载时)
- 执行时刻:组件从页面中消失
钩子函数 | 触发时机 | 作用 |
---|---|---|
componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作(比如:清理定时器等) |
组件的生命周期三个阶段(4不常用钩子函数介绍)
1、shouldComponentUpdate(组件性能优化)
2、getSnapshotBeforeUpdate
生命周期图示:
时间轴:
10-错误边界
部分 UI 的 JavaScript 错误不应该导致整个应用崩溃,为了解决这个问题,React 16 引入了一个新的概念 —— 错误边界。
错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI
,而并不会渲染那些发生崩溃的子组件树。错误边界可以捕获发生在整个子组件树的渲染期间、生命周期方法以及构造函数中的错误。
其中重要方法是
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
logErrorToMyService(error, errorInfo);
}
11-Fragments
React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。
(主要解决子组件包裹元素的问题)
方式一:
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
方式二:
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
12-Portals
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
ReactDOM.createPortal(child, container)
第一个参数(child
)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。(第一个参数一般情况下是 this.props.children)
第二个参数(container
)是一个 DOM 元素。
Protals的特征实际应用在 弹窗、确认框、警告等窗口设计中
13-Profiler
Profiler
测量一个 React 应用多久渲染一次以及渲染一次的“代价”。
Profiler
能添加在 React 树中的任何地方来测量树中这部分渲染所带来的开销。 它需要两个 prop :一个是 id
(string),一个是当组件树中的组件“提交”更新的时候被React调用的回调函数 onRender
(function)。
分析Navigation组件和它的子代们:
render(
<App>
<Profiler id="Navigation" onRender={callback}>
<Navigation {...props} />
</Profiler>
<Main {...props} />
</App>
);
多个Profiler组件能测量应用中的不同部分
render(
<App>
<Profiler id="Navigation" onRender={callback}>
<Navigation {...props} />
</Profiler>
<Profiler id="Main" onRender={callback}>
<Main {...props} />
</Profiler>
</App>
);
嵌套使用Profiler组件来测量相同一个子树下的不同组件:
render(
<App>
<Profiler id="Panel" onRender={callback}>
<Panel {...props}>
<Profiler id="Content" onRender={callback}>
<Content {...props} />
</Profiler>
<Profiler id="PreviewPane" onRender={callback}>
<PreviewPane {...props} />
</Profiler>
</Panel>
</Profiler>
</App>
);
onRender
回调
function onRenderCallback(
id, // 发生提交的 Profiler 树的 “id”
phase, // "mount" (如果组件树刚加载) 或者 "update" (如果它重渲染了)之一
actualDuration, // 本次更新 committed 花费的渲染时间
baseDuration, // 估计不使用 memoization 的情况下渲染整棵子树需要的时间
startTime, // 本次更新中 React 开始渲染的时间
commitTime, // 本次更新中 React committed 的时间
interactions // 属于本次更新的 interactions 的集合
) {
// 合计或记录渲染时间。。。
}
14-构建 React.js 的UI框架
-
Material-UI
一套实现 Google Material Design 的 React 组件 -
React Desktop
MacOS Sierra 和 Windows 10 的 React UI 组件。 -
Semantic-UI
Semantic-UI 的官方 React 组件 -
Ant-design
一套企业级的前端设计语言和基于 React 的前端框架实现。 -
Blueprint
针对构建复杂、数据密集的 Web 界面的桌面应用进行了最优化。如果你重度依赖移动互动,并且正在寻找 mobile-first 的 UI 工具包,它可能不适合你。 -
React-Bootstrap
React-Bootstrap 是一个可重复使用的前端组件库。你可以通过 Facebook 的 React.js 框架获得 Twitter Bootstrap 的体验,而且有更为清晰的代码 -
React-Toolbox
一组使用 CSS 模块实现 Google Material Design 的 React 组件。 -
Grommet
用于企业应用最先进的 UX 框架。 -
Fabric 用于构建与 Office 和 Office 365 界面相类似的 Web 应用的 React 组件。
-
React-md
一个实现 Material Design 的库。React-md 可以轻松地根据自己的需要进行定制,拥有良好的文档和快速上手的“入门”指南,以及许多常见的 Material 组件。
Material-UI(MUI)使用
安装MUI
npm install @mui/material @emotion/react @emotion/styled
快速使用
import * as React from 'react';
import Button from '@mui/material/Button';
export default function MyApp() {
return (
<div>
<Button variant="contained">Hello World</Button>
</div>
);
}
React-Bootstrap
React进阶
render props和高阶组件概述(1)
render props模式(1思路分析)
render props模式(2使用步骤)
render props模式(3演示Mouse组件的复用)
render props模式(4children代替render属性)
render props模式(5代码优化)
高阶组件(1介绍)
高阶组件(2使用步骤)
高阶组件(3设置displayName)
高阶组件(4传递props)
React组件进阶总结
React原理揭秘学习目标
setState()方法的说明(1更新数据)
setState()方法的说明(2推荐语法)
setState()方法的说明(3第二个参数)
JSX语法的转化过程
组件更新机制
组件性能优化(1减轻state)
组件性能优化(2避免不必要的重新渲染1)
组件性能优化(2避免不必要的重新渲染-随机数案例)
组件性能优化(2避免不必要的重新渲染-随机数案例2)
组件性能优化(3纯组件-基本使用)
组件性能优化(3纯组件-shallow compare)
虚拟DOM和Diff算法
虚拟DOM和Diff算法(代码演示)
React原理揭秘总结
React路由基础学习目标
React路由介绍
路由的基本使用
路由的基本使用(常用组件说明)
路由的执行过程
编程式导航
默认路由
匹配模式(1模糊匹配模式)
匹配模式(2精确匹配)
React路由基础总结