合肥网站维护,电商网站开发参考文献,云主机云服务器,兰溪自适应网站建设特点文章目录 认识JSX语法JSX是什么为什么Rect选择了JSXJSX书写规范JSX注释编写 JSX的基本使用JSX的事件绑定this绑定问题参数传递问题 JSX的条件渲染常见的条件渲染方式 JSX的列表渲染JSX的原理和本质JSX的本质虚拟DOM的创建过程 案例练习 认识JSX语法
// 1. 定义根组件
const el… 文章目录 认识JSX语法JSX是什么为什么Rect选择了JSXJSX书写规范JSX注释编写 JSX的基本使用JSX的事件绑定this绑定问题参数传递问题 JSX的条件渲染常见的条件渲染方式 JSX的列表渲染JSX的原理和本质JSX的本质虚拟DOM的创建过程 案例练习 认识JSX语法
// 1. 定义根组件
const element divHello World/div// 2. 渲染根组件
const root ReactDOM.createRoot(document.querySelector(#root))
root.render(element)上述代码中element变量的声明右侧赋值的标签语法其实就是一段JSX的语法。
它不是一段字符串因为没有使用引号包裹它看起来是一段HTML元素但是我们能在js中直接给一个变量赋值HTML吗其实是不可以的如果我们将type text/babel 去除掉那么就会出现语法错误。
JSX是什么
JSX是一种JavaScript的语法扩展也在很多地方称之为JavaScript XML因为看起来就是一段XML语法它用于描述我们的UI界面并且其完成可以和JavaScript融合在一起使用它不同于Vue中的模块语法不需要专门学习模块语法中的一些指令比如v-if、v-for、v-bind等
为什么Rect选择了JSX
React认为渲染逻辑本质上与其他UI逻辑存在内在耦合。比如UI需要绑定事件button、a原生等等、比如UI中需要展示数据的状态、比如在某些状态发生改变时又需要改变UI它们之间是密不可分的所以React没有将标记分离到不同的文件中而是将它们组合到了一起这个地方就是组件。 JSX书写规范
JSX的顶层只能有一个根元素所以我们很多时候会在外层包裹一个div元素或者Fragment为了方便阅读我们通常在jsx的外层包裹一个小括号()这样可以方便阅读并且jsx可以进行换行书写JSX中的标签可以是单标签也可以是双标签如果是单标签必须以/结尾
return (divdivh2{message}/h2/divdiv哈哈哈/div/div
)JSX注释编写
return (div{/* JSX的注释写法*/}h2{message}/h2/div
)JSX的基本使用 JSX嵌入变量作为子元素 情况一当变量是Number、String、Array类型时可以直接显示情况二当变量是null、undefined、Boolean类型时内容为空 如果希望可以显示null、undefined、Boolean那么需要转成字符串转换的方式有很多比如toString方法、和空字符串拼接、String等方式 情况三Object对象类型不能作为子元素 JSX嵌入表达式 运算表达式三元运算符执行一个函数 JSX绑定属性 比如元素都会有title属性比如img元素会有src属性比如a元素会有href属性比如元素可能需要绑定class比如元素使用内联样式style
JSX的事件绑定
如果原生DOM有一个监听事件我们可以如何操作
方式一获取DOM元素添加监听事件方式二在HTML原生中直接绑定onclick
在React中是如何操作呢
React事件的命名采用小驼峰cameClass而不是纯小写我们需要通过{}传入一个事件处理函数这个函数会在事件发生时被执行
bodydiv idroot/divscript typetext/babel// 类组件class App extends React.Component {// 组件数据constructor() {super()this.state {message: Hello World}}// 组件方法btnClick() {// 内部完成了两件事// 1. 将state中的message值修改掉// 2. 自动重新执行render函数this.setState({message: Hello React})}// 渲染内容render() {// 简单数据// return h2Hello World/h2// 复杂数据return (divh2{this.state.message}/h2button onClick{this.btnClick.bind(this)}修改文本/button/div)}// 为什么这里要bind一下? 因为类中的方法中的this默认指向undefined, 所以要将render函数中的this给方法}// 将组件渲染到界面上const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/body这种数据的数据是定义在当前对象的state中的我们可以通过构造函数中的this.state{定义的数据}然后当我们数据发生变化时我们可以调用this.setState来更新数据并且通知React进行update操作在进行update操作时会重新调用render函数并且使用最新的数据来渲染界面。
this绑定问题
上述代码还存在this绑定问题
在事件执行后我们可能需要获取当前类的对象中相关的属性这个时候需要用到this。
在类中直接定义一个函数并且将这个函数绑定到元素的onClick事件上当前这个函数的this指向是谁呢
默认情况下是undefined因为在正常的DOM操作中监听点击监听函数中的this其实是节点对象比如说button对象但是因为React并不是直接渲染成真实DOM我们所编写的button只是一个语法糖它的本质React的Element对象那么在这里发生监听的时候react在执行函数时并没有绑定this默认情况下就是一个undefined。
我们在绑定的函数中可能想要使用当前对象比如执行this.setState函数就必须拿到当前对象的this我们就需要在传入函数时给这个函数直接绑定this
方案一bind给btnClick显式绑定this
// 写法一
button onClick{this.btnClick.bind(this)}修改文本/button// 写法二
constructor() {super()this.state {message: Hello World}this.btnClick this.btnClick.bind(this)
}方案二使用ES6 class fields 语法方案三事件监听时传入箭头函数推荐
bodydiv idroot/divscript typetext/babel/*this的四种绑定规则1. 默认绑定 独立执行 2. 隐式绑定 作为对象中的方法执行3. 显式绑定 call apply bind4. new绑定*/class App extends React.Component {constructor() {super()this.state {counter: 100}}btn1Click() {console.log(btn1Click)this.setState({ counter: this.state.counter 1 })}// 所有实例都会有btn2Click这个字段将一个箭头函数赋值给btn2Click而箭头函数没有this就会去上层作用域中查找找到的是当前类的作用域的this而this正好指向当前实例btn2Click () {console.log(btn2Click)this.setState({ counter: this.state.counter 1 })}btn3Click () {console.log(btn3Click)this.setState({ counter: this.state.counter 1 })}render() {return (divh2当前计数{this.state.counter}/h2{/*1. this绑定方式一bind绑定*/}button onClick{this.btn1Click.bind(this)}按钮1/button{/*2. this绑定方式二ES6 class fields*/}button onClick{this.btn2Click}按钮2/button{/*3. this绑定方式三直接传入一个箭头函数(重要)*/}button onClick{() this.btn3Click()}按钮3/button{/*怎么做的形成一个隐式绑定this是当前实例btn3Click作为当前实例的方法被调用*/}/div)}}const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/body参数传递问题
情况一获取event对象 很多时候我们需要拿到event对象来做一些事情比如阻止默认行为那么默认情况下event对象有被直接传入函数就可以获取到event对象 情况二获取更多参数 有更多参数时最好的方式就是传入一个箭头函数主动执行的事件函数并且传入相关的其他参数
bodydiv idroot/divscript typetext/babelclass App extends React.Component {constructor() {super()this.state {counter: 100}}btn1Click(event) {console.log(btn1Click, event)}btn2Click(event, name, age) {console.log(btn2Click, event, name, age)}render() {return (divh2当前计数{this.state.counter}/h2{/*1. event参数的传递 */}button onClick{this.btn1Click.bind(this)}按钮1/buttonbutton onClick{(event) this.btn1Click(event)}按钮1/button{/*2. 额外的参数传递*/}button onClick{this.btn2Click.bind(this,)}按钮2/buttonbutton onClick{(event) this.btn1Click(event, zy, 18)}按钮2/button/div)}}const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/body
JSX的条件渲染
某些情况下界面的内容会根据不同的情况显示不同的内容或者决定是否渲染某部分内容
在vue中我们会通过指令来控制比如v-if、v-show在React中所有的条件判断都和普通的JavaScript代码一致
常见的条件渲染方式
方式一条件判断语句适合逻辑较多的情况方式二三元运算符适合逻辑比较简单方式三与运算符适合如果条件成立渲染某一个组件如果条件不成立什么内容也不渲染
bodydiv idroot/divscript typetext/babelclass App extends React.Component {constructor() {super()this.state {isReady: true}}render() {const { isReady } this.statelet showElement nullif (isReady) {showElement h2准备开始比赛吧/h2} else {showElement h2请提前做好准备/h2}return (div{/*1. 方式一根据条件给变量赋值不同的内容*/}div{showElement}/div{/*2. 方式二三元运算符*/}div{isReady ? button开始战斗/button : h3准备/h3}/div{/*3. 方式三逻辑与运算*/}{/*场景当某一个值有可能为undefined时使用进行条件判断*/}div{info div{info.name info.desc}/div}/div/div )}}const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/bodyJSX的列表渲染
真实开发中我们会从服务器请求到大量数据数据会以列表的形式存储
比如歌手、歌曲、排行榜列表的数据比如商品、购物车、评论列表的数据比如好友消息、动态、联系人列表数据
在React中并没有像Vue模块语法中的v-for指令而且需要我们通过JavaScript代码的方式组织数据转成JSX那到底如何展示列表呢在React中展示列表最多的方式就是使用数组的map高阶函数。很多时候我们在展示一个数据之前需要先对它进行一些处理比如过滤掉一些内容filter函数比如截取数组中的一部分内容slice函数。
bodydiv idroot/divscript typetext/babelclass App extends React.Component {constructor() {super()this.state {students: [{ id: 1, name: zy, score: 99 },{ id: 2, name: lgc, score: 88 },{ id: 3, name: mxy, score: 100 },{ id: 4, name: jack, score: 66 },{ id: 5, name: kobe, score: 92 },]}}render() {const { students } this.statereturn (divh2学生列表数据/h2div classNamelist{// 选出成绩大于90分的人students.filter(item item.score 90).map(item {return (div classNameitem key{item.id}h2学号{item.id}/h2h2姓名{item.name}/h2h2分数{item.score}/h2/div)})}/div/div)}}const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/bodyJSX的原理和本质 JSX的本质 实际上jsx仅仅只是React.createElement(component, props, ...children)函数的语法糖所有的jsx最终都会被转换成React.createElement的函数调用 React.createElement需要传递三个参数
参数一type 当前ReactElement的类型如果是标签元素那么就使用字符串表示“div”如果是组件元素那么就直接使用组件的名称 参数二config 所有jsx中的属性都在config中以对象的属性和值的形式存储比如传入className作为元素的class 参数三children 存放在标签中的内容以children数组的方式进行存储如果是多个元素React内部有对它们进行处理 虚拟DOM的创建过程
我们通过React.createElement最终创建出来一个ReactElement对象这个ReactElement对象是什么作用呢React为什么要创建它呢这是因为React利用ReactElement对象组成了一个JavaScript的对象树JavaScript的对象树就是虚拟DOM。
如何查看ReactElement的树结构呢我们可以将之前的就实现返回结果进行打印 jsx-虚拟DOM-真实DOM 案例练习
要求
在界面上以表格的形式显示一些书籍的数据在底部显示书籍的总价格点击或者-可以增加或减少书籍如果为1那么不能继续-点击移除按钮可以将书籍移除当所有书籍移除完毕时显示购物车为空~ !DOCTYPE html
htmlheadmeta charsetUTF-8 /title购物车/title!-- 添加依赖 --script srchttps://unpkg.com/react18/umd/react.development.js/scriptscript srchttps://unpkg.com/react-dom18/umd/react-dom.development.js/script!-- babel --script srchttps://unpkg.com/babel/standalone/babel.min.js/scriptstyletable {border-collapse: collapse;text-align: center;}thead {background-color: #f2f2f2;}td,th {padding: 10px 16px;border: 1px solid black;}/style
/headbodydiv idroot/divscript src./data.js/scriptscript typetext/babelclass App extends React.Component {constructor() {super()this.state {books: books}}format(price) {return Number(price).toFixed(2);}// 方法increment(index) {const newBooks [...this.state.books]newBooks[index].count 1this.setState({ books: newBooks })}decrement(index) {const newBooks [...this.state.books]newBooks[index].count - 1this.setState({ books: newBooks })}removeItem(index) {const newBooks [...this.state.books]newBooks.splice(index, 1)this.setState({ books: newBooks })}render() {const { books } this.state// 计算总价let totalPrice 0for (let i 0; i books.length; i) {totalPrice books[i].count * books[i].price}return (divtabletheadtrth序号/thth书籍名称/thth出版日期/thth价格/thth购买数量/thth操作/th/tr/theadtbody {books.map((item, index) {return (tr key{item.id}td{item.id}/tdtd{item.name}/tdtd{item.data}/tdtd{this.format(item.price)}/tdtdbutton disabled{item.count 1} onClick{() this.decrement(index)}-/button{item.count}button onClick{() this.increment(index)}/button/tdtdbutton onClick{() this.removeItem(index)}移除/button/td/tr)})}/tbody/tableh1总价格{this.format(totalPrice)}/h1/div)}}const container document.getElementById(root);const root ReactDOM.createRoot(container);root.render(App /);/script
/body/html// data.js
const books [{id: 1,name: 《算法导论》,data: 2006-9,price: 85.0,count: 1,},{id: 2,name: 《UNIX编程艺术》,data: 2006-9,price: 59.0,count: 1,},{id: 3,name: 《编程珠玑》,data: 2006-9,price: 39.0,count: 1,},{id: 4,name: 《代码大全》,data: 2006-9,price: 128.0,count: 1,},
];
container); root.render();
// data.js
const books [{id: 1,name: 《算法导论》,data: 2006-9,price: 85.0,count: 1,},{id: 2,name: 《UNIX编程艺术》,data: 2006-9,price: 59.0,count: 1,},{id: 3,name: 《编程珠玑》,data: 2006-9,price: 39.0,count: 1,},{id: 4,name: 《代码大全》,data: 2006-9,price: 128.0,count: 1,},
];