目录
1.createElement()问题
繁琐不简洁。不直观,无法一眼看出所描述的结构。不优雅,用户体验不好。
2.JSX简介
是纯js的语法糖
JSX 是 JavaScript XML(HTML) 的简写,表示在 JavaScript 代码中写 XML(HTML) 格式的代码。( React 的核心内容)React定义的一种类似XML的js扩展语法
作用:
在React中创建HTML结构(页面UI结构)简化创建虚拟DOM
优势:
- 声明式语法更加直观、与HTML结构相同,降低了学习成本、提升开发效率。(采用类似于HTML的语法,降低学习成本,会HTML就会JSX)
- JSX语法更能体现React的声明式特点(描述UI长什么样子)。
- 充分利用JS自身的可编程能力创建HTML结构。
注意:
JSX 并不是标准的 JS 语法,是 JS 的语法扩展,浏览器默认是不识别的,脚手架中内置的 @babel/plugin-transform-react-jsx 包,用来解析该语法。
3.JSX使用步骤
1.使用 JSX 语法创建 react 元素
// 使用 JSX 语法,创建 react 元素:
const title = <h1>Hello JSX</h1>
2.使用 ReactDOM.render() 方法渲染 react 元素到页面中
// 渲染创建好的React元素
ReactDOM.render(title, root)
4.为什么脚手架中可以使用JSX语法
- JSX 不是标准的 ECMAScript 语法,它是 ECMAScript 的语法扩展。
- 需要使用 babel 编译处理后,才能在浏览器环境中使用。
- create-react-app 脚手架中已经默认有该配置,无需手动配置。
- 编译 JSX 语法的包为:@babel/preset-react
5.JSX注意点
1.React元素的属性名使用驼峰命名法
2.特殊属性名:
- 标签中的类选择器不要使用class(避免es6中的class冲突),class -> className
- for -> htmlFor、
- tabindex -> tabIndex 。
3.没有子节点的React元素可以用 /> 结束 。
4.推荐:使用小括号包裹 JSX ,从而避免 JS 中的自动插入分号陷阱。
// 使用小括号包裹 JSX
const dv = (
<div>Helo JSX</div>
)
1.保存后出现格式报错
出现vscode中保存react文件时标签名div自动多一个空格。
禁用插件eslint 禁用beautify,插件存在问题,逐步排查即可。
jsx语法规则
1.修改class样式(class -> className)
<style>
.red {
color: red;
}
</style>
<div id="root"></div>
<script type="text/babel">
const VClass = 'red'
const VDOM = (
<h1>
<span className={VClass}>Hello</span>
</h1>
)
ReactDOM.render(VDOM, document.getElementById('root'))
</script>
2.标签中使用js表达式(需要加上{})
const Span = 'React'
const VDOM =
(
<h1>
1.<span className={VClass}>Hello{Span}</span>
2.<span className={VClass}>Hello{Span + 'nihao'}</span>
</h1>
)
3.内联样式要使用style={{ key: value }}
<span style={{ fontSize: '10px' }}></span>
4.虚拟DOM只能有一个根标签
5.标签必须闭合 (无子节点用/>)
6.关于标签
- 如果是小写字母开头的标签,会作为html标签,去转换为真实DOM,但是如果没有真实的dom标签对应,就会报错。
- 如果是小写字母开头的标签,会作为组件,但是如果没有定义对应的组件,并且引入对应的组件,就会报错。
6.嵌入JS表达式
数据存储在JS。在JSX中使用表达式。
语法:{ JavaScript表达式 }
注意:语法中是单大括号,不是双大括号!
const name = 'Jack'
const dv = (
<div>你好,我叫:{name}</div>
)
const getAge = () => {
return 7
}
const flag = false
{getAge()}
{flag ? 'xx' : 'zz'}
1.注意点:
- 单大括号中可以使用任意的 JavaScript 表达式
- JSX 自身也是 JS 表达式
const h1 = <h1>我是JSX</h1> const dv = ( <div>嵌入表达式:{h1}</div> )
- 注意:JS 中的对象是一个例外,一般只会出现在 style 属性中
//错误演示 <p>{ {a: '6' } }</p>
- 注意:不能在{}中出现语句(比如:if/for 等)
2.可以使用的表达式
- 字符串、数值、布尔值、null、undefined、object( [] / {} )
- 1 + 2、'abc'.split('')、['a', 'b'].join('-')
- fn()
3.特别注意
if 语句/ switch-case 语句/ 变量声明语句,这些叫做语句,不是表达式,不能出现在 {}
中。
7.JSX条件渲染
依据应用的不同状态,可以只渲染对应状态下的部分内容。
- 场景:loading效果
- 条件渲染:根据条件渲染特定的 JSX 结构
- 可以使用if/else或三元运算符或逻辑与运算符来实现
-
作用:根据是否满足条件生成对应的HTML结构,比如Loading效果
const isLoading = false
const loadData = () => {
if/else或三元运算符或逻辑与运算符
}
const title = (
<h1>
条件渲染:
{loadData()}
</h1>
)
1.if/else
const loadData = () => {
if (isLoading) {
return <div>loading...</div>
}
return <div>加载完成</div>
}
2.三元运算符
const loadData = () => {
return isLoading ?(<div>loading...</div>):(<div>加载完成</div>)
}
3.逻辑与运算符
逻辑与&&:如果第一个条件满足,才执行第二个条件
要么展示,要么隐藏,不能决定显示A内容还是B内容
const loadData = () => {
//isLoading满足,则不执行<div>loading</div>
return isLoading && <div>loading</div>
}
案例:
class App extends React.Component {
state = { age: 10, name: 'zz' }
changeAge = () => {
this.setState({
age: this.state.age + 1
})
}
changeName = () => {
this.setState({ name: 'ls' })
}
render () {
let str = ''
// if/else
if (this.state.age >= 19) {
str = "成年"
}
else {
str = '未成年'
}
// 使用if/else渲染整个return
if (this.state.name === 'zz') {
return (
<div >
<h2>{this.state.age}</h2>
{/* 三元运算符 */}
<h2>{this.state.age >= 18 ? '成年' : '未成年'}</h2>
<button onClick={this.changeAge}>改变年龄</button>
<h2>我今年{str}</h2>
<button onClick={this.changeName}>改变名字</button>
</div>
)
} else {
return (
<div>
<h2>请你给出正确的名字</h2>
</div>
)}}}
8.JSX 的列表渲染
{}里面放一个数字,react会自动帮你解析,将这个数组的内容遍历出来放到页面中。
- 如果要渲染一组数据,应该使用数组的 map() 方法(就是for循环)
- 注意:渲染列表时应该添加 key 属性,key 属性的值要保证唯一
- 原则:map() 遍历谁,就给谁添加 key 属性
- 注意:尽量避免使用索引号作为 key
const songs = [{ id: 1, name: 'xx' }, { id: 2, name: 'aa' }, { id: 3, name: 'qq' }] const list = ( <ul> { songs.map(item => ( <li key={item.id}>{item.name}</li> )) } </ul> )
一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用数据中的id来作为元素的key
9.JSX 的样式处理
1.行内样式-style(不推荐,耦合的太紧密了)
<h1 style={{ color: 'red', backgroundColor: 'skyblue' }}>
JSX的样式处理
</h1>
2. 行内样式 - style - 更优写法
const styleObj = {
color:red
}
function App() {
return (
<div className="App">
<div style={ styleObj }>this is a div</div>
</div>
)
}
export default App
3.类名-className(推荐)
// 把样式写在单独的css中,并引入css
import css from '../src/css/index.css'
//添加类名
<h1 className="title" >
JSX的样式处理
</h1>
完整代码:
app.css
.title {
font-size: 30px;
color: blue;
}
app.js
import './app.css'
function App() {
return (
<div className="App">
<div className='title'>this is a div</div>
</div>
)
}
export default App
4.类名 - className - 动态类名控制
import './app.css'
const showTitle = true
function App() {
return (
<div className="App">
<div className={ showTitle ? 'title' : ''}>this is a div</div>
</div>
)
}
export default App
注意点:需要为遍历项添加 key
属性
- key 在 HTML 结构中是看不到的,是 React 内部用来进行性能优化时使用
- key 在当前列表中要唯一的字符串或者数值(String/Number)
- 遍历列表需要一个类型为number/string不可重复的key,提高diff性能
- 如果列表中有像 id 这种的唯一值,就用 id 来作为 key 值
- 如果列表中没有像 id 这种的唯一值,就可以使用 index(下标)来作为 key 值
JSX注意事项
- JSX必须有一个根节点,如果没有根节点,可以使用
<></>
(幽灵节点)替代 - 所有标签必须形成闭合,成对闭合或者自闭合都可以
- JSX中的语法更加贴近JS语法,属性名采用驼峰命名法
class -> className
for -> htmlFor
- JSX支持多行(换行),如果需要换行,需使用
()
包裹,防止bug出现
总结
- JSX 是React 的核心内容。
- JSX 表示在JS代码中写HTML结构,是React声明式的体现。
- 使用 JSX 配合嵌入的 JS 表达式、条件渲染、列表渲染,可以描述任意 UI 结构。
- 推荐使用 className 的方式给JSX添加样式。
- React 完全利用 JS 语言自身的能力来编写UI,而不是造轮子增强 HTML 功 能。
案例:
练习步骤:
1.按照图示,完成 评论数据渲染 tab内容渲染 评论列表点赞和点踩
三个视图渲染
{/* 评论列表 */}
<div className="comment-list">
{this.state.list.map(item => (
<div className="list-item" >
<div className="user-face">
<img className="user-head" src={avatar} alt="" />
</div>
<div className="comment">
<div className="user">作者</div>
<p className="text">留言</p>
<div className="info">
<span className="time">时间</span>
{/* 动态类名控制 */}
<span className="leke liked">
<i className="icon" />
</span>
<span className="hate hated">
<i className="icon" />
</span>
<span className="reply btn-hover">删除</span>
</div>
</div>
</div>
))}
</div>
2.在评论列表comment-list遍历标签list-item
{state.list.map(item=>(
---list-item的内容---
))}
3.在遍历的元素上面加key
<div className="list-item" key={item.id}>
4.渲染名称和评论
<div className="user">{item.author}</div>
<p className="text">{item.comment}</p>
5.时间的格式化
function formatTime (time) {
return `${time.getFullYear()}-${time.getMonth() + 1}-${time.getDate()}`
}
6.不知道用上面方法,可以在console中打
new Date().
7.渲染时间
<span className="time">{formatTime (item.time)}</span>
8.动态类名控制
<span className={item.attitude === 1 ? 'like liked' : 'like'}>
<span className={item.attitude === -1 ? 'hate hated' : 'hate'}>
9.渲染热度和时间排序
{state.tabs.map(item =>
<li key={item.id} className={item.type === state.active ? 'on'
:''}>按{item.name}排序</li>
)}
10.删除(在排序里面)和默认排序的激活状态(是亮时间还是热度)
{this.state.tabs.map(tab =>
(
<li
onClick={() => this.switchTab(tab.type)}
key={tab.id}
className={tab.type === this.state.active ? 'on' : ''}>
按{tab.name}排序
</li>
)
)}
源码在gitee
- gitee为黑马的源码,在此基础上完成自己的代码,并推送到自己的仓库,需要先执行
- git remote rm origin
- 然后再按照gitee要求上传即可
- 如果还是不成功,可以使用git commit -m "first commit",然后再按照gitee要求上传即可