React(二) JSX中的this绑定问题;事件对象参数传递;条件渲染;列表渲染;JSX本质;购物车案例

news2024/11/29 20:49:16

文章目录

  • 一、jsx事件绑定
    • 1. 回顾this的绑定方式
    • 2. jsx中的this绑定问题
      • (1) 方式一:bind绑定
      • (2) 方式二:使用 ES6 class fields 语法
      • (3) 方式三:直接传入一个箭头函数(重要)
    • 3.事件参数传递
      • (1) 传递事件对象event
      • (2) 传递其他参数
    • 4. 事件绑定小案例
  • 二、条件渲染
    • 1. if-else、三元运算符,逻辑与&&
    • 2. 模拟v-show的效果
  • 三、列表渲染
  • 四、JSX的本质
    • 1. babel转译JSX
    • 2. 虚拟DOM到真实DOM
  • 五、购物车案例
    • 1. 总价格与格式化
    • 2. 商品数量+和-的操作
    • 3. 删除
    • 4. 无数据时给提示

一、jsx事件绑定

1. 回顾this的绑定方式

(绑定方式就是指this值的几种指向)

  • 默认绑定。 函数独立执行 fun()—此时this指向window
  • 隐式绑定。被一个对象调用指向 obj.foo()—此时this指向obj
  • 显示绑定。通过call/apply/bind明确规定this的指向 — foo.call('aaa')
  • new绑定。 new Foo()—> 创建一个实例,this指向实例

仔细看下边这段代码,分析两次函数调用分别打印什么值

 const obj = {
   name: "obj",
   foo: function () {
     console.log("foo:", this)
   }
 }
 obj.foo() // obj

 const config = {
   onClick: obj.foo
 }
 const click = config.onClick //这句话实际是click = obj.foo
 click()  // 等价于foo(), 独立执行,指向window(严格模式值为undefined)

若修改为

 const config = {
   onClick: obj.foo.bind(obj)
 }
 const click = config.onClick //这句话实际是click = obj.foo
 click()  // 等价于obj.foo(), 打印出来的this指向obj

在这里插入图片描述

2. jsx中的this绑定问题

 如之前所说,在这个类组件中,事件的处理函数需要对数据进行处理;
 在严格模式下,构造函数与render里的this指向实例对象,而类里的方法中的this值为undefinedundefined.setState会报错,所以需要处理this绑定问题
在这里插入图片描述

(1) 方式一:bind绑定

   constructor() {
     super()
     this.state = {
       number: 0
     }
     // bind改变btnClick1 方法里this的指向
     this.btnClick1 = this.btnClick1.bind(this)
   }
   
   btnClick1 () {
     console.log('btn1', this);
     this.setState({
       number: this.state.number + 1
     })
   }
   render(){
    ...
     <button onClick={this.btnClick1}>+1</button>
    ...
   }

(2) 方式二:使用 ES6 class fields 语法

es6中,在类里可以省略constructor,直接给变量赋值,这就是class fileds。

 class App extends React.Component {
    ...
   // 给变量btn2Click 赋值一个箭头函数
   btn2Click = () => {
     console.log("btn2Click", this)
     this.setState({ number: 1000 })
   }
   render () {
     return (
       <div>
         {/* 2.this绑定方式二: ES6 class fields */}
         <button onClick={this.btn2Click}>按钮2</button>
       </div>
     )
   }
 }

当调用箭头函数时,箭头函数没有自己的this,会向上层作用域查找,而上层作用域是类的作用域(App类),指向的则会是类的实例。

(3) 方式三:直接传入一个箭头函数(重要)

 class App extends React.Component {
    ...
   // 给变量btn2Click 赋值一个箭头函数
   btn3Click = () => {
   // 隐式绑定后,这里的this就是render函数里的this,就是当前对象实例
     console.log("btn3Click", this) 
     this.setState({ number: 666})
   }
   render () {
     return (
       <div>
         {/* 3.this绑定方式三: 直接传入一个箭头函数 */}
          <button onClick={() => this.btn3Click()}>按钮3</button>
       </div>
     )
   }
 }

当点击按钮时,onClick被触发,执行箭头函数。而在代码逻辑在btn3Click里,所以箭头函数调用了btn3Click,而在调用btn3Click时,是this在调用,也就是一个对象调用了btn3Click,即进行了隐式绑定。

3.事件参数传递

(1) 传递事件对象event

   btnClick (event) {
     console.log("btnClick:", event, this)
   }
   render () {
     return (
       <div>
         {/*默认参数传递*/}
         <button onClick={this.btnClick}>按钮1</button>
         <button onClick={this.btnClick.bind(this)}>按钮2</button>
         <button onClick={() => this.btnClick()}>按钮3</button>
         <button onClick={(event) => this.btnClick(event)}>按钮4</button>
       </div>
     )
   }

点击按钮1:默认传递了事件对象event,this是undefined
点击按钮2:默认传递了事件对象event,this是组件实例
点击按钮3:调用了btnClick函数,什么参数也没传。所以event是undefined;this是组件实例。
点击按钮4:传递了事件对象,所以event和this都有值

(2) 传递其他参数

在传递了事件对象的基础上,再传递其他参数

btnClick (event, name, age) {
	console.log("btnClick:", event, this)
	console.log("name,age:", name, age)
}
...
<button onClick={(event) => this.btnClick(event, 'tom', 18)}>按钮5</button>

在这里插入图片描述

4. 事件绑定小案例

二、条件渲染

vue中是通过指令来控制:比如v-if、v-show;
在React中,所有的条件判断都和普通的JavaScript代码一致

1. if-else、三元运算符,逻辑与&&

  • if-else:条件判断语句,适合逻辑较多的情况
  • 三元运算符:适合逻辑简单的情况
  • 与运算符&&:适合于条件成立,则渲染组件;条件不成立,则什么也不渲染
 this.state = {
   isReady: true,
   friend: {
     name: 'tom',
     desc: '很棒!'
   }
 }
render () {
  const { isReady, friend } = this.state
  let showEle = null
    // 采用if判断是否生成页面内容
  if (isReady) {
    showEle = <h2>准备开始比赛! </h2>
  } else {
    showEle = <h2>请提前做好准备</h2>
  }

  return (
    <div>
      {/* 1.方式一: 根据条件给变量赋值不同的内容*/}
      {showEle}
      {/* 2.方式二: 三元运算符*/}
      {isReady ? <button>点击开始战斗</button> : <h2>赶紧准备!</h2>}
      {/* 3.方式三: &&逻辑运算,friend为空则不显示,有值则显示*/}
      {friend && <h2>{friend.name + ':' + friend.desc}</h2>}
    </div>
  )
}

在这里插入图片描述

2. 模拟v-show的效果

控制display属性是否为none;
需求:点击按钮,实现文字的隐藏与显示

  btnClick () {
    this.setState({
      isShow: !this.state.isShow
    })
  }
  render () {
    const { msg, isShow } = this.state
    return (
      <div>
        <button onClick={() => this.btnClick()}>切换</button>
         {/*逻辑与&&*/}
        {isShow && <h2>{msg}</h2>}
        {/*v-show的效果*/}
        <h2 style={{ display: isShow ? 'block' : 'none' }}>{msg}</h2>
      </div >
    )
  }

采用了两种实现方式,加深一下对逻辑与&&的运用

三、列表渲染

React中没有像Vue模块语法中的v-for指令,React渲染列表就是采用JS里的一些方法对列表进行遍历或其他处理。
◼ 如何展示列表呢?
   在React中,展示列表最多的方式就是使用数组的map高阶函数
◼ 很多时候我们在展示一个数组中的数据之前,需要先对它进行一些处理:
   比如过滤掉一些内容:filter函数
   比如截取数组中的一部分内容:slice函数

注意:这里要注意map中这个返回标签的话,返回的东西要和return写在一行(比如这个括号),不然默认就return跳出去了,什么也不会渲染。(其他博主踩的坑)

案例:展示学生信息。

// 数据
   students: [
     { id: 111, name: "why", score: 199 },
     { id: 112, name: "kobe", score: 98 },
     { id: 113, name: "james", score: 199 },
     { id: 114, name: "curry", score: 188 },
   ]

map函数展示

  render () {
    const { students } = this.state
    return (
      <div>
        {
          students.map((item) => {
            return (
              <div className="item" key={item.id}>
                <h2>学号: {item.id}</h2>
                <h3>姓名: {item.name}</h3>
                <h1>分数: {item.score}</h1>
              </div>
            )
          })
        }
      </div>
    )
  }

展示分数大于100的学生:filter

render () {
   ...
  const filterStus = students.filter((item) => item.score > 100)
  return (
   ...
    filterStus.map((item) => {
      return (
        <div className="item" key={item.id}>
         ...
        </div>
      )
    })
    ...
  )
}

展示分数大于100的前两位学生:slice

  return (
    <div>
      {
        filterStus.slice(0, 2).map((item) => {
          return (
            <div className="item" key={item.id}>
              <h2>学号: {item.id}</h2>
              <h3>姓名: {item.name}</h3>
              <h1>分数: {item.score}</h1>
            </div>
          )
        })
      }
    </div>
  )

其中key的唯一标识和vue中原理差不多。

四、JSX的本质

Jsx的本质是 React.createElement(type, config, ...children) 函数的语法糖。所有的jsx最终都会被转换成React.createElement的函数调用。

先看这个函数的参数:

  • 参数一:type
    当前ReactElement的类型;
    如果是标签元素,那么就使用字符串表示 “div”;
    如果是组件元素,那么就直接使用组件的名称;
  • 参数二:config
    所有jsx中的属性都在config中以对象的属性和值的形式存储;
    比如传入className作为元素的class;
  • 参数三:children
    存放在标签中的内容,以children数组的方式进行存储;

1. babel转译JSX

babel将JSX语句转换成React.createElement的函数,这个函数会创建element,element最终会形成元素树。每个元素就是虚拟DOM。

比如render函数里有这样一段JSX代码

<div>
    <h2>{count}</h2>
    <ul className='active'>
        <li>我是li1</li>
        <li>我是li2</li>
        <li>我是li3</li>
    </ul>
    <button>按钮</button>
</div>

经babel转译,得到原生的React:

<script>
    /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/
    React.createElement("h2", null, count),
    
     /*#__PURE__*/React.createElement("ul", {className: "active"},
      /*#__PURE__*/React.createElement("li", null, "\u6211\u662Fli1"),
       /*#__PURE__*/React.createElement("li", null, "\u6211\u662Fli2")),

     /*#__PURE__*/React.createElement("button", null, "\u6309\u94AE"));
</script>

(因为版本问题,我自己没有转换成这样的原生React,原因见博客:jsx的转换)
不用babel的话,需要写原生的React(React.createElement)来展示页面内容;所以JSX能够方便开发,是个语法糖,其本质就是在调用React.createElement

2. 虚拟DOM到真实DOM

(1) 、虚拟DOM的创建
  React.createElement最终创建出来一个个ReactElement对象,这些对象则组成了一个JavaScript的对象树,而这个对象树就是虚拟DOM

查看ReactElement树结构(这就是虚拟DOM):
在这里插入图片描述
(2) 、虚拟DOM到真实DOM
流程是:
编写JSX代码
---------->经过babel转译,转成React.createElement函数的调用
--------->该函数调用生成ReactElement对象,形成虚拟DOM
--------->虚拟DOM经过渲染生成真实DOM,这个渲染的过程就是React做的。

(3) 、虚拟DOM的作用

主要的作用:

  • 当更新数据时,不用将所有DOM重新渲染;新旧虚拟DOM对比,来快速决定哪些东西更新,哪些东西不用更新。

  • 做跨平台应用程序。虚拟DOM的本质就是JS对象,下一步是要渲染到页面上,

    • React可以将其渲染到Web应用的界面上(就是调用原生的document.createElement),将按钮渲染成网页的按钮button等。
    • 也可以将其渲染到IOS/Android端,渲染成IOS/Android控件,将按钮渲染成移动端的UIButton控件。
  • 虚拟DOM帮助我们从命令式编程转到了声明式编程的模式。
    你只需要告诉React希望让UI是什么状态; React来确保DOM和这些状态是匹配的;(也就是 你不需要直接进行DOM操作,不需要手动渲染。只需要写好状态(state的数据),写好页面结构即可。更改DOM,渲染的事交给React。)

五、购物车案例

实现以下这个页面及功能:
在这里插入图片描述

  <script src="./data.js"></script>
  <div id="root"></div>
  <script type="text/babel">

    // 1. 定义类组件
    class App extends React.Component {
      // 1.1 构造函数
      constructor() {
        super()
        this.state = {
          books: books
        }
      }
      render () {
        const { books } = this.state
        return (
          <div>
            <table>
              <thead>
                <tr>
                  <th>序号</th>
                  <th>书籍名称</th>
                  <th>出版日期</th>
                  <th>价格</th>
                  <th>购买数量</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>
                {books.map((item, index) => {
                  return (
                    <tr key={index}>
                      <td>{index + 1}</td>
                      <td>{item.name}</td>
                      <td>{item.date}</td>
                      <td>{item.price}</td>
                      <td>
                        <button disabled>-</button>
                        {item.count}
                        <button>+</button>
                      </td>
                      <td><button>删除</button></td>
                    </tr>
                  )
                })}
              </tbody>
            </table>
            <h2>总价格:¥311</h2>
          </div>
        )
      }
    }

    // 2. 渲染类组件
    const root = ReactDOM.createRoot(document.querySelector('#root'))
    root.render(<App />)

  </script>

data.js里的数据为

const books = [
  {
    id: 1,
    name: '《算法导论》',
    date: '2006-9',
    price: 85.00,
    count: 1
  },
  {
    id: 2,
    name: '《UNIX编程艺术》',
    date: '2006-2',
    price: 59.00,
    count: 1
  }
  ...
]

1. 总价格与格式化

(1)计算总价格:每本书的单价*数量,相加
方式一:for循环遍历计算
方式二:reduce函数

// 封装为函数
 getTotalPrice () {
   let totalPrice = this.state.books.reduce((preValue, current) => {
     return preValue + current.count * current.price
   }, 0)
   return totalPrice
 }

(2)格式化
表格里显示价格的地方,格式都是¥xxx.xx,因此可写个函数格式化

function formatPrice (price) {
  // toFixed,保留两位小数
  return '¥' + Number(price).toFixed(2)
}
// 应用:
//表格中价格一列
<td>{formatPrice(item.price)}</td>
//总价格
<h2>总价格:{formatPrice(this.getTotalPrice())}</h2>

2. 商品数量+和-的操作

  // 加
  increment (index) {
    const newBooks = [...this.state.books]
    newBooks[index].count += 1
    this.setState({ books: newBooks })
  }
  // 减
  decrement (index) {
    const newBooks = [...this.state.books]
    newBooks[index].count += -1
    this.setState({ books: newBooks })
  }

可以看出,这两个操作十分相似,唯一的区别是对count的操作数不一样。所以可以进一步封装。
   我们不能直接去修改state中的数据,我们要借助调用setState这个方法去修改,从而可以执行render函数更新页面。
  React官方推荐的做法是使用一个新的变量浅拷贝原来的数据,然后修改结束之后把新的浅拷贝赋值给state中数据

 // 商品数量变化,count为+1或-1
 changeCount (index, count) {
   const newBooks = [...this.state.books]
   newBooks[index].count += count
   this.setState({
     books: newBooks
   })
 }

需要注意当数量小于或等于1时,减号按钮应该禁用。
在这里插入图片描述

3. 删除

数组中删除数据,用到splice函数

  // 处理删除
  removeItem (index) {
    const newBooks = [...this.state.books]
    // 删除数据
    newBooks.splice(index, 1)
    this.setState({ books: newBooks })
  }
 // 页面
<td><button onClick={() => this.removeItem(index)}>删除</button></td>

4. 无数据时给提示

考虑到条件渲染,当有数据时展示表格,无数据时隐藏表格。可将有数据与无数据时的页面结构封装到不同的函数里。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DeepBook V3和DEEP token正式上线

10月14日&#xff0c;DeepBook V3版本正式在主网上线&#xff0c;同时发布了DEEP token&#xff0c;标志着其发展历程中的一个重要里程碑。通过这次升级&#xff0c;用户和做市商将受益于精细调控的激励措施&#xff0c;为通过社区驱动的治理实现更大的去中心化奠定了基础。 D…

【大模型问答测试】大模型问答测试脚本实现(第一版)

背景 公司已经做了一段时间的大模型&#xff0c;每次测试或者回归的时候都需要针对问答进行测试回归&#xff0c;耗费大量的时间与精力&#xff0c;因此结合产品特点&#xff0c;开发自动化脚本替代人工的操作&#xff0c;提升测试回归效率 设计 使用pythonrequestExcel进行…

python+大数据+基于Spark的共享单车数据存储系统【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

【jQuery】 jQuery基础及选择器介绍(基本选择器 层次选择器 属性选择器 过滤选择器)

文章目录 jQuery基础1. 优势2. 版本3. 基本语法4. 选择器基本选择器层次选择器属性选择器过滤选择器基本过滤选择器可见性过滤选择器 注意事项 jQuery基础 jQuery 是一个功能强大且易于使用的 JavaScript 库&#xff0c;它极大地简化了前端开发的工作。无论是 DOM 操作、事件处…

简单概述Ton链开发路径

区块链开发领域发展迅速&#xff0c;各种平台为开发人员提供不同的生态系统。其中一个更有趣且越来越相关的区块链是TON&#xff08;开放网络&#xff09;区块链。TON 区块链最初由 Telegram 构思&#xff0c;旨在提供快速、安全且可扩展的去中心化应用程序 (dApp)。凭借其独特…

加盟模式如何运营?有哪些好的技巧和方法!

对于很多品牌方来说&#xff0c;生意发展到一定程度&#xff0c;就考虑通过加盟的方式扩大市场份额。 本篇文章&#xff0c;将从3个角度来为大家分享&#xff0c;运营加盟模式的好方法和技巧&#xff01; 一、加盟前的准备 1、明确品牌定位与核心竞争力 确定你的企业在市场…

暖水毯/取暖毯语音识别控制芯片IC方案

暖水毯、取暖毯作为现代家居生活的温暖伴侣&#xff0c;其智能化升级已是大势所趋。在暖水毯与取暖毯中融入语音识别控制芯片IC方案&#xff0c;为用户的冬日取暖体验带来了革命性的变革。 一、暖水毯/取暖毯增加语音识别控制芯片方案&#xff0c;让产品能通过对话来调节&…

【笔记】vue课堂小作业之书籍购物车列表的增删改查小记

&#xff08;一&#xff09;reduce作迭代器 1. reduce 函数的基本用法 array.reduce((accumulator, currentValue) > { ... }, initialValue); accumulator: 累积器&#xff0c;表示当前累积的值&#xff0c;通常在第一次时为 initialValue。&#xff08;总数sum&#x…

OpenCV高级图形用户界面(8)在指定的窗口中显示一幅图像函数imshow()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在指定的窗口中显示一幅图像。 函数 imshow 在指定的窗口中显示一幅图像。如果窗口是以 cv::WINDOW_AUTOSIZE 标志创建的&#xff0c;图像将以原…

遵循国药准字,确保益安宁丸疗效与安全

益安宁丸真品辨别唯一标准 益安宁丸为同溢堂药业有限公司所独家生产的一款中成药&#xff0c;在内地市场和港澳地区均有上市。 益安宁丸真品的唯一标准&#xff1a;无论港版还是内地版&#xff0c;包装盒必然有国药准字Z20063087标识&#xff0c;但凡没有国药准字标识的必为假…

性价比最高的开放式耳机,五大热门品牌开放式耳机

在当今快节奏的生活环境中&#xff0c;开放式耳机以其独特的开放式设计&#xff0c;既能让用户享受高质量的音乐&#xff0c;又能保持对外界环境的感知&#xff0c;逐渐成为市场上的新宠。然而&#xff0c;面对众多品牌和型号&#xff0c;如何选择一款性价比高的开放式耳机成为…

IDEA 编译报错 “java: 常量字符串过长” 的解决办法

目录 一、问题描述二、问题原因2.1 理论角度2.2 源码角度 三、解决方案解决方案①&#xff1a;StringBuilder 拼接解决方案②&#xff1a;读取文件内容 四、方案验证 在线文本换行工具&#xff1a; https://lzltool.cn/Toolkit/WrapWordsInText 一、问题描述 今天在开发过程中…

JavaScript全面指南(五)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;JavaScript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript全面指南 目录 81、ES6 class关键字原理跟function什么区别 82、如何检…

Vue(3) 组件

文章目录 对组件的理解单文件组件非单文件组件基本使用几个注意点组件的嵌套VueComponent构造函数一个重要的内置关系 组件的自定义事件全局事件总线安装全局事件总线使用事件总线解绑事件消息订阅与发布简介使用步骤范例 $nextTick插槽1.默认插槽2.具名插槽作用域插槽 对组件的…

某市驾驶培训监管服务平台 GreatSQL 数据库适配之旅

某市驾驶培训监管服务平台 GreatSQL 数据库适配之旅 一、项目背景 某市驾培系统主要为社会公众提供驾培单位查询和学车报名&#xff0c;为相关合作单位提供某市驾培监管、某市驾培考核等功能。业务信息教练车培训过程视频信息、包括培训机构基本信息、教练员基本信息和学员个…

从零创建苹果App应用,不知道怎么申请证书的可以先去看我的上一篇文章

用大家自己的开发者账户&#xff0c;登录进入App Store Connect ,注册自己的应用 进入之后&#xff0c;点击增加 填写相关的信息 一切顺利的话&#xff0c;就可以来到这个页面

【Java】画心形图形

开始看到的是这个爱心图形&#xff0c;挺好看的&#xff08;感谢这些前端巨佬&#xff09;&#xff1a; HTML流光爱心_爱心代码html-CSDN博客 本来想着自己看下这个源代码能不能实现&#xff0c;看了下源代码其实非常复杂。 在看代码的过程中发现&#xff0c;源代码里边给出…

5: Euclid‘s Game

题意分析&#xff1a;给定数列&#xff08;A,B&#xff09;&#xff08;A>B&#xff09;&#xff0c;任取两数之差&#xff0c;若不含于数列&#xff08;A,B&#xff09;则添加得&#xff08;A.B,C&#xff09;重复任取两数之差且不重复得&#xff08;A,B,C,...&#xff09;…

【汇编语言】寄存器(内存访问)(二)—— DS和[address]

前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构、操作系统、微机原理&#xff09;的重要基础。但仅仅从课程的角度出发就太片面了&#xff0c;其实学习汇编语言可以深入理解计算机底层工作原理&#xff0c;提升代码效率&#xff0c;尤其在嵌入式系统和性能优…

微信外卖小程序(lw+演示+源码+运行)

摘 要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。手机具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;成本低等优点。 因此&#xff0c;构建符合自己要求的操作…