React
用于动态构建用户界面的 JS 库(只关注于视图)
原生JS的缺点
React的特点
虚拟DOM和Diff算法
,尽量复用DOM节点,减少与真实DOM的交互JSX
,代码的可读性更好组件化模式
,提高代码复用率、且让代码更好维护声明式编程
, 让编码人员无需直接操作DOM,提高开发效率命令式编程与声明式编程
命令式编程
:用详细的命令机器怎么去处理一件事情以达到你想要的结果.声明式编程
:你只需要告诉计算机,你要得到什么样的结果,计算机则会完成你想要的结果,以React为例,在页面中通过 { } 显示一个变量,你只需要改变这个变量,页面就会跟着刷新,这就是你只需要结果,React 内部去处理过程,这就是声明式编程重绘与重排
重绘(repaint)
:当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程重排(reflow)
:当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置的过程模块化与组件化
业务逻辑
: 举个例子比如淘宝双12举办活动,那些活动页面的逻辑,什么时候显示,在某些情况下显示什么,在另外一些情况下又该显示什么 ,这就是业务逻辑
传统开发模式的主要问题
:命名冲突、文件依赖, 通过模块化
可解决上述问题
模块
: 一个JS文件
就是一个模块,模块内部定义的变量和函数默认情况下在外部无法得到
模块化
:从业务逻辑角度或功能需要角度划分的,按照项目功能需求划分成不同类型的业务框架(例如:注册、登录、外卖、直播…) ,目的: 隔离、分装
把单独的一个功能封装到一个模块(js文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块
优点
: 方便代码的重用,从而提升开发效率,并且方便后期的维护
传统方式编写应用的问题
:依赖关系混乱、代码复用率不高, 通过组件化
可解决上述问题
组件
: 可复用的 Vue/React 实例组件化
: 从UI界面角度或复用的角度划分的,页面上每个独立的区域都可以看做是一个组件,目的:复用、解耦最大区别
:划分角度不同,都是便于项目的维护和开发。模块化是对功能的拆分,模块化并没有要求一定组件化,就是说进行模块化拆分时你可以完全不考虑代码重用,只是把同一业务的代码做内聚整合成不同的模块
虚拟DOM
虚拟DOM
是JS按DOM(真实DOM)的结构来创建的虚拟树型结构对象,是对DOM的抽象,比DOM更加轻量型(属性更少),本质还是Object类型的对象,虚拟DOM最终会被React转化为真实DOM,呈现在页面上。
react.js
:React核心库。
react-dom.js
:提供操作DOM的React扩展库。
babel.min.js
:解析JSX语法代码转为JS代码的库。
type="text/babel"
, 声明需要babel来处理JS 创建虚拟 DOM(一般不用)
<script type="text/JS" >
//1.创建虚拟DOM,创建嵌套格式的dom
const VDOM=React.createElement('h1',{id:'title'},React.createElement('span',{},'hello,React'))
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.querySelector('.test'))
</script>
JSX 创建虚拟DOM
//1.创建虚拟DOM
script type="text/babel" > /* 此处一定要写babel */
const VDOM = ( /* 此处一定不要写引号,因为不是字符串 */
<h1 id="title">
<span>Hello,React</span>
</h1>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.querySelector('.test'))
</script>
虚拟DOM的渲染
语法
:
//virtualDOM为虚拟dom containerDOM用来包裹虚拟DOM的真实dom对象
ReactDOM.render(virtualDOM, containerDOM)
作用
: 将虚拟DOM渲染为真实DOM,然后在页面中显示
代码总览
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<body>
<!-- 真实DOM对象 根节点-->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/JS" src="../js/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/JS" src="../js/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/JS" src="../js/babel.min.js"></script>
<script type="text/babel"> /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM = <h1>Hello,React</h1> /* 此处一定不要写引号,因为不是字符串 */
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
JSX(JS XML)
是一种类似于XML的JS扩展语法,用来简化创建虚拟DOM, 在React中可以方便地用来描述UI(用户界面) 。 JSX为我们提供了创建React元素方法(React.createElement(component, props, ...children)
)的语法糖
(简写形式)
写法:
import React from 'react';
//JSX不是字符串, 也不是HTML/XML标签,最终产生的就是一个JS对象
var ele = <h1>Hello, JSX!</h1>
// 等价于
var element = React.createElement(
"h1",
null,
"Hello, world!"
);
注:
定义虚拟DOM时,不要写引号。只有一个根标签且每个标签必须闭合
JSX 语法有时需要小括号( )
包裹,避免遇到js自动插入分号的陷阱
内联样式
,要用 style={{ key:value }}
的形式去写。 React 提倡的是组件思想,万物皆是 JS 控制(用 JS 来写 HTML 和 CSS)。以组件为维度,把 HTML、CSS、JS 混合在一起。React 会自动添加 ”px” 后缀到内联样式为数字的属性后。如需使用 ”px” 以外的单位,请将此值设为数字与所需单位组成的字符串
style={{
marginBottom: 40,//或'40px' 有px需要加' '
width: 590,
height: 590,
display: 'flex',
float: 'left',
justifyContent: 'flex-end'
}}
JSX本身也是一个表达式
,在编译后,JSX表达式会变成普通的JS对象(Object)。
你可以在if语句或for循环中使用JSX,你可以将它赋值给变量,你可以将它作为参数接收,你也可以在函数中返回JSX。
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
//上面的代码在if语句中使用JSX,并将JSX作为函数返回值。实际上,这些JSX经过编译后都会变成JS对象。经过babel会变成下面的js代码:
function test(user) {
if (user) {
return React.createElement(
"h1",
null,
"Hello, ",
formatStr(user),
"!"
);
}
return React.createElement(
"h1",
null,
"Hello, Stranger."
);
}
在 JSX 语法中,你可以在{ }
内放置任何有效的JS表达式
, 例如,2 + 2
,user.firstName
或 formatName(user)
都是有效的 JS 表达式。
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
但if语句以及for循环不是JS表达式
,不能直接作为表达式写在{ }中,可以先将其赋值给一个变量(变量是一个JS表达式):
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
}
JSX还可自动防范注入攻击,在JSX中嵌入接收到的内容是安全的,在默认情况下,React DOM会将所有嵌入JSX的值进行编码。这样可以有效避免xss攻击。比如:
const danger = response.potentialDanger;
cosnt ele = <h1>{title}</h1>
相关补充 :js表达式与js语句
js表达式
:一个表达式会产生一个值,可以放在任何一个需要值的地方
判断方法
:在它们左边定义一个变量 const x =xxx 若有返回值就是表达式
下面这些都是表达式:
js语句
: 语句可以理解为一个行为,循环语句和判断语句就是典型的语句。下面这些都是语句:
可以使用引号
将字符串字面量
指定为属性值或者可以将一个JS表达式
嵌在一个大括号{ }
中作为属性值:
//”0”是一个字符串字面量
const element = <div tabIndex="0"></div>
const element = <img src={user.avatarUrl}></img>;
//这里用到的是JS属性访问表达式,上面的代码将编译为:
const element = React.createElement("img", { src: user.avatarUrl });
一个标签里面没有内容,你可以使用 />
来闭合标签 , JSX 标签里能够包含很多子元素 Children
const element = (
<div>
<h1>Hello!</h1>
<img src={user.avatarUrl} />
</div>
);
标签属性名使用驼峰命名法camelCase
, class== > className;,for== >Htmlfor , tabindex== >tabIndex
const element = <div className='demo'></div>
每个组件都是一个对象,props是对象的一个属性,组件对象可以通过props传递
指定JSX中的props有以下几种方式:
使用JS表达式
,任何有效的JS表达式
都可以作为props的值
,使用的时候将该表达式放在一对大括号{ }
中即可
<MyComponent foo={1 + 2 + 3 + 4} />
<YourComponent clickTodo={(id) => this.props.handleClick(id)} />
字符串字面量可以作为prop值
<MyComponent message="hello world" />
// 等价于
<MyComponent message={'hello world'} />
使用扩展运算符
, 你想将一个prop对象传入JSX,你可以使用扩展运算符...
直接将整个prop对象传入
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
// 等价于
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
React组件中有一个特殊的prop–props.children
。它指代了JSX表达式中标签体内容。
指定 JSX中的props.children 有以下几种方式:
使用字符串字面量
, 在JSX标签体中写入字符串字面量,组件得到的props.children就是该字符串值
//MyComponent的props.chilren获得”Hello World!”字符串
<MyComponent>Hello world!</MyComponent>
JSX元素作为children
, 我们同样可以使用JSX元素作为JSX的children,由此生成嵌套组件 , 也可以混合使用字符串字面量和JSX作为children :
<MyContainer>
Here is a list:
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
JS表达式
, 和props一样,你也可以将任何有效的JS表达式作为children传入,将它放在{ }中就可以了。
<MyComponent>{a+b}</MyComponent>
函数children
, 传入自定义组件的children并没有严格的限制,只要在React需要render的时候能将它们转换成可以render的东西就行了
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
//作为一个prop传入
{(index) => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
}
布尔值、Null以及Undefined
, 布尔值,Null以及Undefined可以作为有效的children,但他们不会被render
<div>
// 只有在showHeader为true时才会render
{showHeader && <Header />}
<Content />
</div>
遇到 <
开头的代码, 观察标签首字母: