ajax、promise、react、缓存笔记记录

ajax请求

1.请求基本步骤

<body>
    <form action="###">
    手机号:<input type="text" name="phone" placeholder="手机号" id="phone">
    <br>
    密码:<input type="text" name="pass" id="pass">
    <br>
    <button id="btn">登录</button>
  </form>
    <script>
        const phone=document.getElementById('phone')
        const pass=document.getElementById('pass')
        const btn=document.getElementById('btn')
        btn.onclick=function(){
            //1.1利用ajax核心对象xmlHttpRequest创造实例对象
            //1.2 利用open方法打开路径
            //1.3 利用send方法发送请求参数
            //1.4 利用readystatechange事件监听readyState请求状态码的变化
            return false
        }
    </script>
</body>

1.1 利用ajax核心对象xmlHttpRequest创造实例对象

因为XMLHttpRequest的原型对象中包含很多方法用来支持ajax请求

const xhr=new XMLHttpRequest()

注意:在与form表单标签使用时,要注意form表单的默认请求事件 return false

1.2 利用open方法打开路径

open的3个参数:

​ 请求方式:get/post

​ 请求地址:

​ 1、get请求的地址中包含查询字符段(请求参数)因为get请求默认读取缓存,所以可以用时间戳拼接到查询字符串后面,保证请求地址不同

​ 2、post请求参数在请求体中

​ 是否异步:false/true

//get请求
xhr.open('get',`/login?phone=${phone.value}&pass=${pass.value}&_=${Date.now()}`,true)
//post请求
xhr.open('post','/login',true)

1.3 利用send方法发送请求参数

send 参数:

​ 1.如果是get请求,因为请求参数都在请求地址里面,所以可以不填参数,也可以填写null

​ 2.如果是post请求,里面填写的是要发送的请求体

​ send发送数据的时候需要设置请求头,告诉服务端我发送的数据是什么类型

​ - 如果send中数据格式是url查询字符串格式,请求头的content-type :application/x-www-form-urlencoded

​ - 如果send中数据格式是json字符串格式,请求头的content-type:application/json

//get请求
xhr.send() 或 xhr.send(null)
//post请求
xhr.setRequestHeader('Content-Type','application/json;charset=utf-8')
xhr.send(JSON.stringfy{
         phone:phone.value,
         pass:pass.value
         })

1.4 利用readystatechange事件监听readyState请求状态码的变化

readyState请求状态码(0-4):

​ 0 : 表示没有发送

​ 1 : 表示启动了open方法

​ 2 : 表示启动了send方法

​ 3 : 表示开始部分接受数据

​ 4 : 表示成功了

status 响应状态码(200-299)

responseText 接受其他文本类响应(json)

responseXml 接受xml响应

xhr.onreadystatechange=function(){
    console.log('readyState'+xhr.readyState)
    if(xhr.readyState===4&&xhr.status>=200&&xhr.status<=299){
       console.log('请求发送成功了')
        const resData=JSON.parse(xhr.responseText)
        //app.js 设置了响应成功code :200
        if(resData.code===200){
          return alert("登录成功,您的用户名是" + resData.data.username)
        }
        alert('登录失败')
}

2.jQuery中ajax

2.1 一级封装

$(function(){
    $('#btn').click(function(){
        $.ajax({
            url:'/login',//请求地址
            type:'get' /'post' , //请求方式
            cache:false,//是否缓存
            data:{
                //请求参数
                //数据:如果是get请求 则帮我们拼接在url上,如果是post请求 会转成字符串
                 phone:$('#phone').value,
         		pass:$('#pass').value
            },
            dataType: "json", //预期的响应数据的格式
            headers: {}, //请求头
            timeout: 2000, //设置超时时间
            sucess(val){
                //成功的回调函数,参数就是得到的数据
                console.log(val)
			}
          })
           return false 
        })  
     })

2.2 二级封装

$(function(){
  $('#btn').click(function(){
    //get请求
    $.get('/login',
          {
                //请求参数
                //数据:如果是get请求 则帮我们拼接在url上,如果是post请求 会转成字符串
                 phone:$('#phone').value,
         		pass:$('#pass').value
            },
          (val)=>{
        //成功的回调函数,参数就是得到的数据
                console.log(val)
    	},
          'json')
    
    //post请求
     $.post('/login',
          {
                //请求参数
                //数据:如果是get请求 则帮我们拼接在url上,如果是post请求 会转成字符串
                 phone:$('#phone').value,
         		pass:$('#pass').value
            },
          {
                //请求参数
                //数据:如果是get请求 则帮我们拼接在url上,如果是post请求 会转成字符串
                 phone:$('#phone').value,
         		pass:$('#pass').value
            },
          (val)=>{
        //成功的回调函数,参数就是得到的数据
                console.log(val)
    	},
          'json')
    
    return false
    
	})
})

2.3 三级封装

$(function(){
    $('#btn').click(function(){
        $.getJSON('/login',
                  { //请求参数
            phone:$('#phone').value,
            pass:$('#pass').value
           },
              	(val)=>{
     					console.log(val)
    	})
	})
})

Promise

1. Promise基本介绍

1.1 Promise构造函数

  1. Promise对象是一个异步编程的解决方案,可以将异步代码操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称‘回调地狱’)

  2. Promise上有then,catch,finally三个原型方法

  3. Promise上有all,allSettled,race,any,reject,resolve 六个静态方法

  4. Promise是处理异步代码的,本身Promise自己的回调函数的执行是同步的

1.2 Promise基本使用

  1. Promise实例化的接收一个回调函数作为参数

  2. Promise回调函数接受两个参数分别是reslove和reject(这两个都是函数)

  3. Promise中书写异步代码,在异步代码成功的时候,可以调用reslove函数,在异步代码失败的时候可以调用reject函数

  4. Promise的返回值会根据resolve和reject的调用决定状态,如果没有reject或resolve,则会返回pending状态的promise实例对象,如果是同步代码错误,则直接返回失败的实例对象promise,值为错误信息
    resolve和reject接受参数,分别是成功的值和失败的值,会传递给Promise的实例对象

  5. Promise实例对象的状态只能由pending变为其他状态

1.3 Promise实例化对象

  1. promiseState属性:当前promise的状态

    • 默认是pending状态,代表异步代码正在执行中

    • fulfilled/resolved:代表异步代码执行成功并调用了resolve函数

    • rejected: 代表异步代码执行失败并调用了reject函数

  2. PromiseResult属性:当前promise执行的结果

    • 如果异步代码执行成功,值是resolve函数中传递值

    • 如果异步代码执行失败,值是reject函数中的错误信息

2.Promise原型方法

const p1=new Promise((resolve,reject)=>{
    try{
        throw new Error('A有错误')
        setTimeout(()=>{
            throw new Error('A异步有错误')
            console.log('A打印成功')
            resolve('A')
        })
    }catch(e){
        reject(e.message)
    }
})
注意:try...catch...只能捕获同步错误,异步里面的错误不能到catch里面,会直接报错
同时同步代码里面有错误后,同步代码后面的代码不会执行,会直接进入catch里面
try...catch...捕获错误后,就不会直接报错 就是会进入catch,我们可以通过error.message获取错误信息,但是不会直接直接在页面里报错

2.1 then()方法

p1.then((value)=>{
    //若调用then方法的promise实例状态为成功,则进入这个回调函数,value是promise实例的值
    console.log(value) //A
},(reason)=>{
    //若调用then方法的promise实例状态为失败,则进入这个回调函数,reason是promise实例的传入的错误信息
    console.log(reason)//e.message的具体信息
})
2.1.1 then方法基本介绍
  1. then方法是供Promise的实例对象调用,能够通过实例对象的状态执行下一步操作
  2. then方法可以接受2个参数,都是回调函数,分别处理成功状态和失败状态的的promise实例对象
  3. then方法中回调函数都是异步进行的
  4. then方法中回调函数的参数就是成功或者失败的promise实例的
2.1.2 then方法返回值
  1. 默认返回一个成功状态的promise对象,值为返回的值
  2. 如果then中出现报错且没有解决,则返回一个失败状态的promise对象,值为错误信息
  3. 如果then返回一个promise对象,则返回值与这个promise对象挂钩
  4. 如果then中没有处理调用then方法的promise实例对应状态的回调函数时候,会发生值穿透现象

(值穿透现象:返回一个promise对象,promise对象的内容和调用方法的promise实例一样)

2.2 catch()方法

p1.catch(reson=>{
   //catch只处理调用该方法的失败状态下的promise实例,如果是成功状态的promie实例,会发生值的穿透
   //若调用then方法的promise实例状态为失败,则进入这个回调函数,reason是promise实例的传入的错误信息
     console.log(reson)//e.message的具体信息
})
2.2.1 catch方法基本介绍
  1. 和then的第二个回调函数作用一致
  2. 不能和then的第二个回调函数同时使用
2.2.2 catch返回值:规律与then方法一致

2.3 finally()方法

p1.finally(()=>{
    //调用的promise实例状态为成功或失败都可以进入这个回调函数
    console.log(reson)//undefined
    console.log(value)//undefined
})
2.3.1 finally方法基本介绍
  1. 无论调用方法的promise实例状态是成功与否,都会进入finally的回调函数
  2. finally的回调函数不接受任何参数
2.3.2 finally返回值:
  1. 默认情况下直接穿透

  2. 如果finally中出现异常,则会返回一个失败的promise对象,值为异常信息

  3. 如果finally中返回promise实例

    • 返回的promise实例为成功,则无需理会,直接穿透
    • 返回的promise实例为失败,则finally返回这个失败的promise实例

2.4 案例练习

3.Promise静态方法

    const p1 = new Promise((resolve, reject) => {
      console.log("开始请求A");
      try {
        // throw new Error("A错误")
        setTimeout(() => {
          console.log("A成功");
          resolve("A")
        }, 2000)
      } catch (e) {
        reject(e.message)
      }
    })

    const p2 = new Promise((resolve, reject) => {
      console.log("开始请求B");
      try {
        // throw new Error("B错误")
        setTimeout(() => {
          console.log("B成功");
          resolve("B")
        }, 1000)
      } catch (e) {
        reject(e.message)
      }
    })

    const p3 = new Promise((resolve, reject) => {
      console.log("开始请求C");
      try {
        // throw new Error("C错误")
        setTimeout(() => {
          console.log("C成功");
          resolve("C")
        }, 1500)
      } catch (e) {
        reject(e.message)
      }
    })
	const allResult = Promise.all([p1, p2, p3]);//传入的参数必须是iterable
	const allResult = Promise.allSettled([p1, p2, p3]);
	const allResult = Promise.race([p1, p2, p3]);
	const allResult = Promise.any([p1, p2, p3]);
	const allResult = Promise.resolve([p1, p2, p3]);
	const allResult = Promise.reject([p1, p2, p3]);
    console.log("allResult", allResult);

3.1 all()方法

  1. 返回一个promise对象
  2. 如果参数中promise对象状态都是成功的,则返回一个成功的promise对象,值为参数中所有promise对象的值组成的数组
  3. 如果参数中有任何一个promise对象状态是失败的,则返回一个失败的promise对象,值为参数中监听到的最先执行失败的promise对象的错误信息(reject中的值)

3.2 allSettled()方法

  1. 返回一个promise对象
  2. 主要是为了检测所有的promise对象是否执行结束(无论成功还是失败)
  3. allSettled方法永远返回成功的promise状态,值是一个数组,数组的每一个值是监听的promise对象的状态和值组成的新对象

3.3 race()方法

  1. 返回一个promise对象
  2. 返回的promise对象与参数中第一个改变状态的promise对象挂钩

3.4 any()方法

  1. 返回一个promise对象
  2. 返回的promise对象与参数中执行最快且成功promise对象挂钩
  3. 如果参数中所有promise对象的状态都为失败,返回一个错误状态的promise对象,值为新的错误类型AggregateError:All promises were rejected

3.5 resolve()方法

  1. 快速的得到一个成功的promise对象,值为resolve的参数(也可以快速的把一个值包装到成功promise对象中,就可以继续then异步处理)
  2. 当resolve的参数是一个promise对象的时候,resolve的返回值就和这个promise对象挂钩

3.6 reject()方法

  1. 快速的得到一个失败的promise对象,值为reject的参数(也可以快速的把一个错误包装到失败promise对象中,就 可以继续catch异步处理)
  2. 当reject的参数是一个promise对象的时候,返回一个失败状态的promise对象,值为传入的参数promise对象

async&await

1.generator

      // generator函数 *号  yield关键字

      function* fn() {
        console.log("123");
        yield console.log("1");
        // 一个yield分号结束之前,都属于yield
        yield console.log("2");
        yield console.log("3");
        yield console.log("4");
        yield console.log("5");
      }
      const res = fn();
      console.log(res); //res中的原型链上有next方法 返回一个迭代器对象(iterator)

      document.onclick = function () {
        res.next();
      };
    function* getData() {
        yield setTimeout(() => {
          console.log("要1");
          res.next();
        }, 2000);

        yield setTimeout(() => {
          console.log("要2");
          res.next();
        }, 1000);

        yield setTimeout(() => {
          console.log("要3");
          res.next();
        }, 1500);

        yield setTimeout(() => {
          console.log("要4");
          res.next();
        }, 1500);

        yield setTimeout(() => {
          console.log("要5");
        }, 1000);
      }

      const res = getData(); //先调用generator函数 得到一个对象

      
      document.onclick = function () {
        // 点击文档后开始调用getData 每次点击会重新调用,重新开始
        // const res = getData();
        res.next();
      };

2.async&await

// 最终结果顺序:1 3 2
        async function fn(){
          await console.log(1);
          // await语法语句后面的代码是异步代码
          console.log(2);
      }
      fn()
      console.log(3);
      // 最终结果顺序:3 2 1
      async function fn() {
        // await后面的代码 没有等待前面计时器异步代码的执行
        await setTimeout(() => {
          console.log(1);
        }, 2000);
        // await语法语句后面的代码是异步代码
        console.log(2);
      }
      fn();
      console.log(3);

      // 结果顺序:3 1 2
      async function fn() {
        // await 后面等待promise对象 因为promise对象有异步代码成功结束节点提示
        // 如果接受到的是reject失败结果,await语句后面的代码不会执行 会报错
        // 如果接受到的是resolve成功结果,await语句后面代码正常执行,await返回值是promise实例对象的值(resolve传的值)
        const p=await new Promise((resolve, reject) => {
          setTimeout(() => {
            console.log(1);
            resolve('这是异步代码结果');
            reject()
          }, 2000);
        });
        console.log(p);//这是异步代码结果 
        console.log(2);
      }
      fn();
      console.log(3);
      

async函数返回值

  1. async函数返回一个promise对象
  2. 默认返回成功状态的promise对象,值为函数返回值(与await没有关系)
  3. 当async函数内部出现错误时,返回失败状态的promise对象,值为错误信息
  4. 当async函数内的await等到了一个失败状态的promise实例对象,则函数返回值与这个promise对象挂钩
  5. await返回值:成功的promise对象的值
async function getA() {
        // throw new error('错啦')
        const p=await new Promise((resolve, reject) => {
          //  throw new Error('错啦')

          try {
            console.log("开始请求A");
            // throw new Error("A错啦");
            setTimeout(() => {
              console.log("A开始执行");
              // throw new Error("A错啦");
              console.log("A成功啦");
              resolve("A成功");
            }, 1000);
          } catch (e) {
            reject(e.message);
          }
        });
        console.log('B');
        console.log('p',p);
        
        return 1;
      }
      const res = getA();
      console.log("async函数的返回值", res);

3.案例练习

3.1 getData案例

3.1.1 普通版
async function getData(){
          console.log('开始请求A数据');
          const A=await new Promise((resolve,reject)=>{
              try{
               
                  setTimeout(()=>{
                      console.log("A成功了");
                      resolve({
                          name:'laowang'
                      })
                  })
              }catch(e){
                  reject(e.message)
              }
          })

          console.log('开始请求B数据');
          const B=await new Promise((resolve,reject)=>{
              try{
                 
                  setTimeout(()=>{
                      console.log("B成功了");
                      resolve({
                          age:18
                      })
                  })
              }catch(e){
                  reject(e)
              }
            })


            console.log('开始请求C数据');
            const C=await new Promise((resolve,reject)=>{
              try{
                  
                  setTimeout(()=>{
                      console.log("C成功了");
                      resolve(Object.assign(A,B,{gender:'nan'}))
                  })
              }catch(e){
                  reject(e)
              }
            })

        console.log(C)
    }

    getData()



3.1.2 函数封装版
function getName() {
  return new Promise((resolve, reject) => {
    try {
      setTimeout(() => {
        resolve({
          name: "zs",
        });
      }, 2000);
    } catch (e) {
      reject(e.message);
    }
  });
}

function getAge() {
  return new Promise((resolve, reject) => {
    try {
      setTimeout(() => {
        resolve({
          age: 18,
        });
      }, 1500);
    } catch (e) {
      reject(e.message);
    }
  });
}

function getGender(name, age) {
  return new Promise((resolve,reject) => {
    try {
      setTimeout(() => {
        resolve(Object.assign(name, age, { gender: "男" }));
      }, 1000);
    } catch (e) {
      reject(e.message);
    }
  });
}

async function getData() {
  const name = await getName();
  const age = await getAge();
  const data = await getGender(name, age);
  console.log(data);
}
getData()

3.2 写入文件案例

3.2.1 普通版
const fs = require("fs");
const path = require("path");
const filePath = path.join(__dirname, "./a.txt");

async function writeWordsInTxt() {
  const fd = await new Promise((resolve, reject) => {
    fs.open(filePath, "a", (err, fd) => {
      if (err) return reject(err.message);
      resolve(fd);
    });
  });
  await new Promise((resolve, reject) => {
    fs.write(fd, "你好呀", (err) => {
      if (err) return reject(err.message);
      resolve();
    });
  });
  await new Promise((resolve, reject) => {
    fs.close(fd, (err) => {
      if (err) return reject(err.message);
      resolve();
    });
  });
}

writeWordsInTxt() 
3.2.2 函数封装版
const fs = require("fs");
const path = require("path");
const filePath = path.join(__dirname, "./a.txt");

function open() {
  return new Promise((resolve, reject) => {
    fs.open(filePath, "a", (err, fd) => {
      if (err) return reject(err.message);
      resolve(fd);
    });
  });
}

function write(fd) {
  return new Promise((resolve, reject) => {
    fs.write(fd, "封装好啦", (err) => {
      if (err) return reject(err.message);
      resolve();
    });
  });
}

function close(fd) {
  return new Promise((resolve, reject) => {
    fs.close(fd, (err) => {
      if (err) return reject(err.message);
      resolve;
    });
  });
}

async function writeWordsInFile() {
  const fd = await open();

  await write(fd);
  close(fd);
}

writeWordsInFile();
3.2.3 promisify版
const fs = require("fs");
const path = require("path");
const filePath = path.join(__dirname, "./a.txt");
const { promisify } = require("util");
const open = promisify(fs.open);
const write = promisify(fs.write);
const close = promisify(fs.close);

(async function () {
  const fd = await open(filePath, "a");
  await write(fd,'promisify完成啦');
  close(fd);
})();

axios

1.axios基础请求

使用:

<button id="get">get-得到用户信息</button>
    <button id="post">post-得到用户信息</button>
    <button id="put">put-得到用户信息</button>
    <button id="del">delete-删除用户信息</button>

    <script>

        const oGet = document.getElementById("get");
        const oPost = document.getElementById("post");
        const oPut = document.getElementById("put");
        const oDel = document.getElementById("del");

        //  get请求
        oGet.onclick =async function () {
          try{
            const re=await axios({
            url: "/user",
            method: "GET",
            // get请求发送的数据 1.拼接到url上 2.使用params配置
            // params有2种格式 1.对象格式 2.查询字符串格式
            params:{
              userID:001
            },
            timeout:1000,
          });
          console.log('get',re);
          }catch(e){
            console.log(e.message);
          }
        };


        //  post请求
      oPost.onclick =  async function () {
          try{
            const re=await axios({
            url: "/login",
            method: "POST",
            // post请求 请求体参数用data发送,data是一个对象类型
            data:{
              phone:'1300000001',
              pass:'11111'
            },
            timeout:1000,
          });
          console.log('post',re);
          }catch(e){
            console.log(e.message);
          }
        };


        // put请求
        oPut.onclick = async function () {
          try{
            const re=await axios({
            url: "/update",
            method: "put",

            //put请求同post请求一样
           data:{
              userID:'zs',
              age:18
            },
            timeout:1000,
          });
          console.log('put',re);
          }catch(e){
            console.log(e.message);
          }
        };


        //  delete请求
        oDel.onclick = async function () {
          try{
            const re=await axios({
            url: "/deleteuser",
            method: "Delete",
            // delete请求同get请求一样
            params:{
              userID:'zs',

            },

            timeout:1000,
          });
          console.log('del',re);
          }catch(e){
            console.log(e.message);
          }
        };
    </script>

2.axios别名请求

<button id="get">get-得到用户信息</button>
    <button id="post">post-得到用户信息</button>
    <button id="put">put-得到用户信息</button>
    <button id="del">delete-删除用户信息</button>

    <script>
      const oGet = document.getElementById("get");
      const oPost = document.getElementById("post");
      const oPut = document.getElementById("put");
      const oDel = document.getElementById("del");

      //  get请求
      oGet.onclick = async function () {
        try {
          const re = await axios.get("/user", {
            params: {
              userID: 001,
            },
            timeout: 1000,
          });

          // 将查询字符串写在请求地址上
          // const re=await axio.get('/user?userid=001',{
          //   timeout: 1000,
          // })


          console.log("get", re);
        } catch (e) {
          console.log(e.message);
        }
      };

      //  post请求
      oPost.onclick = async function () {
        try {
          const re = await axios.post("/login", {
            data: {
              phone: "1300000001",
              pass: "11111",
            },
            timeout: 1000,
          });
          console.log("post", re);
        } catch (e) {
          console.log(e.message);
        }
      };

      // put请求
      oPut.onclick = async function () {
        try {
          const re = await axios.put("/update", {
            data: {
              userID: "zs",
              age: 18,
            },
            timeout: 1000,
          });
          console.log("put", re);
        } catch (e) {
          console.log(e.message);
        }
      };

      //  delete请求
      oDel.onclick = async function () {
        try {
          // const re = await axios.delete("/deleteuser", {
          //   params: {
          //     userID: "zs",
          //   },
          //   timeout: 1000,
          // });

          const re=await axios.delete('/deleteuser?userid=zs',{
            timeout: 1000,
          })



          console.log("del", re);

        } catch (e) {
          console.log(e.message);
        }
      };
    </script>

3.axios配置默认值

 // axios全局默认配置(配置默认基础路径)
    axios.defaults.baseURL = "/api";

4.创建axios实例

 	const oGet = document.getElementById("get");
      const oPost = document.getElementById("post");
      const oPut = document.getElementById("put");
      const oDel = document.getElementById("del");

      // axios全局默认配置(配置默认基础路径)
      // axios.defaults.baseURL = "/api";

      // 创建实例 (创建一个副本)
      // const myReq = axios.create();
      // 创建实例,并传入配置项
      const myReq = axios.create({
        // 配置当前实例的基础路径
        baseURL: "/api",
        // 配置当前实际的超时时间
        timeout: 1000,
        // 配置当前实例的请求头
        headers: {
          "hello": "world",
        },
      });

      // 创造另一个实例,并传入配置项
      const yourReq = axios.create({
        // 配置当前实例的基础路径
        baseURL: "/sss",
        // 配置当前实际的超时时间
        timeout: 1000,
        // 配置当前实例的请求头
        headers: {
          "isAction": "no",
        },
      });
 const oGet = document.getElementById("get");
      const oPost = document.getElementById("post");
      const oPut = document.getElementById("put");
      const oDel = document.getElementById("del");

      // axios全局默认配置(配置默认基础路径)
      // axios.defaults.baseURL = "/api";

      // 创建实例 (创建一个副本)
      // const myReq = axios.create();
      // 创建实例,并传入配置项
      const myReq = axios.create({
        // 配置当前实例的基础路径
        baseURL: "/api",
        // 配置当前实际的超时时间
        timeout: 1000,
        // 配置当前实例的请求头
        headers: {
          "hello": "world",
        },
      });

      // 创造另一个实例,并传入配置项
      const yourReq = axios.create({
        // 配置当前实例的基础路径
        baseURL: "/sss",
        // 配置当前实际的超时时间
        timeout: 1000,
        // 配置当前实例的请求头
        headers: {
          "isAction": "no",
        },
      });

      //  get请求
      oGet.onclick = async function () {
        try {
          const re = await myReq.get("/user", {
            params: {
              userID: 001,
            },
          });
          console.log("get", re);
        } catch (e) {
          console.log(e.message);
        }
      };

5.axios拦截器

 // 配置请求拦截器
      myReq.interceptors.request.use(
        (config) => {
          // 请求拦截器中拦截的是axios请求的配置项
          console.log("请求配置项", config);
          // 拦截配置项后,要把配置项return出去,否则请求无法进行
          return config;
        },
        (error) => {
          // 进入这个函数,说明请求未到达服务器,请求就有错,此时可以放回一个失败的promise对象,同时错误原因也返回出去,await等到这个失败的promise对象,可以知道请求有问题
          return Promise.reject(error);
        }
      );

      // 配置响应拦截器
      myReq.interceptors.response.use(
        (response) => {
          console.log("response", response);

          return response;
        },
        (error) => {
          //如果请求出现错误,则我们希望进入发请求的时候catch的异常处理
          //在发请求阶段得到响应后异常处理怎么进去呢?await等的时候失败的promise对象
          //所以我们可以把error包装成一个失败的promise对象,返回出去交给请求的地方处理
          console.log("响应拦截器失败处理函数");
          // 进入这个函数,说明请求到达服务器,回来的时候发现有错,返回这个失败的promise对象,可以知道请求有问题
          return Promise.reject(error);
        }
      );

6.axios拦截器的应用

      // 配置请求拦截器
      myReq.interceptors.request.use(
        (config) => {
          // 请求拦截器中拦截的是axios请求的配置项
          console.log("请求配置项", config);
          // 应用1:此处进度条开始
          NProgress.start()
          
          return config;
        },
        (error) => {
          // 响应有问题,进度条也可以结束
          NProgress.done()
          // 进入这个函数,说明请求未到达服务器,请求就有错,此时可以放回一个失败的promise对象,同时错误原因也返回出去,await等到这个失败的promise对象,可以知道请求有问题
          return Promise.reject(error);
        }
      );

      // 配置响应拦截器
      myReq.interceptors.response.use(
        (response) => {
          console.log("response", response); //response是个对象 其中data是response回来的数据
          // 1.响应拦截器用法1:进度条执行结束 NProgress
          // 此处进度条结束
          NProgress.done()

          // 应用2:对响应的数据进行处理 server可以根据我们传过去的信息判断符不符合要求,response根据符不符合要求返回对应状态 我们可以通过判断状态 看是否提供对应页面
          //比如登录-无论登录成功还是失败,只要把结果响应回来了都算响应成功
          //但是对于我们来说,只有登录成功才叫响应成功,如果登录失败,我们就把他交给catch处理
          // 拦截配置项后,要把配置项return出去,否则请求无法进行
          if(response.data.code !== 200){
          return Promise.reject({message:response.data.msg})
          }

          return response.data;
        },
        (error) => {
          //如果请求出现错误,则我们希望进入发请求的时候catch的异常处理
          //在发请求阶段得到响应后异常处理怎么进去呢?await等的时候失败的promise对象
          //所以我们可以把error包装成一个失败的promise对象,返回出去交给请求的地方处理
          console.log("响应拦截器失败处理函数");
          // 进入这个函数,说明请求到达服务器,回来的时候发现有错,返回这个失败的promise对象,可以知道请求有问题
          return Promise.reject(error);
        }
      );

7.axios取消请求

      // 取消axios请求 首先要拿到cancelToken构造函数,cancelToken构造函数在axios上
      // 注:cancelToken构造函数只能在axios拿 不能从axios实例上拿
      const CancelToken = axios.CancelToken;

      // 定义一个全局变量,用来保存局部中得等到取消请求的函数
      let cancel=null;
 	oCancel.onclick=function(){
        // 启动cancel函数
        // 函数里可以传入参数 请求理由
        cancel()
      }

跨域

1.JSONP

<button id="get">get-得到用户信息</button>
  <script>
    const oGet = document.getElementById('get');

    //回调函数,用来jsonp发请求的时候 携带回调函数给服务端 用来服务端调用
    function callback(value) {
      alert("我是callback:" + value)
    }

    let oScript = null;
    //get请求
    oGet.onclick = async function () {
      if (oScript) {
        oScript.remove()
      }
      //因为跨域原因无法直接请求,但是script标签的src可以跨域,我们选择创建一个script标签,帮助我们发送请求
      oScript = document.createElement("script");
      //把请求地址赋值给script标签的src属性
      oScript.src = "http://192.168.20.82:8888/user?userID=001&cb=callback";
      //把script标签插入页面中,则直接会把请求发送
      document.body.appendChild(oScript)
    }
  </script>

//服务器部分
app.get("/user", (req, res) => {

  const {
    userID,
    //拿到客户端发送的回调函数名称
    cb
  } = req.query;

  console.log("请求进来了", userID);

  //模拟客户端需要的数据
  const userToken = "abcdefghijk";
  //设置响应的数据类型是js类型
  res.set("Content-Type", "application/javascript;charset=utf-8")
  //给客户端的script标签响应一个js代码(js代码是调用了客户端发来的回调函数,并传入了数据作为实参)
  return res.send(`${cb}('${userToken}')`);


})

2.cors

//get请求
    oGet.onclick = async function () {
      try {
        //get请求参数放在配置中写
        const re = await axios.get("http://192.168.20.82:8888/user", {
          params: {
            userID: "001"
          }
        })
        console.log("最终的数据是1", re);
      } catch (e) {
        console.log("请求出现异常,异常信息是", e);
      }
    }
//服务器部分
app.get("/user", (req, res) => {
  const {
    userID
  } = req.query;

  //获取当前的origin地址
  const nowOrigin = req.headers.origin;

  //设置白名单
const allowOrigin = ["http://127.0.0.1:5501", "http://127.0.0.1:5505", "http://127.0.0.1:5500", "http://127.0.0.1:5504"]

  //判断当前的origin地址是否在白名单中 如果在 则设置跨域
  if (allowOrigin.includes(nowOrigin)) {
    //设置cors跨域
    res.set("Access-Control-Allow-Origin", nowOrigin)
  }

  if (userID === "001") {
    return res.json({
      code: 200,
      msg: "ok",
      data: {
        username: "laoli"
      }
    });
  }

  res.json({
    code: 201,
    msg: "用户id出错",
    data: null
  })
})

3.代理

缓存

1.强制缓存

强制缓存:

  1. 强制缓存是向浏览器缓存查找请求结果,并根据请求结果来决定我们是否可以使用缓存的过程

  2. 简单来讲,就是浏览器直接使用自己的缓存,不进行任何的请求

  3. 强制缓存的设置过程

    • 客户端请求的时候,需要携带 Cache-Control请求头字段,值是 max-age=XXXX(秒数)

    • 服务端响应的时候,也需要携带 Cache-Contorl的响应头字段,值是max-age=XXXX(秒数)

    • 当下次再次请求的时候,判断自己是否符合强制缓存条件,如果符合,则直接读取缓存,如果不符合,则会走协商缓存

///服务器部分
app.get("/img", (req, res) => {
    const filePath = path.resolve(__dirname, "./01.jpg");
    const rs = fs.createReadStream(filePath);
    res.set("Cache-Control", "max-age=1000")
    rs.pipe(res)
})

2.协商缓存

协商缓存:

  1. 客户端向服务端发送请求,请求某一个资源文件
  2. 服务端向客户端响应当前的文件,并且在响应头中添加两个字段,分别是文件的唯一标识(eTag)和当前被请求文件的最后一次修改时间(last-modified)
  3. 客户端接收到响应,还要处理关于协商缓存的信息,把文件的唯一标识和最后一次修改时间保存下来,并且还要修改字段名,把eTag更名为if-none-match,把last-modified更名为if-modified-since
  4. 客户端再次请求资源,会携带if-none-match和if-modified-since字段
  5. 服务端接收到请求后,会把if-none-match和自己的eTag进行比较,把if-modified-since和自己的last-modified进行比较,如果都相同,则直接响应304状态码,要求读取缓存。否则响应数据,并携带最新的eTag和last-modified
//服务器部分
app.get("/axios", async (req, res) => {
    console.log(1);
    const filePath = path.resolve(__dirname, "axios.min.js");
    //获取文件的唯一标识
    const Etag = etag(filePath);

    //获取文件的最后修改时间 fs.stat可以得到文件的详情
    const stat = promisify(fs.stat);
    const fileStat = await stat(filePath)
    console.log(fileStat.mtime.toGMTString());
    const lastModified = fileStat.mtime.toGMTString();

    //获取请求对象携带的if-modified-since if-none-match
    console.log(req.headers);
    const ifNoneMatch = req.headers["if-none-match"];
    const ifModifiedSince = req.headers['if-modified-since'];

    //把请求携带的信息和服务端文件的信息对比,如果有一个不一致,则重新响应文件

    if (ifNoneMatch !== Etag || ifModifiedSince !== lastModified) {
        //当读取新资源的时候,需要重新设置文件唯一标识 和最后修改时间的 响应头
        res.set("etag", Etag);
        res.set("last-modified", lastModified);
        return res.sendFile(filePath);
    }

    //如果上边的判断不成立,则需要读取缓存
    res.status(304).send();
})

3.压缩

app.get("/", async (req, res) => {

    const filePath = path.resolve(__dirname, "./index.html")
    const rs = fs.createReadStream(filePath);
    //查看支持的压缩格式
    const accpetEncoding = req.headers['accept-encoding'];
    console.log(accpetEncoding)

    //根据客户端的支持的格式来进行不同的压缩
    if (accpetEncoding.includes("gzip")) {
        //zlib.createGzip()//创建一个gzip压缩的盒子,能够被流式写入
        const gzipFile = rs.pipe(zlib.createGzip()) //返回一个gizp压缩格式的可读流

        //告诉客户端我响应的压缩格式是什么
        res.set("content-encoding", "gzip")
        //把压缩好的文件写入到响应中
        return gzipFile.pipe(res) //22.1kb
    }
    
    //根据客户端的支持的格式来进行不同的压缩
    if (accpetEncoding.includes("deflate")) {
        //zlib.createDeflate()//创建一个gzip压缩的盒子,能够被流式写入
        const gzipFile = rs.pipe(zlib.createDeflate()) //返回一个gizp压缩格式的可读流

        //告诉客户端我响应的压缩格式是什么
        res.set("content-encoding", "deflate")
        //把压缩好的文件写入到响应中
        return gzipFile.pipe(res) //22.1kb
    }


    //没有压缩的响应
    rs.pipe(res) //99.1kb
})

事件轮询机制

1. Global对象

2. nodejs事件轮询机制

3. 浏览器事件轮询机制

回调函数:将函数A作为函数B的参数,并且函数A在函数B内进行调用

3.1 代码分类

  • 初始化代码(同步代码):设置定时器、绑定事件,发送ajax等等
  • 回调执行代码(异步代码):定时器回调函数,事件回调函数,ajax回调函数

3.2 轮询机制

  • 浏览器先执行同步代码,再执行异步代码。
  • 在执行同步代码的时候,把异步代码交给浏览器的管理模块进行管理(事件管理模块、ajax管理模块,定时器管理模块)。
  • 当异步代码的回调函数需要执行的时候,会把回调函数放在回调队列(任务队列)中等待执行。
  • 当同步代码执行完毕之后,主线程会去任务队列中轮询,并将任务队列中的任务(回调函数)取出来执行,主线程不断重复这一步,因此叫做事件轮询。

4. 宏任务和微任务

  1. 异步代码有优先级关系。有的优先级高先执行,有的优先级低后执行。分为宏任务(macrotask )和微任务(microtask )

  2. 微任务是js自身发起的: Promise.then/catch/fanally,await语句后的内容,process.nextTick,queueMicrotask

  3. 宏任务是宿主发起的:包括整体代码script,setTimeout,setInterval等等

  4. js引擎执行异步代码。会优先执行微任务,再执行宏任务

  5. 过程如下:

    5.1 执行栈选择最先进入队列的宏任务(一般都是script),执行其同步代码直至结束;

    5.2 检查微任务队列中是否存在微任务,有则会执行至微任务队列为空;

    5.3 执行宏任务中的异步代码

    5.4 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中

    5.5 当前宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)

    5.6 当开始下一个宏任务(从事件队列中获取)

模块化

1.原始

2.commonJS模块化

3.ES6模块化规范

webpack

1.基础配置板块

五大’护法’

  1. entry:入口起点(entry point)

    • 打包时,第一个被访问的源码文件,指示webpack应该使用哪个模块(webpack中一切都是模块),来作为构建其内部依赖图的开始

    • 默认是src/index.js(可以通过配置文件指定)

    • webpack可以通过入口,加载整个项目的依赖

  2. output:出口

    • 打包后,输出的文件名称
    • 默认是dist/main.js(可以通过配置文件指定)
  3. loader :加载器

    • loader让webpack能够去处理那些非JavaScript文件(webpack自身只能解析JavaScript)
  4. plugins:插件

    • 实现loader之外的其他功能(打包优化和压缩等)
    • 是Webpack的支撑,用来实现丰富的功能
  5. mode :模式

    • 生产模式 production
    • 开发模式 development

2.使用webpack配置文件

2.1打包详细配置

2.1 .1打包CSS
2.1.1.1 基本打包
  1. 打包CSS包含:打包逻辑、打包LESS、打包成独立的CSS文件、添加样式前缀、格式校验、压缩CSS
  2. css-loader:将CSS转换为JS(将css输出到打包后的js文件中)
  3. style-loader:把包含CSS内容的JS代码,挂载到页面的style标签中
  4. 需要在入口文件引入CSS(import’./css/main.css’)
  5. 加载器配置:use:[‘style-loader’,‘css-loader’]
  6. 安装 npm i css-loader style-loader -D
rules[
    {
        //匹配后缀名
        test:/\.css$/i,
        use:[
            //use中loader加载是有顺序的,先上后下,注意有的loader需要按照顺序书写
            'style-loader',
            'css-loader'
        ]
    }
]
2.1.1.2 打包less
  1. less-loader:打包less的加载器

  2. 匹配后缀名

  3. 加载器配置:use:[‘style-loader’,‘css-loader’,‘less-loader’]

  4. 安装 npm i less less-loader -D

rules: [{
    test: /\.less$/i,
    use: [
        //use中loader加载是有顺序的,先下后上,注意有的loader需要按照顺序书写
        "style-loader",
        'css-loader',
        'less-loader'
    ]
}]

React

1.基本使用

1.1 相关js库

  1. react.js:React核心库。
  2. react-dom.js:提供操作DOM的react扩展库。
  3. babel.min.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>
    <!-- react的核心包 包含了react的核心内容 -->
    <script src="./js/react.development.js"></script>
    <!-- react中处理虚拟DOM和diffing算法的工具 -->
    <script src="./js/react-dom.development.js"></script>
    <!-- react中使用的jsx语法,babel用来编译jsx语法 -->
    <script src="./js/babel.min.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <!-- 因为script标签中写的是jsx语法,所以我们要一如babel并且设置script标签的type为text/babel -->
    <script type="text/babel">
      // 定义一个虚拟DOM
      const vDOM = <h1>hello world</h1>;
      // 使用ReactDOM的render方法 把虚拟DOM渲染在真实DOM中
      ReactDOM.render(vDOM, document.getElementById("app"));
    </script>                     
  </body>
</html>

1.2 js方式创建虚拟DOM

<!-- 此处用js写虚拟DOM所以不用定义type,默认就是text/javascript -->
<script>
      // 利用js创建一个虚拟DOM
      // const vDOM = React.createElement(
      //   "div",
      //   {
      //     className: "box",
      //     // data-index:1,
      //     // dataIndex: 1,
      //     "data-index": 1,
      //   },
      //   "欢迎"
      // );


      // 嵌套
      const vDOM = React.createElement(
        "div",
        {
          className: "box",
          // data-index:1,
          // dataIndex: 1,
          "data-index": 1,
        },
        React.createElement(
          "h1",
          null,
          React.createElement("span", null, "title")
        )
      );

      // 使用ReactDOM的render方法 把虚拟DOM渲染在真实DOM中
      ReactDOM.render(vDOM, document.getElementById("app"));

1.3 jsx方式创建虚拟DOM

  <style>
      .red {
        color: red;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
<!-- 因为script标签中写的是jsx语法,所以我们要一如babel并且设置script标签的type为text/babel -->
    <script type="text/babel">
      const vDOM = (
        <div>
          <h3>boring</h3>
          <ul>
            <li className="red">boring1</li>
            <li>boring2</li>
            <li>boring3</li>
          </ul>
        </div>
      );
      // 使用ReactDOM的render方法 把虚拟DOM渲染在真实DOM中
      ReactDOM.render(vDOM, document.getElementById("app"));

1.4 虚拟DOM与真实DOM

虚拟DOM:

  1. 本质就是Object类型的对象(一般对象)

  2. 虚拟DOM比较“轻”,真实DOM比较“重”,虚拟DOM是react内部在用的,无需真实DOM身上那么多属性

  3. 虚拟DOM早晚会被react转变成真实DOM,呈现在页面上

<script type="text/babel" >
    //1.创建一个虚拟DOM
    const VDOM = <h1>Hello,React</h1>
    console.log(VDOM) //输出的是虚拟DOM,本质就是Object类型的一般对象
        
    const TDOM = document.getElementById('test')
    console.log(TDOM) //输出的是真实DOM
    debugger;
        
    //2.将虚拟DOM准备真实DOM渲染到页面
    ReactDOM.render(VDOM,document.getElementById('test'))
</script>

1.5 React JSX语法

js表达式:有返回值 js语句:没有返回值

  1. 定义虚拟DOM时,不要写引号

  2. 标签结构中要混入js表达式,需要用{}做分割,即:{js表达式}

  3. 指定标签的类名时,用className

  4. 行内样式,要用style={{}} ,外面一层{}是表示js区域,里面的{}表示对象,里面填写键和键值,像font-size这种属性,要转为fontSize

  5. 只能有一个根标签

  6. 标签必须闭合

  7. 标签首字母:

    • 如果标签首字母小写:则该标签转为html中同名元素,若若html中无该元素,则报错。

    • 如果标签首字母大写:则表明是React去渲染的对应组件,若没有定义过该组件,则报错。

1.6 JSX中的js区域{}里面值表现

jsx中{}得到不同类型的值的反应

  1. string和number:直接插入

  2. null,undefined,true,false:直接为空

  3. 数组:把数组的值按顺序放入虚拟DOM中

  4. 对象:对象不允许作为jsx插值中的值

  <script type="text/babel">
      const arr = ["Angular", "React", "Vue"];
      const vDOM = (
        <div>
          <h1>前端框架</h1>
          <ul>
            {arr.map((item, index) => {
             //每一个虚拟DOM变化的地方都有一个key值,以便以后改变的时候有对比参照
              return <li key={index}>{item}</li>;
            })}
          </ul>
        </div>
      );

      ReactDOM.render(vDOM, document.getElementById("box"));

2.React中组件

2.1 函数式组件

如果构造函数实例化后,其返回值:

  1. 如果构造函数里面没有return,或者return了一个基本数据类型,则函数返回一个实例化对象
  2. 如果构造函数内部返回了一个复杂数据类型,则函数实例化后,则函数返回这个复杂数据
<script type="text/babel">
    //1.声明一个函数式组件
    function Dome(){
        console.log(this);//undefined
        return <h1>我是用函数定义的组件</h1>
    }
    //2.渲染组件到页面 	ReactDOM.render(<Dome/>,getElementById('app'))
</script>

函数式组件定义

  1. 定义组件函数时,函数名首字母必须大写
  2. 该组件函数必须有返回值,返回值一般为虚拟DOM
  3. 渲染函数组件到页面中时,函数组件必须放到自结束标签中,<函数名 />

​ 函数式组件的特点

  1. 里面的this为undefined(在babel严格模式下)
  2. 没有生命周期
  3. 没有状态

使用函数组件的过程:

  1. 寻找组件申明,确认组件类型为函数组件
  2. 把函数组件给调用(一定不要自己调用函数,而是使用组件调用的方式,否则将不具备任何组件特征)
  3. 组件调用返回一个虚拟DOM,放到设置的位置中
  4. 将虚拟DOM转为真实DOM,并渲染到页面中

2.2 类式组件

2.1.1 类的基本知识

公有方法和属性:设置给实例化对象的属性和方法

私有方法和属性:声明在构造函数中的变量或函数

静态方法和属性:js中无需实例化就可以获得的的属性和调用的方法 就是给构造函数自己的属性和方法

//创建一个Person类
class Person{
    //构造器方法或函数
    constructor(name,age){
        //构造器中的this指向类的实例对象
        //公有属性
        this.name=name;
        this.age=age
    }
    //一般方法 
    //公有方法
    speak(){
        //speak方法放在了Person类的原型对象上,供实例使用
        //通过Person实例调用speak时,speak中的this就是Person实例
        
        console.log(`我叫${this.name},年龄是${this.age}`)
    }   
}
//创建一个Person的实例对象
const p1=new Person('tom',18)
const p2=new Person('jerry',20)


//创建一个Student类,继承于Person类
class Student extends Person{
    //若和Person类父类属性一致,不需要写构造器,也可以正常继承
    constructor(name,age,gender){
        //super方法,将与Person类父类属性一致的属性作为参数
        super(name,age)
        this.gender=gender
    }
   //重写从父类继承过来的方法
   speak(){
       console.log(`这是Student的原型对象,我叫${this.name},年龄是${this.age},gender是${this.gender}`)
   }
}
const s1=new Student('zs',21,'nan')
s1.speak();

2.1.2 类式组件
class Demo extends React.Component{
    render(){
        return <h1>我是标题</h1>
    }
}
ReactDOM.render(<Demo/>,document.getElementById('app'))

类式组件的定义:

  1. 使用class声明一个类组件,继承React.Component
  2. 在类组件中必须要有一个render方法,用来返回一个虚拟DOM

render方法:

  1. render方法定义在类组件中,属于类组件原型对象上的方法
  2. 当类组件被使用时,render方法就会被调用

使用类组件的过程:

  1. 寻找组件申明,确认组件类型为类组件
  2. 把类组件实例化,得到一个实例化对象(组件实例)
  3. 组件实例会调用类组件原型对象上的render方法,render方法返回一个虚拟DOM,放到设置的位置中
  4. 将虚拟DOM转为真实DOM,并渲染到页面中

3. 组件实例三大核心属性一:state

3.1 state基本写法

组件实例重要属性-state

  1. state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
  2. state代表的是当前组件的状态,状态中包含了当前组件需要的数据
  3. 如果虚拟DOM使用了状态中的数据,则修改状态中的数据,虚拟DOM会随之更新
  4. state设置给实例对象的,state需要定义在类的constructor中 this.state={XXX:XXX}

3.2 修改state的方法

方法:

  1. state不能直接修改,需要使用组件实例的setState方法
  2. setState接受的参数是一个对象,将来会合并给原有的state中

练习:


3.3 数量加减的练习


4. React绑定事件

4.1 基础绑定事件

class Demo extends React.Component{
    render(){
        return <button onClick={this.printWeather}>点击<button/>
    }
    //事件函数,位于Demo原型对象上
    printWeather(){
                console.log('今天天气好')
                console.log('this',this)//this为undefined
    }
            
 }
 ReactDOM.render(</Demo>,document.getElementById('app'))
   

事件定义:

  1. 命名采用小驼峰方法命名,放在绑定的标签中
  2. 被绑定的函数位于jsx的js{}区域
  3. 一般函数为原型上或实例上方法,需要用this.方法名调用,this不能漏了

这个基础绑定事件里面,有一个问题就是:React里面默认事件调用函数里面的this为undefined

4.2 绑定事件进阶

4.2.1 方法一
class Demo extends React.Component{
    render(){
        this.printWeather=this.printWeather.bind(this)
        return <button onClick={this.printWeather}>点击<button/>
    }
    //事件函数,位于Demo原型对象上
    printWeather(){
                console.log('今天天气好')
                console.log('this',this)//this为调用的实例对象
    }
            
 }
 ReactDOM.render(</Demo>,document.getElementById('app'))
4.2.1 方法二
class Demo extends React.Component{
    constructor(){
       super()//不可少,少了无法得到this
       this.printWeather=this.printWeather.bind(this)
    }
    render(){
        return <button onClick={this.printWeather}>点击<button/>
    }
    //事件函数,位于Demo原型对象上
    printWeather(){
                console.log('今天天气好')
                console.log('this',this)//this为调用的实例对象
    }
            
 }
 ReactDOM.render(</Demo>,document.getElementById('app'))

4.3 绑定事件和state简写

constructor函数的两个用法:

  1. 需要实例化的时候传参
  2. this指向组件实例

但是我们在未来react中基本不用实例化传参,直接在class语法中给一个变量赋值,这个变量就属于组件实例的属性

class Demo extends React.Component{
    //直接写在类class里面的属性,是实例的属性
   state={
       project:'js',
   }
   //事件函数的简写位置
   printWeather=this.printWeather.bind(this)
   render(){
        return <button onClick={this.printWeather}>点击<button/>
    }
    //事件函数,位于Demo原型对象上
    printWeather(){
                console.log('今天天气好')
                console.log('this',this)//this为调用的实例对象
    }
            
 }
 ReactDOM.render(</Demo>,document.getElementById('app'))

4.4 真正绑定事件写法

4.4.1 方法一

4.4.2 方法二

4.5 React事件的event事件对象

js事件:

  1. onput事件:当表单内容发生改变就会触发
  2. onchange事件:当表单内容发生改变并失去焦点的时候触发
  3. React的onChange事件是当前表单内容发生改变就会触发

React事件对象:

  1. 可以直接获取事件对象
  2. 不能使用return false来阻止默认事件,需要直接使用preventDefault()来阻止默认事件
  3. e.target可以获取当前的元素,就可以不用使用ref
      class App extends React.Component {
        render() {
          return (
            <div>
              <a href="http://www.baidu.com" onClick={(e)=>{e.preventDefault()}}></a>
              <button onClick={e=>{console.log(e.target.textContent)}}>点击可以获取内容</button>
              <input type="text" onChange={e=>{console.log(e.target.value)}} />
            </div>
          );
        }
      }
        
      ReactDOM.render(<App/>,document.getElementById('app'))

5. 组件实例三大核心属性二:props

5.1 基础的传值方式

props:

  1. 主要用于外部向组件内部传值使用
  2. 写法就是在组件标签上书写属性
  3. 接受props的组件,可以在组件实例上访问到props对象
  4. 不要修改props的值,props是只读的
class Myself extends React.Component{
    //组件实例内部,可以通过this.props拿到从外部传过来的值,不要修改props的值,props是只读的
    render(){
        console.log(this.props)//看下图1
        let {name,age,gender}=this.props.mes;
        //如果真的要修改值,则可以结构出来变量,然后对变量进行修改
        name+='~';
        return (
            <ul>
                <li>我的名字是{name}</li>
                <li>我的性别是{age}</li>
                <li>我的年龄是{gender}</li>
            </ul>
        )
    }
}
class App extends React.Component{
    state={
        persons:{
            [name:'zs',age:20,gender:'n'],
            [name:'ls',age:21,gender:'w'],
            [name:'ws',age:23,gender:'w'],
        }
    }
    render(){
        const {persons}=this.state;
        return (
            <div>
                <Myself mes={persons[0]}/>
                <Myself mes={persons[1]}/>
                <Myself mes={persons[2]}/>
            </div>
        )
    }
}
ReactDOM.render=(<App/>,document.getElementById('app'))

this.props 对象:(图一)

5.2 props传值

 class Myself extends React.Component {
        render() {
          console.log(this);
          console.log(this.props);
          const { name, age, gender } = this.props.mes;
          return (
            <ul>
              <li>姓名是:{name}</li>
              <li>年龄是:{age}</li>
              <li>性别是:{gender}</li>
            </ul>
          );
        }
      }
      class App extends React.Component {
        state = {
          persons: [
            { name: "zs", age: 20, gender: "nan" },
            { name: "ls", age: 18, gender: "wn" },
            { name: "wl", age: 25, gender: "nan" },
          ],
        };
        render() {
          const { persons } = this.state;
          return (
            <div>
              {persons.map((item, index) => {
                //每一个虚拟DOM变化的地方都有一个key值,以便以后改变的时候有对比参照
                return <Myself mes={item} key={index} />;
              })}
            </div>
          );
        }
      }

5.3 props批量传值

{…obj} 在jsx中书写时,可以展开对象为key-value(jsx+react实现的,不是js语法)

 class Myself extends React.Component {
        render() {
          console.log(this);
          console.log(this.props);
          const { name, age, gender } = this.props;
          return (
            <ul>
              <li>姓名是:{name}</li>
              <li>年龄是:{age}</li>
              <li>性别是:{gender}</li>
            </ul>
          );
        }
      }
      class App extends React.Component {
        state = {
          persons: [
            { name: "zs", age: 20, gender: "nan" },
            { name: "ls", age: 18, gender: "wn" },
            { name: "wl", age: 25, gender: "nan" },
          ],
        };
        render() {
          const { persons } = this.state;
          return (
            <div>
              {persons.map((item, index) => {
                // {...obj}在jsx中书写时,可以展开对象为key-value(jsx+react实现,不是js语法)
                // 后面再给组件添加属性,也没有影响,this.props会直接展开为一个对象
                return <Myself {...item} index={index} key={index} />;
              })}
            </div>
          );
        }
      }

5.4 配置props限制

使用:

  1. 引入第三方包
  2. 设置为要传入值的构造函数的静态属性 class类组件里面可以static配置或外面构造函数的静态属性
      class Myself extends React.Component {
        static propTypes = {
          name: PropTypes.string.isRequired,
          age: PropTypes.number,
          gender: PropTypes.string,
          gender: PropTypes.oneOf(["nan", "wn"]),
        };
        render() {
          console.log(this);
          const { name, age, gender } = this.props;
          return (
            <ul>
              <li>姓名是:{name}</li>
              <li>年龄是:{age}</li>
              <li>性别是:{gender}</li>
            </ul>
          );
        }
      }

      //   Myself.propTypes={
      //     name:PropTypes.string.isRequired,
      //     age:PropTypes.number,
      //     gender:PropTypes.string,
      //     gender:PropTypes.oneOf(['nan','wn'])
      //   }
      class App extends React.Component {
        state = {
          persons: [
            { name: "zs", age: 20, gender: "nan" },
            { name: "ls", age: 18, gender: "wn" },
            { name: "wl", age: 25, gender: "nan" },
          ],
        };
        render() {
          const { persons } = this.state;
          return (
            <div>
              {persons.map((item, index) => {
                return <Myself {...item} key={index} />;
              })}
            </div>
          );
        }
      }

5.5 函数式组件的props写法

过程:

  1. 判断组件类型,确认为函数式组件
  2. 判断为函数式组件后,则调用函数
  3. 将组件中的属性合并到一个对象传给函数作为参数
function Myself({ name, age, gender }) {
        return (
          <ul>
            <li>姓名是:{name}</li>
            <li>年龄是:{age}</li>
            <li>性别是:{gender}</li>
          </ul>
        );
      };

      Myself.propTypes = {
        name: PropTypes.string.isRequired,
        age: PropTypes.number,
        gender: PropTypes.string,
      };

      const persons = [
        { name: "zs", age: 20, gender: "nan" },
        { name: "ls", age: 18, gender: "wn" },
        { name: "wl", age: 25, gender: "nan" },
      ];

      function App() {
        return (
          <div>
            {persons.map((item, index) => {
              let { name, age, gender } = item;
              return (
                <Myself name={name} age={age} gender={gender} key={index} />
              );
            })}
          </div>
        );
      };

      ReactDOM.render(<App />, document.getElementById("app"));

6. 组件实例三大核心属性三:refs

使用情景:

  1. 管理焦点,文本选择或媒体播放
  2. 触发强制动画
  3. 集成第三方DOM库

6.1 refs的字符串方式-方法一:

基本步骤:字符串方式

  1. refs主要是React用来操作DOM的
  2. ref的字符串方法,只需要在备货的DOM上设置ref属性,值为一个自定义名称XXX 类似于设置ID给标签
  3. 在当前组件的其他位置可以通过this.refs.XXX(设置的名称)获取当前DOM
      class App extends React.Component {
        render() {
          console.log(this);
          return (
            <div>
              <input type="text" ref="oIpt" />
              <button onClick={this.printMsg}>打印输出内容</button>
            </div>
          );
        }
        printMsg = () => {
          console.log(this.refs.oIpt.value);
          console.log(this.refs);
        };
      }
	ReactDOM.render(<App />, document.getElementById("app"));   

6.2 refs的回调函数方式-方法二

基本步骤:回调形式

  1. 给被获取的DOM设置ref属性
  2. ref属性的值是一个函数(箭头函数)
  3. 当读取到ref属性时,React会将ref属性的回调函数调用,并传递当前的DOM为实参
  4. 把这个接受实参的形参赋值给实例对象的一个属性,这个属性就是被获取的DOM
      class App extends React.Component {
        render() {
          console.log(this);
          return (
            <div>
              <input type="text" ref={(c) => (this.oIpt = c)} />
              <button onClick={this.printMsg}>打印输出内容</button>
            </div>
          );
        }
        printMsg = () => {
          console.log(this.oIpt);
          console.log(this.oIpt.value);
          console.log(this.refs);
        };
      }
	ReactDOM.render(<App />,document.getElementById("app"));

6.3 refs的创建容器方式-方法三

基本步骤:创建容器方式

  1. 首先使用React.createRef()方法创建一个容器
  2. 把这个容器给到要被获取的DOM节点的ref属性上
  3. 通过this.容器.current获取到当前的DOM
      class App extends React.Component {
        //设置一个ref的容器
        oIpt = React.createRef();
        render() {
          console.log(this);
          return (
            <div>
              <input type="text" ref={this.oIpt} />
              <button onClick={this.printMsg}>打印输出内容</button>
            </div>
          );
        }
        printMsg = () => {
          console.log(this.oIpt);
          console.log(this.oIpt.current.value);
          console.log(this.refs);
        };
      }

      ReactDOM.render(<App />, document.getElementById("app"));

7.React收集表单数据

7.1 非受控表单

     class Demo extends React.Component {
        render() {
          return (
            <form action="###">
            用户名:
            <input type="text" ref={(c) => (this.user = c)} />
            <br />
            密码:
            <input type="text" ref={(c) => (this.pass= c)} />
            <br />
            <button onClick={this.login}>登录</button>
          </form>
          )

        }

        login = (e) => {
          e.preventDefault();
          console.log(`用户名是${this.user.value},密码是${this.pass.value}`);
        };
      }

7.2 受控表单

 class Demo extends React.Component {
        state = {
          user: "",
          pass: "",
        };
        render() {
          return (
            <form action="###">
              用户名:
              <input type="text" onChange={this.setUser} />
              <br />
              密码:
              <input type="text" onChnage={this.setPass} />
              <br />
              <button onClick={this.login}>登录</button>
            </form>
          );
        }
        setUser = (e) => {
          this.setState({ user: e.target.value });
        };

        setPass = (e) => {
          this.setState({ user: e.target.value });
        };

        login = (e) => {
          e.preventDefault();
          const { user, pass } = this.state;
          console.log(`用户名是${user},密码是${pass}`);
        };
      }

7.3 受控表单高阶写法


      class Demo extends React.Component {
        state = {
          user: "",
          pass: "",
        };
        render() {
          return (
            <form action="###">
              用户名:
              <input type="text" onChange={this.setFormData("user")} />
              <br />
              密码:
              <input type="text" onChange={this.setFormData("pass")} />
              <br />
              <button onClick={this.login}>登录</button>
            </form>
          );
        }

        setFormData = (type) => {
          return (e) => {
            this.setState({ [type]: e.target.value });
          };
        };

        login = (e) => {
          e.preventDefault();
          const { user, pass } = this.state;
          console.log(`用户名是${user},密码是${pass}`);
        };
      }

7.4 高阶函数和函数柯里化

高阶函数:如果有函数A,A只需满足以下2个条件中任意一个,A就是高阶函数

  1. 若A函数接受的参数是一个参数,例如数组相关方法,promise,setTimeout
  2. 若A函数调用后,返回值任然是一个函数,例如防抖节流函数

函数柯里化:通过函数调用,继续返回函数的方式,实现多次接受参数的函数形式

      // 函数柯里化
      function add(a) {
        return function (b) {
          return a + b;
        };
      }
      add(1)(2);

8. React组件生命周期

8.1 生命周期引入

 <div id='app'></div>
  <script type='text/babel'>
    class App extends React.Component{
      state = {
        opacity : 1
      }

      componentDidMount(){
        let {opacity} = this.state
        console.log(opacity);
        this.timer = setInterval(()=>{
          opacity -= 0.1;
          if(opacity<=0){
            opacity = 1
          }
          this.setState({opacity})
        },200)
      }

      render(){
        const {opacity} = this.state;
        return (
          <div>
            <p style={{opacity:opacity}}>React 太简单了,都是对勾</p>  
            <button onClick={()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}}>从入门到放弃</button>
          </div>
        )
      }

      componentWillUnmount(){
        clearInterval(this.timer)
      }
    }
    ReactDOM.render(<App/>,document.getElementById('app'))

8.2 生命周期挂载流程

初始化阶段由ReactDOM.render()触发—初次渲染

若触发流程5,组件卸载不再呈现在页面中

  1. React组件挂载流程1-构造器constructor()
  2. React组件挂载流程2-React组件即将挂载 componentWillMount()
  3. React组件挂载流程3-渲染render()
  4. React组件挂载流程4-React组件已经挂载完成componentDidMount()
  5. React组件挂载流程5-React组件即将卸载componentWillUnmount() ,由ReactDOM.unmountComponentAtNode()触发,参数为组件卸载的父节点
 class App extends React.Component {
        // 挂载流程1 :constructor构造器
        constructor() {
          super();
          console.log("constructor 执行了");
        }

        // 挂载流程2 :React组件即将挂载
        componentWillMount() {
          console.log("componentWillMount执行了");
        }

        // 挂载流程3:React组件渲染
        render() {
          console.log("render 执行了");
          return (
            <div>
              <p>更新阶段 由组件内部this.setSate()或父组件重新render触发</p>
              <button
                onClick={() => {
                  ReactDOM.unmountComponentAtNode(
                    document.getElementById("app")
                  );
                }}
              >
                从入门到放弃
              </button>
            </div>
          );
        }

        // 挂载流程4:React组件已经完成挂载
        componentDidMount() {
          console.log(" componentDidMount执行了");
        }

        // 挂载流程5:React组件即将卸载 由ReactDOM.unmountComponentAtNode()触发,参数为组件从哪里卸载
        componentWillUnmount() {
          console.log(" componentWillUnmount执行了");
        }
      }
      ReactDOM.render(<App />, document.getElementById("app"));

8.3 生命周期更新流程

由组件内部this.setSate()或父组件重新render触发

  1. React组件更新流程1-阀门,可以控制state更新后,render函数是够渲染 shouldComponentUpdate() 必须返回布尔值 return true (渲染)/false(不渲染);此处若是false,后面的流程2-4不会触发执行

  2. React组件更新流程2-组件将要更新 componentWillUpdate() , this.forceUpdate()可以触发强制更新

    如果流程触发了强制更新,前面流程1-shouldComponentUpdate() 不管返回什么,都不会生效执行

  3. React组件更新流程3-渲染render()

  4. React组件更新流程4-组件完成更新 componentDidUpdate()

  5. React组件更新流程5-React组件即将卸载componentWillUnmount(),由ReactDOM.unmountComponentAtNode()触发,参数为组件卸载的父节点

class App extends React.Component {
        // 挂载流程1 :constructor构造器
        constructor() {
          super();
          console.log("constructor 执行了");
        }

        state = {
          count: 0,
        };

        // 挂载流程2 :React组件即将挂载
        componentWillMount() {
          console.log("componentWillMount执行了");
        }

        // 挂载流程3:React组件渲染
        render() {
          console.log("render 执行了");
          let { count } = this.state;
          return (
            <div>
              <h1>{count}</h1>
              <p>更新阶段 由组件内部this.setSate()或父组件重新render触发</p>
              <button onClick={() => {this.setState({count:++count})}}>+</button>
              <br />
              <button onClick={() => {this.forceUpdate()}}>强制更新</button>
              <button
                onClick={() => {
                  ReactDOM.unmountComponentAtNode(
                    document.getElementById("app")
                  );
                }}
              >
                从入门到放弃
              </button>
            </div>
          );
        }

        // 挂载流程4:React组件已经完成挂载
        componentDidMount() {
          console.log(" componentDidMount执行了");
        }
        //更新流程2:阀门,可以控制state更新后,render函数是否渲染
        shouldComponentUpdate() {
          console.log("---componentShouldUpdate执行了---");
          return true;
        }

        // 更新流程3:即将更新 this.forceUpdate()方法可以要求强制更新
        componentWillUpdate() {
          console.log("---componentWillUpdate执行了---");
        }

        // 更新流程4:更新已完成 
        componentDidUpdate(){
            console.log("---componentDidUpdate执行了---");
        }

        // 挂载流程5:React组件即将卸载 由ReactDOM.unmountComponentAtNode()触发,参数为组件从哪里卸载
        componentWillUnmount() {
          console.log(" componentWillUnmount执行了");
        }
      }

      ReactDOM.render(<App />, document.getElementById("app"));

8.4 生命周期父传子更新流程

子中更新流程新增:componentWillReceiveProps()

  1. 初次渲染过程,父与子正常渲染,子渲染流程是不会执行上面的生命函数的;
  2. 后面父组件只要重新渲染,无论是否接受父组件的props都要执行这个生命周期函数,而且所有更新流程也要执行
 class App extends React.Component {
        state = {
          weather: "hot",
          count: 0,
        };

        render() {
          let { weather ,count } = this.state;
          return (
            <div>
                <p>{weather},{count}</p>
                <button onClick={()=>{this.setState({weather:'cool'})}}>改变天气</button>
                <br/>
                <button onClick={()=>{this.setState({count:++count})}}>改变count</button>
                <p>我是父组件 我下边是子组件</p>
                <Son />
            </div>
            );
        }
        }
                


      class Son extends React.Component{
          render (){
              return (
                  <div>
                    <button onClick={()=>{ReactDOM.unmountComponentAtNode(document.getElementById('app'))}}>卸载组件</button>
                </div>
                     
              )
            }
            componentWillMount(){
                console.log("即将渲染了");
            }
    
            componentDidMount(){
                console.log("已经渲染了");
            }
    
            //此步骤:子组件渲染流程的时候是不执行的
            // 父组件只要重新渲染,无论是否接受父组件的props都要执行这个生命周期函数
            componentWillReceiveProps(){
                console.log('即将接受props');
            }
    
    
            shouldComponentUpdate(){
                console.log("---shouldComponentUpdate---");
                return false;
            }
    
            componentWillUpdate(){
                console.log("---componentWillUpdate---");
            }
    
            componentDidUpdate(){
                console.log('---componentDidUpdate---');
            }
    
            componentWillUnmount(){
                console.log('---componentWillUnmount---');
            }
        }
        ReactDOM.render(<App />, document.getElementById("app"));

9.虚拟DOM和DOM Diffing算法

Diffing算法

 /* 
      //旧
      <li key=0>laowang input</li>
      <li key=1>laozhang input</li>
      <li key=2>laojun input</li>

      //新
      <li key=4>laoyang input</li>
      <li key=0>laowang input</li>
      <li key=1>laozhang input</li>
      <li key=2>laojun input</li>
      
    
    
    
    
    */
    class App extends React.Component{
      state = {
        person:[

          {id:"001",name:"laowang"},
          {id:"002",name:"laozhang"},
          {id:"003",name:"laojun"}
        ]
      }
      render(){
        const {person}  = this.state
        return (
          <div>
            <button onClick={this.addPerson}>添加</button> 
            <ul>
              {
                person.map((item,index)=>{
                  return <li key={item.id}>{item.name} <input type="text"/></li>
                })
              }   
            </ul>
          </div>
        )
      }

      addPerson = () => {
        const {person} = this.state;
        person.unshift({id:"004",name:"laoyang"})
        this.setState({person})
      }
    }
    ReactDOM.render(<App/>,document.getElementById('app'))

10.脚手架

10.1 useState

步骤:

  1. const [要存的变量名,修改变量的方法名]=useState(变量内容)
  2. 用useContext暴露达到传递的目的

10.2 useContext

步骤:

  1. 父组件 createContext
  2. 利用createContext()创造对应实例组件对象,同时将其暴露出去
  3. 将要传数据的子组件放在<实例组件对象名.Provider><实例组件对象名.Provider/>组件标签中
  4. 该组件标签上有一属性value,可以填写要传给子组件的数据 value={{}}
  5. 子组件里引入useContext ,用useContext(实例组件对象名),接收数据

10.3 useEffect

用法:

  1. useEffect通用副作用函数,可以取代生命周期中的componentDidMount、componentDidUpdate、componentWillUnmount
  2. useEffect接受的第一个参数是函数,如果没有第二个参数的情况下,无论是更新还是初始挂载都会执行这个函数
  3. useEffect接受第二个参数是数组,可以限定数组中哪一个状态变化的时候,再执行useEffect的函数,如果是空数组,则无论状态怎么更新,都不会再次执行
  4. 可以设置多个useEffect,也建议不同的功能有不同的useEffect
  5. useEffect返回一个函数,当这个组件被卸载之前,会调用这个函数

10.4 React-Router-DOM旧版本

10.4.1 基础配置
  • 在 App 组件外层嵌套一个 BrowserRouter 组件
  • 所有导航使用 Link 组件 内部是 to 属性定义路由地址
  • 路由展示区域使用 Route 组件,path 用来对应路径 component 属性用来确定组件
10.4.2 NavLink
  • 当导航组件点击需要切换样式的时候,可以给导航使用 NavLink 组件
  • NavLink 组件提供 activeClassName 属性,里边放的是获取焦点后应该加载的类
10.4.3 自定义 Link 组件
  • 自定一个 Link 组件,通过 props 传值进即可
  • 组件的标签内的内容 也是可以在 props.children 中得到的
10.4.4 Switch 组件
  • 可以把多个 Route 放在一个 Switch 组件中,此时只要匹配到一个 Route,则退出整个 Switch
  • 可以拥有多个 Switch
10.4.5 严格匹配
  • 在 Route 组件上有一个 exact 属性,值是布尔值,负责开启严格匹配
  • 严格匹配:(to:/home/news) (path:/home) 此时是无法匹配的
  • 我们一般不开启严格匹配,否则二级路由无法访问
10.4.6 Redirect
  • 重定向
  • 当所有的 Route 没有完成匹配的时候,则自动走 Redirect 组件,Redirect 组件把地址重定向到我们预设的一个默认地址
10.4.7 组件划分
  • 路由组件(pages)和一般组件(components)
  • 一般组件的 props 就是我们传的值
  • 路由组件的 props 是由 history location match 等对象组成的一个对象,提供了很多操作路由的方法
10.4.8 二级和三级路由
  • 正常向一级一样书写即可
  • 路由切换的时候 默认是组件创建和销毁
10.4.9 params 路由传参
  • 路由导航书写接受参数的变量 /user/:id/:say
  • Link 中的路径中拼接需要数据 /user/001/hello
  • 在路由组件中 使用 props.match.params 得到想要的数据
10.4.10 search 路由传参
  • 路由导航正常书写路径
  • 在 Link 的路径中拼接数据为查询字符串
  • 在路由组件中 使用 props.location.search 得到想要的查询字符串
  • 通过 qs 工具 转为对象
10.4.11 state 路由传参
  • 路由导航的 to 属性写成对象 {pathname:路由路径 state:数据}
  • 在路由组件中 通过 props.location.state 得到想要的数据
10.4.12 编程式路由导航
  • Link 默认转为 a 标签,很多时候不用 a 标签,或者不用点击等情况下需要路由跳转
  • props.history.push(path,state)进行编程式路由导航
10.4.13 replace
  • 声明式路由导航中 使用Link组件的 replace属性为boolean值 来进行确定是否替换历史记录
  • 编程式路由导航中 使用props.history.push/replace方 法来确定是否留下历史记录
10.4.14 前进后退历史纪录
  • 使用props.history.go/goBack/goForward
10.4.15 withRouter
  • 可以让一般组件拥有路由组件的props对象
  • 暴露组件的时候 直接把组件名放在 withRouter方法中暴露出去

10.5 React-Router-DOM v6 版本

10.5.1 BrowserRouter
  • BrowserRouter组件最好放在最顶层所有组件之外,这样能确保内部组件使用 Link 做路由跳转时不出错(相比较 v5 没有变化)
10.5.2 Switch 重命名为 Routes
10.5.3 基础写法
  • Link 组件用来定义选项
  • Route 组件用来定义响应(route 内部加载的组件使用 element 属性 值为对应的组件标签)
  • NavLink组件styleclassName可以接收一个函数,函数接收一个isActive参数,可根据该参数调整样式
<NavLink
           to="/about"
           className={({ isActive }) => {
      			return isActive ? "list-group-item active" : "list-group-item";
      	}}
  >
      About
  </NavLink>
  <NavLink
           to="/home"
           className={({ isActive }) => {
      		return isActive ? "list-group-item active" : "list-group-item";
      	 }}
  >
      Home
  </NavLink>


  <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/home" element={<Home />} />
      <Route path="/about" element={<About />} />
  </Routes>
10.5.4 路由传参
  • params 传参
    • 传值方式不变
    • 接收值的方式
  import { useParams } from "react-router-dom";
    console.log(useParams());
  • search 传参
    • 传值方式不变
    • 接收值的方式
   import { useLocation } from "react-router-dom";
    console.log(useLocation());
  • state 传参
    • 使用编程式路由导航
import { useNavigate } from "react-router-dom";
    <button
      onClick={() => {
        to("/list", { state: { say: "byebye" } });
      }}
    ></button>;

​ 接收值的方式

import { useLocation } from "react-router-dom";
    console.log(useLocation());
  • 二级路由
    • 在一级路由的 Route 中书写 path 为:<Route path="/about/*" element={<About />} />
    • 在二级路由的时候
 <h3>我是About的内容</h3>
    <Link to="/about/hello">hello</Link>
    <Link to="/about/world">world</Link>

    <Routes>
        <Route path="hello" element={<Hello />}></Route>
        <Route path="world" element={<World />}></Route>
    </Routes>

正则:

正则对象调用test方法,传入字符串,返回布尔值 (看符不符合正则要求)

字符串:

字符串调用match方法,传入正则规则,返回符合要求的字符串组成的数组

调用replace方法,替换关键字

正则表达式方法

字符串方法

数组方法

对象方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值