- React学习笔记
最近开始接触react,本文是自己学习过程中做的一点学习笔记,如有错误欢迎指出哈哈哈 1、hello React babel.js 的作用 (1) 浏览器不能直接解析 JSX 代码, 需要 babel 转译为纯 JS 的代码才能运行 (2) 只要用了 JSX,都要加上 type=“text/babel”, 声明需要 babel 来处理 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 准备好一个容器 --> <div id="test"></div> <!-- react核心库 --> <script src="../../js//react.development.js"></script> <!-- 用于支持react支持dom操作 --> <script src="../../js//react-dom.development.js"></script> <!-- 引入babel,用于将jsx转换成js --> <script src="../../js/babel.min.js"></script> <script type="text/babel"> // 创建虚拟dom const VDOM=<h1>Hello,React</h1> // 渲染虚拟dom到页面 ReactDOM.render(VDOM,document.getElementById('test')); </script> </body> </html> [代码] 2、创建虚拟dom的两种方式 纯 JS 方式(一般不用),如果标签太多,会嵌套太多层 JSX 方式 [代码]//纯js方式 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 准备好一个容器 --> <div id="test"></div> <!-- react核心库 --> <script src="../../js//react.development.js"></script> <!-- 用于支持react支持dom操作 --> <script src="../../js//react-dom.development.js"></script> <!-- 引入babel,用于将jsx转换成js --> <script src="../../js/babel.min.js"></script> <script type="text/javascript"> // 创建虚拟dom // const VDOM=React.createElement(标签名,标签属性,标签内容) const VDOM=React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React')); // 渲染虚拟dom到页面 ReactDOM.render(VDOM,document.getElementById('test')); </script> </body> </html> [代码] [代码]//JSX方式 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 准备好一个容器 --> <div id="test"></div> <!-- react核心库 --> <script src="../../js//react.development.js"></script> <!-- 用于支持react支持dom操作 --> <script src="../../js//react-dom.development.js"></script> <!-- 引入babel,用于将jsx转换成js --> <script src="../../js/babel.min.js"></script> <script type="text/babel"> // 创建虚拟dom const VDOM=( <h1 id="title"> <span>Hello,React</span> </h1> ) // 渲染虚拟dom到页面 ReactDOM.render(VDOM,document.getElementById('test')); </script> </body> </html> [代码] React 提供了一些 API 来创建一种 “特别” 的一般 js 对象 [代码]const VDOM = React.createElement('xx',{id:'xx'},'xx') [代码] 上面创建的就是一个简单的虚拟 DOM 对象 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 准备好一个容器 --> <div id="test"></div> <div id="demo"></div> <!-- react核心库 --> <script src="../../js//react.development.js"></script> <!-- 用于支持react支持dom操作 --> <script src="../../js//react-dom.development.js"></script> <!-- 引入babel,用于将jsx转换成js --> <script src="../../js/babel.min.js"></script> <script type="text/babel"> // 创建虚拟dom const VDOM=( <h1 id="title"> <span>Hello,React</span> </h1> ) // 渲染虚拟dom到页面 ReactDOM.render(VDOM,document.getElementById('test')); console.log(VDOM); console.log(typeof VDOM); console.log(document.getElementById('demo')); </script> </body> </html> [代码] [图片] 虚拟 DOM 对象最终都会被 React 转换为真实的 DOM 我们编码时基本只需要操作 react 的虚拟 DOM 相关数据, react 会转换为真实 DOM 变化而更新界。 3、jsx语法规则: 全称: JavaScript XML react 定义的一种类似于 XML 的 JS 扩展语法: JS + XML 本质是 React.createElement(component, props, …children)方法的语法糖 作用: 用来简化创建虚拟 DOM 写法:[代码]var ele = <h1>Hello JSX!</h1>[代码] 它不是字符串, 也不是 HTML/XML 标签 它最终产生的就是一个 JS 对象 1.定义虚拟DOM时,不要写引号。 2.标签中混入JS表达式时要用{}。 3.样式的类名指定不要用class,要用className。 4.内联样式,要用style={{key:value}}的形式去写。 5.只有一个根标签 6.标签必须闭合 7.标签首字母 (1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。 (2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> <style> .title{ background-color: orange; width: 200px; } </style> </head> <body> <div id="test"></div> <script type="text/babel"> const myId="demo"; const myData="Hello,React"; const VDOM=( <div> <h2 className="title" id={myId.toLowerCase()}> {myData} </h2> <span className="title" id={myId.toUpperCase()} style={{backgroundColor:"blue",fontSize:"26px"}}>{myData}</span> <input type="text"/> </div> ) ReactDOM.render(VDOM,document.getElementById('test')); </script> </body> </html> [代码] [图片] 练习 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jsx小练习</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- 引入react-dom,用于支持react操作DOM --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel" > //模拟一些数据 const data = ['Angular','React','Vue'] //1.创建虚拟DOM const VDOM = ( <div> <h1>前端js框架列表</h1> <ul> { data.map((item,index)=>{ return <li key={index}>{item}</li> }) } </ul> </div> ) //2.渲染虚拟DOM到页面 ReactDOM.render(VDOM,document.getElementById('test')) </script> </body> </html> [代码] [图片] 一定注意区分:【js语句(代码)】与【js表达式】 1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方 下面这些都是表达式:(可以用const a=…表达) (1). a (2). a+b (3). demo(1) (4). arr.map() (5). function test () {} 2.语句(代码): 下面这些都是语句(代码): (1).if(){} (2).for(){} (3).switch(){case:xxxx} 4、模块与组件、模块化与组件化 4.1、模块 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。 作用:复用 js, 简化 js 的编写, 提高 js 运行效率 4.2、组件 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image 等等) 为什么要用组件: 一个界面的功能更复杂 作用:复用编码, 简化项目编码, 提高运行效率 4.3、模块化 当应用的 js 都以模块来编写的, 这个应用就是一个模块化的应用 4.4、组件化 当应用是以多组件的方式实现, 这个应用就是一个组件化的应用 5、组件 5.1、函数式组件 1.React解析组件标签,找到了函数式组件。 2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。 3.组件名和标签必须大写,函数必须要有返回值 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建函数式组件 function Demo(){ console.log(this); return <h2> 我是用函数定义的组件(适用于简单组件的定义)</h2> } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] [图片] [图片] 5.2、类式组件 执行了[代码]ReactDOM.render(<MyComponent/>,.......)[代码]之后,发生了什么? 1.React解析组件标签,找到了MyComponent组件。 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ render(){ return <h2>我是用类定义的组件(适用于复杂组件的定义) </h2> } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] 6、组件实例的三大属性state 6.1、state中this指向 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) //初始化状态 this.state={ isHot:true } } render(){ const {isHot}=this.state; return <h2>今天天气很{isHot?'炎热':'凉爽'}</h2> } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] [图片] [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } } render(){ const {isHot}=this.state; return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); function changeWeather(){ console.log("标题被点击了"); } </script> </body> </html> [代码] [图片] 如果是 [代码] render(){ const {isHot}=this.state; return <h2 onClick={demo()}>今天天气很{isHot?'炎热':'凉爽'}</h2> } [代码] 将会调用demo函数,没有点击控制台也会输出,undifined作为onClick的回调了 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } } //render是放在哪里的?—— Demo的原型对象上,供实例使用。 //render中的this是谁?—— Demo的实例对象 <=> Demo组件实例对象。 render(){ const {isHot}=this.state; return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); function changeWeather(){ console.log(this); console.log("标题被点击了"); } </script> </body> </html> [代码] [图片] babel在翻译的时候,禁止自定义函数指向window,所以changeWeather方法里触碰不到组件实例对象,不能读取 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } } render(){ const {isHot}=this.state; return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { console.log(this); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] [图片] changWeather已经放在类中了,是类中的方法了,render也是类中的方法,但是render中的this指向没有问题,因为执行了ReactDOM.render(<组件名/>…)之后,React解析组件标签,找到了组件。发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。 所以render方法有被组件实例调用。 [代码]<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <script type="text/javascript" > class Person { constructor(name,age){ this.name = name this.age = age } study(){ //study方法放在了哪里?——类的原型对象上,供实例使用 //通过Person实例调用study时,study中的this就是Person实例 console.log(this); } } const p1 = new Person('tom',18) p1.study() //通过实例调用study方法 const x = p1.study x() </script> </body> </html> [代码] [图片] 相当于x是study方法的另一个引用,x()相当于直接调用,如果是直接调用,this会指向window,但是类中自定义方法都局部开启了严格模式,所以调用后this指向是undifine [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } } render(){ const {isHot}=this.state; return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { console.log(this); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] 所以这里面[代码]<h2 onClick={this.changeWeather}>[代码]相当于直接找到了changeWeather方法把它交给了onClick,一点击就直接调用这个方法了,不是实例对象调用的 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } } render(){ const {isHot}=this.state; return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { console.log(this); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); const d=new Demo(); d.changeWeather(); </script> </body> </html> [代码] 模拟实例对象调用,谁调用指向谁,所以this指向实例对象 [图片] 总的来说,就是 changeWeather放在哪里? ———— Weather的原型对象上,供实例使用 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined 6.2、this指向解决 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } this.changeWeather=this.changeWeather.bind(this); } render(){ const {isHot}=this.state; return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { console.log(this); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] 构造器中的this就是指向实例对象。 [代码] this.changeWeather=this.changeWeather.bind(this); [代码] 第一个this指向实例对象,第二个this也指向实例对象。 看右边式子,虽然实例对象中没有changeWeather这个方法,但是会顺着原型链去找,然后就找到了方法,bind()会生产一个函数,同时根据传递的第一个参数改变this指向,第三个当前也是指向实例对象的,所以生产一个新的函数的this指向改成指向构造器。 然后你有了一个指向实例对象的函数了。把这个函数放在了这个实例对象自身,并且把它命名为changeWeather [图片] bind 没有规定,传递值和数组都可以。call 和 apply 函数的执行是直接执行的,而 bind 函数会返回一个函数,然后我们想要调用的时候才会执行。 然后点击后,触发的是实例对象上的changeWeather了,而不是顺着原型链找到的changeWeather了 [图片] 改下名字,测试一下 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } this.tool=this.changeWeather.bind(this); } render(){ const {isHot}=this.state; return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { console.log(this); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] 6.3、setState的使用 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } this.tool=this.changeWeather.bind(this); } render(){ const {isHot}=this.state; return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { this.state.isHot=!this.state.isHot console.log(this.state.isHot) } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] 多次点击,页面没有变化,但是控制台会有输出 [图片] 改了但是没完全改,react不认可 状态不可直接更改,要借助一个内置的api 这是直接更改,是错误的 [代码] this.state.isHot=!this.state.isHot [代码] 调用setState [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../../js//react.development.js"></script> <script src="../../js//react-dom.development.js"></script> <script src="../../js/babel.min.js"></script> </head> <body> <div id="test"></div> <script type="text/babel"> // 创建类式定义组件 class Demo extends React.Component{ constructor(props){ super(props) this.state={ isHot:true } this.tool=this.changeWeather.bind(this); } render(){ const {isHot}=this.state; return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2> } changeWeather() { const isHot=this.state.isHot; console.log(this); this.setState({isHot:!isHot}) console.log(this.state.isHot); } } ReactDOM.render(<Demo/>,(document.getElementById('test'))); </script> </body> </html> [代码] [图片] 状态必须通过setState进行更新,且更新是一种合并,不是替换。其他状态值不会受到影响 6.4、简写state 类中可以直接写赋值语句,含义是给类的实例对象添加一个属性 [代码]class Car { constructor(name,price){ this.name = name this.price = price // this.wheel = 4 } //类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1 a = 1 wheel = 4 static demo = 100 } const c1 = new Car('奔驰c63',199) console.log(c1); console.log(Car.demo); [代码] [图片] 给组件的实例对象添加一个箭头函数,由于箭头函数中没有this,将从上下文寻找this,此时箭头函数中this指向实例对象 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- 引入react-dom,用于支持react操作DOM --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> //1.创建组件 class Weather extends React.Component{ //初始化状态 state = {isHot:false,wind:'微风'} render(){ const {isHot,wind} = this.state return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1> } //自定义方法————要用赋值语句的形式+箭头函数 changeWeather = ()=>{ const isHot = this.state.isHot this.setState({isHot:!isHot}) } } //2.渲染组件到页面 ReactDOM.render(<Weather/>,document.getElementById('test')) </script> </body> </html> [代码] [图片] 6.5、总结 组件中 render 方法中的 this 为组件实例对象 组件自定义的方法中 this 为 undefined,如何解决? a) 强制绑定 this: 通过函数对象的 bind() b) 箭头函数 状态数据,不能直接修改或更新 7、组件实例的三大属性props 7.1、基本使用 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../../js/react.development.js"></script> <!-- 引入react-dom,用于支持react操作DOM --> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/babel"> //1.创建组件 class Weather extends React.Component{ render(){ console.log(this); return( <ul> <li>{this.props.name}</li> <li>{this.props.age}</li> </ul> ) } } ReactDOM.render(<Weather name="tom" age="19"/>,document.getElementById('test1')) ReactDOM.render(<Weather name="jack"age="18"/>,document.getElementById('test2')) ReactDOM.render(<Weather name="mike"age="17"/>,document.getElementById('test3')) </script> </body> </html> [代码] [图片] [图片] 7.2、批量传递props [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../../js/react.development.js"></script> <!-- 引入react-dom,用于支持react操作DOM --> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/babel"> //1.创建组件 class Weather extends React.Component{ render(){ const {name,age}=this.props; console.log(this); return( <ul> <li>{name}</li> <li>{age}</li> </ul> ) } } const p={ name:'jack', age:19 } // ReactDOM.render(<Weather name={p.name}age={p.age}/>,document.getElementById('test1')) ReactDOM.render(<Weather {...p}/>,document.getElementById('test1')) </script> </body> </html> [代码] 7.3、对props进行限制 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签属性进行限制 --> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> //1.创建组件 class Person extends React.Component{ render(){ const {name,age,sex,speak}=this.props; console.log(this); return( <ul> <li>{name}</li> <li>{age}</li> <li>{sex}</li> </ul> ) } } Person.propTypes={ name:PropTypes.string.isRequired,//限制name为字符串且必传 age:PropTypes.number,//限制age为number类型 speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func } Person.defaultProps={ sex:'男',//sex默认值为男 age:18//age默认值为18 } ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1')) function speak() { console.log("你好哇"); } </script> </body> </html> [代码] [图片] [图片] 7.4、props简写 props只能读不能改 类中可以直接写赋值语句,含义是给类的实例对象添加一个属性 [代码]class Car { constructor(name,price){ this.name = name this.price = price // this.wheel = 4 } //类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1 a = 1 wheel = 4 static demo = 100//相当于在类的外面写Car.demo=100 } const c1 = new Car('奔驰c63',199) console.log(c1); console.log(Car.demo); [代码] [图片] [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签属性进行限制 --> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> //1.创建组件 class Person extends React.Component{ static propTypes={ name:PropTypes.string.isRequired,//限制name为字符串且必传 age:PropTypes.number,//限制age为number类型 speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func } static defaultProps={ sex:'男',//sex默认值为男 age:18//age默认值为18 } render(){ const {name,age,sex,speak}=this.props; console.log(this); return( <ul> <li>{name}</li> <li>{age}</li> <li>{sex}</li> </ul> ) } } ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1')) function speak() { console.log("你好哇"); } </script> </body> </html> [代码] 7.5、props与构造器 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>对props进行限制</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <!-- 引入react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- 引入react-dom,用于支持react操作DOM --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="../js/babel.min.js"></script> <!-- 引入prop-types,用于对组件标签属性进行限制 --> <script type="text/javascript" src="../js/prop-types.js"></script> <script type="text/babel"> //创建组件 class Person extends React.Component{ constructor(props){ //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props // console.log(props); super(props) console.log('constructor',this.props); } //对标签属性进行类型、必要性的限制 static propTypes = { name:PropTypes.string.isRequired, //限制name必传,且为字符串 sex:PropTypes.string,//限制sex为字符串 age:PropTypes.number,//限制age为数值 } //指定默认标签属性值 static defaultProps = { sex:'男',//sex默认值为男 age:18 //age默认值为18 } render(){ // console.log(this); const {name,age,sex} = this.props //props是只读的 //this.props.name = 'jack' //此行代码会报错,因为props是只读的 return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age+1}</li> </ul> ) } } //渲染组件到页面 ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1')) </script> </body> </html> [代码] 7.6、函数式组件使用props 函数式组件里面没有实例对象,三大属性按道理都不能使用,但是可以使用props,但是函数可以接受参数 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>对props进行限制</title> </head> <body> <!-- 准备好一个“容器” --> <div id="test1"></div> <div id="test2"></div> <div id="test3"></div> <script type="text/javascript" src="../js/react.development.js"></script> <script type="text/javascript" src="../js/react-dom.development.js"></script> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/javascript" src="../js/prop-types.js"></script> <script type="text/babel"> //创建组件 function Person (props){ const {name,age,sex} = props return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age}</li> </ul> ) } Person.propTypes = { name:PropTypes.string.isRequired, //限制name必传,且为字符串 sex:PropTypes.string,//限制sex为字符串 age:PropTypes.number,//限制age为数值 } //指定默认标签属性值 Person.defaultProps = { sex:'男',//sex默认值为男 age:18 //age默认值为18 } //渲染组件到页面 ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1')) </script> </body> </html> [代码] 8、refs属性 组件内的标签可以定义 ref 属性来标识自己 8.1、字符串形式ref [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { showData=()=>{ console.log(this); console.log(this.refs.input1); console.log(this.refs.input1.value); } showData2=()=>{ console.log(this.refs.input2.value); } render() { return( <div> <input ref="input1" type="text"/> <button onClick={this.showData}>点击显示内容</button> <input ref='input2' onBlur={this.showData2} type="text"/> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] [图片] 8.2、回调形式的ref [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { showData=()=>{ console.log(this.input1.value); } showData2=()=>{ console.log(this.input2.value); } render() { return( <div> <input ref={(node)=>{console.log(node);this.input1=node;console.log(this)}} type="text"/> <button onClick={this.showData}>点击显示内容</button> <input ref={(node)=>{console.log(node);this.input2=node,console.log(this)}} onBlur={this.showData2} type="text"/> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] 实例对象调用render方法,由于箭头函数没有指定的this,向外面找,于是指向实例对象this.input1=node,给实例对象添加了一个属性 [图片] 8.3、refs调用次数 如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { state={isHot:true} showData=()=>{ console.log(this.input1.value); } showData2=()=>{ console.log(this.input2.value); } change=()=>{ let {isHot}=this.state; this.setState({isHot:!isHot}) } render() { return( <div> <h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1> <button onClick={this.change}>点击切换</button> <input ref={(node)=>{console.log(node);}} type="text"/> <button onClick={this.showData}>点击显示内容</button> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] [图片] ref 的回调函数定义成 class 的绑定函数的方式 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { state={isHot:true} showData=()=>{ console.log(this.input1.value); } showData2=()=>{ console.log(this.input2.value); } change=()=>{ let {isHot}=this.state; this.setState({isHot:!isHot}) } showNode=(node)=>{ console.log(node); this.input1=node; } render() { return( <div> <h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1> <button onClick={this.change}>点击切换</button> <input ref={this.showNode} type="text"/> <button onClick={this.showData}>点击显示内容</button> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] 8.4、createRef React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的 [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>state简写方式</title> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { myref=React.createRef(); myref2=React.createRef(); showData=()=>{ console.log(this.myref.current.value); } showData2=()=>{ console.log(this.myref2.current.value); } render() { return( <div> <input ref={this.myref} type="text"/> <button onClick={this.showData}>点击显示内容</button> <input ref={this.myref2} onBlur={this.showData2} type="text"/> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] 9、事件处理 通过 onXxx 属性指定事件处理函数(注意大小写) React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件,为了更好的兼容性 React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素),为了的高效 通过 event.target 得到发生事件的 DOM 元素对象,不要过度使用ref [代码]<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <div id="test1"></div> <script type="text/javascript" src="../../js/react.development.js"></script> <script type="text/javascript" src="../../js/react-dom.development.js"></script> <script type="text/javascript" src="../../js/babel.min.js"></script> <script type="text/javascript" src="../../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { myref=React.createRef(); myref2=React.createRef(); showData=()=>{ console.log(this.myref.current.value); } showData2=(event)=>{ console.log(event.target); } render() { return( <div> <input ref={this.myref} type="text"/> <button onClick={this.showData}>点击显示内容</button> <input ref={this.myref2} onBlur={this.showData2} type="text"/> </div> ) } } ReactDOM.render(<Demo/>,document.getElementById('test1')); </script> </body> </html> [代码] 点击第二个输入框输入,然后失去焦点 [图片]
2021-11-17 - 如何实现一个简单的http请求的封装
好久没发文章了,最近浏览社区看到比较多的请求封装,以及还有在使用原始请求的童鞋。为了减少代码,提升观赏性,我也水一篇吧,希望对大家有所帮助。 默认请求方式,大家每次都这样一些写相同的代码,会不会觉得烦,反正我是觉得头大 😂 [代码]wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '', y: '' }, header: { 'content-type': 'application/json' // 默认值 }, success (res) { console.log(res.data) } }) [代码] 来,进入正题吧,把这块代码封装下。 首先新建个request文件夹,内含request.js 代码如下: [代码]/** * 网络请求封装 */ import config from '../config/config.js' import util from '../util/util.js' // 获取接口地址 const _getPath = path => (config.DOMAIN + path) // 封装接口公共参数 const _getParams = (data = {}) => { const timestamp = Date.now() //时间戳 const deviceId = Math.random() //随机数 const version = data.version || config.version //当前版本号,自定或者取小程序的都行 const appKey = data.appKey || config.appKey //某个小程序或者客户端的字段区分 //加密下,防止其他人随意刷接口,加密目前采用的md5,后端进行校验,这段里面的参数你们自定,别让其他人知道就行,我这里就是举个例子 const sign = data.sign || util.md5(config.appKey + timestamp + deviceId) return Object.assign({}, { timestamp, sign, deviceId, version, appKey }, data) } // 修改接口默认content-type请求头 const _getHeader = (headers = {}) => { return Object.assign({ 'content-type': `application/x-www-form-urlencoded` }, headers) } // 存储登录态失效的跳转 const _handleCode = (res) => { const {statusCode} = res const {msg, code} = res.data // code为 4004 时一般表示storage里存储的token失效或者未登录 if (statusCode === 200 && (code === 4004)) { wx.navigateTo({ url: '/pages/login/login' }) } return true } /** * get 请求, post 请求 * @param {String} path 请求url,必须 * @param {Object} params 请求参数,可选 * @param {String} method 请求方式 默认为 POST * @param {Object} option 可选配置,如设置请求头 { headers:{} } * * option = { * headers: {} // 请求头 * } * */ export const postAjax = (path, params) => { const url = _getPath(path) const data = _getParams(params) //如果某个参数值为undefined,则删掉该字段,不传给后端 for (let e in data) { if (data[e] === 'undefined') { delete data[e] } } // 处理请求头,加上最近比较流行的jwtToken(具体的自己百度去) const header = util.extend( true, { "content-type": "application/x-www-form-urlencoded", 'Authorization': wx.getStorageSync('jwtToken') ? `Bearer ${wx.getStorageSync('jwtToken')}` : '', }, header ); const method = 'POST' return new Promise((resolve, reject) => { wx.request({ url, method, data, header, success: (res) => { const result = _handleCode(res) result && resolve(res.data) }, fail: function (res) { reject(res.data) } }); }) } [代码] 那么如何调用呢? [代码]//把request的 postAjax注册到getApp()下,调用时: const app = getApp() let postData = { //这里填写请求参数,基础参数里的appKey等参数可在这里覆盖传入。 } app.postAjax(url, postData).then((res) => { if (res.success) { //这里处理请求成功逻辑。 } else { //wx.showToast大家觉得麻烦也可以写到util.js里,调用时:util.toast(msg) 即可。 wx.showToast({ title: res.msg || '服务器错误,请稍后重试', icon: "none" }) } }).catch(err => { //这里根据自己场景看是否封装到request.js里 console.log(err) }) [代码] config.js 主要是处理正式环境、预发环境、测试环境、开发环境的配置 [代码]//发版须修改version, env const env = { dev: { DOMAIN: 'https://dev-api.weixin.com' }, test: { DOMAIN: 'https://test-api.weixin.com', }, pro: { DOMAIN: 'https://api.qtshe.com' } } module.exports = { ...env.pro } [代码] 以上就是简单的一个request的封装,包含登录态失效统一跳转、包含公共参数的统一封装。 老规矩,最后放代码片段,util里内置了md5方法以及深拷贝方法,具体的我也不啰嗦,大家自行查看即可~ https://developers.weixin.qq.com/s/gbPSLOmd7Aft
2020-04-03 - INHN
一个简单的校园常见功能小程序
2021-11-18