12.4 axios的二次封装-深拷贝

axios的二次封装 - 配置一个axios

api-config.js

JavaScript 复制代码
import axios from "axios";
axios.defaults.baseURL="http://localhost:3000";
axios.interceptors.request.use(
    config=>{
        console.log("请求拦截器1调用成功");
        return config;
    },
    function(error){
        console.log("请求拦截器1调用失败");
        return Promise.reject(error)
    }
)
//这个是设置响应拦截器的api,第一个成功回调,第二个失败回调
axios.interceptors.response.use(
    function(response){
        console.log("响应拦截器1调用成功");
        return response;
    },
    function(error){
        console.log("响应拦截器1调用失败");
        return Promise.reject(error);
    }
)
export default axios;

api-request.js

JavaScript 复制代码
import axios from "./config";
// 向/goodList发送get请求
export function getGoodList(){
    return axios({
        // http://localhost:3000/goodList
        url:'/goodList',
        method:"get"
    })
}

Index.vue 调用请求

JavaScript 复制代码
async function getData(){
  // 原来调用方式
  // let {data} = await axios({
  //    url:"http://localhost:3000/goodList",
  //    method:"get"
  // })
  // console.log(data);

  // 封装后调用方式
  let data = await  getGoodList();
  console.log(data);
}

onMounted(()=>{
  getData()
})

axios的二次封装 - 配置多个axios

api/config.js

JavaScript 复制代码
import axios from "axios";

// 配置的json-server
const http = axios.create({
    baseURL: 'http://127.0.0.1:3001',
    timeout: 1000,
    headers: {'X-Custom-Header': 'foobar'}
});
http.interceptors.request.use(
    config=>{
        console.log("json-server请求拦截器");
        return config;
    },
    function(error){
        console.log("请求拦截器1调用失败");
        return Promise.reject(error)
    }
)

// 配置nodejs
const httpnode = axios.create({
    baseURL: 'http://127.0.0.1:3000',
    timeout: 1000,
    headers: {'X-Custom-Header': 'foobar'}
});
httpnode.interceptors.request.use(
    config=>{
        console.log("httpnode请求拦截器");
        return config;
    },
    function(error){
        console.log("请求拦截器1调用失败");
        return Promise.reject(error)
    }
)

export {
    http,
    httpnode
}

api/request.js

JavaScript 复制代码
import { http,httpnode } from "./configAll";

// 获取goodsList中的数据
export function goodList(){
    return http({
        url:"/goodList",
        method:"get"
    })
}

// 获取nodejs中的数据
export function goodFloower(){
    return httpnode({
        url:"/hua/getFloower",
        method:"get"
    })
}

index.vue调用方法

HTML 复制代码
<script setup>
import TabBar from "@/components/global/common/TabBar.vue"
import { goodList,goodFloower } from "../../api/requestAll";
import { onMounted } from "vue";
onMounted(async()=>{
   // 获取json-serve染数据
   let data = await goodList();
   console.log(data);
   
   // 获取nodejs中的数据
   let datanode = await goodFloower();
   console.log(datanode);
   
})
</script>

扩展:参考企业axios封装

请求封装

![[b5b9288a-836d-44e7-92a2-78a50feb70c9.png]]

响应封装

![[2d4a8c59-ecb1-47fb-8a87-418ef0a5d42c.png]]

深拷贝

什么是****深拷贝

在Javascript中,对象的复制有两种方式: 浅拷贝和深拷贝。 浅拷贝只拷贝内存地址,拷贝后的对象和原始对象引用同一个地址,所以修改拷贝后的对象会影响到原始对象。

深拷贝是指将一个对象完全复制到另一个对象中,包括对象的所有属性和方法。与浅拷贝不同,深拷贝会递归地复制对象的所有属性和方法,直到所有属性和方法都被复制完毕。因此,深拷贝可以保证复制后的对象与原始对象完全独立,互不影响。

如何实现****深拷贝

  1. 使用扩展运算符

只能实现第一层的深拷贝,不能实现深层级对象的深拷贝

JavaScript 复制代码
//--------------------------------------数组
  let arr1 = [2, 5, 6]
  let arr2 = arr1  // 浅拷贝
  let arr3 = [...arr1] //深拷贝
  //---------------------------------------对象
  // *************************demo1
  //浅拷贝
  // let obj1 = { a: 1, b: 2 };
  // let obj2 = obj1
  // obj2.a = 10
  // console.log(obj1.a); //10
  //深拷贝
  // let obj1 = { a: 1, b: 2 };
  // let obj2 = {...obj1}   // obj2 = { a: 1, b:2}
  // obj2.a = 10
  // console.log(obj1.a); // 1
  // *************************demo2
  //浅拷贝
  let obj1 = { a: { c: 1 }, b: 2 };
  let obj2 = {...obj1}
  obj2.a.c = 10
  console.log(obj1.a.c); //10
  1. 使用 Object.assign()

object.assign()主要用于对象合并,将源对象中的属性复制到目标对象中,他将返回目标对象。 同扩展运算符一样,只能实现对象第一层的深拷贝

JavaScript 复制代码
//深拷贝
// let obj1 = { a: 1, b: 2 };
// let obj2 = Object.assign({},obj1)
// obj2.a = 10
// console.log(obj1.a); // 1
//浅拷贝
let obj1 = { a: { c: 1 }, b: 2 };
let obj2 = Object.assign({},obj1)
obj2.a.c = 10
console.log(obj1.a.c); //10
  1. JSON.parse(JSON.stringify())

这种方式简单易用,大部分情况可用

JavaScript 复制代码
let obj = { a: { b: 1 } };
let clone = JSON.parse(JSON.stringify(obj));clone.a.b = 2;console.log(obj.a.b); // 1

缺点 (自行了解) 参考 https://blog.csdn.net/m0_54566205/article/details/129561012

  1. 无法处理函数和 undefined

  2. 无法处理循环引用

  3. 无法处理一些特殊对象,如 RegExp、Error、Date 等,这些对象会被转换成空对象

  4. 对象的原型链上的属性会丢失

  5. 使用****递归 (最重要)

JavaScript 复制代码
var obj = {
    a: 1,
    b: [1, 2, 3],
    c: {
        c1: 1
    }
}
function deepClone(obj) {
    //如果不是对象,直接返回
    if (obj === null || typeof obj !== "object") return obj;

    //判断是不是数组
    let clone = Array.isArray(obj) ?[] : {};
    for (let key in obj) {
        //判断key是不是自身的属性而不是原型的
        if (obj.hasOwnProperty(key)) {
            //递归
            clone[key] = deepClone(obj[key])
        }
    }
    return clone
}
let obj1 = deepClone(obj);
obj1.b.push(4);
console.log(obj.b, obj1.b);//[1,2,3] [1,2,3,4]
  1. 使用 lodash 的 _.cloneDeep()

Lodash 提供了深拷贝方法 _.cloneDeep(),我们可以直接使用:

JavaScript 复制代码
let obj = { a: { b: 1 } };

let clone = _.cloneDeep(obj);
clone.a.b = 2;console.log(obj.a.b); // 1

菜单的滚动效果

better-scroll网站:https://better-scroll.github.io/docs-v1/doc/zh-hans/options.html

业务逻辑-js部分

HTML 复制代码
<script setup>
// 引入底部tabbar
import TabBar from '@/components/global/common/TabBar.vue';
import { nextTick, onMounted, ref } from 'vue';
import { getGoods } from '../../api/request';
import BScroll from 'better-scroll';

let goods = ref([]);
let curIndex = ref(0);
let foodList = ref([]);
let listHeight = ref([]);

let menuScroll;
let foodScroll;
let timer;

async function init(){
   let {data} = await getGoods();
   goods.value = data;
   // console.log(data);

   nextTick(()=>{
      menuScroll = new BScroll(".left",{
         click:true // 滚动
      })
      foodScroll = new BScroll(".right",{
         probeType:2, // 绑定事件,获取定位
         click:true
      })

      // 获取所有高度
      listHeight = foodList.value.map(item=>item.offsetTop)
      
      // 给foodScroll绑定滚动事件
      foodScroll.on("scroll",pos=>{
         // 防抖效果
         clearInterval(timer);
         timer = setTimeout(()=>{
            // console.log(pos);
            // 滚动效果
            getIndex(pos);
         },300)
      })
   })
}

function getIndex(pos){
   let y = Math.abs(pos.y);
   let len = listHeight.length;
   let index;
   for(let i=0;i<len-1;i++){
      if(y>=listHeight[i] && y<listHeight[i+1]){
         index = i;
         break;
      }
   }

   if(index === undefined){
      index = len - 1;
   }
   curIndex.value = index;
}

onMounted(()=>{
   init();
})

function toggle(index){
   // 变成红色背景
   curIndex.value = index;
   // 点击左侧,右侧内容滚动
   foodScroll.scrollToElement(foodList.value[index],800);
}
</script>

页面布局-template

HTML 复制代码
<template>
   <div class="car">
      <h1>购物车页面</h1>
      <div class="order">
         <div class="left">
            <ul>
               <li
               @click="toggle(index)" 
               v-for="(item,index) in goods" 
               :key="index"
               :class="curIndex == index ? 'active':''"
               >{{item.name}}</li>
            </ul>
         </div>
         <div class="right">
            <ul>
               <li v-for="(item,index) in goods" ref="foodList">
                  <p>{{item.name}}</p>
                  <ul>
                     <li v-for="(sitem,sindex) in item.foods">
                        <img :src="sitem.image" alt="">
                        <div class="text">
                           <p>名称:{{sitem.name}}</p>
                           <p>价格:{{sitem.price}}</p>
                        </div>
                     </li>
                  </ul>
               </li>
            </ul>
         </div>
      </div>
      
      <!-- tabbar -->
      <TabBar></TabBar>
   </div>
</template>

页面样式-css

HTML 复制代码
<style lang="scss" scoped>
.car{
   height: 900px;
   .jxhw{
      height: 100px;
      background-color: red;
      margin-top: 50px;
   }
}
.order{
   // 弹性盒子
   display: flex;
   position: absolute;
   top: 80px;
   bottom: 0;
   left: 0;
   right: 0;
   background-color: #eee;
   .left{
      width: 120px;
      background-color: #aaa;
      // overflow: scroll;
      overflow: hidden;
      li{
         padding: 5px;
         margin: 5px;
         height: 50px;
         border: 1px solid #eee;
      }
   }
   .active{
      background-color: red;
   }
   .right{
      // flex 是 flex-grow[放大比例]、flex-shrink【缩小比例】、flex-basis【剩余空间分配】的缩写
      flex: 120px 1;
      background-color: #fff;
      overflow: hidden;
      &>ul>li{
         &>p{
            height: 30px;
            border: 1px solid #aaa;
         }
         
         ul li{
            height: 70px;
            border: 1px solid #eee;
            margin: 10px;
            display: flex;
            padding: 10px;
            img{
               width: 50px;
               height: 50px;
            }
         }
         
      }
   }
}
</style>

vue.config.js的配置

  1. 认识vue.config.js
  • vue-cli@5 会自动创建vue.config.js

  • vue.config.js 是一个可选的配置文件,如果项目的 (和 package.json 同级的) 根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载。 从vue-cli3开始的一些服务配置都迁移到CLI Service里面了,对于一些基础配置和一些扩展配置需要在根目录新建一个vue.config.js文件进行配置

  1. 常用配置

特别特别需要注意的是只要vue.config.js进行了修改,就必须重启

vue.config.js

JavaScript 复制代码
const path = require('path')
// 工具函数,添加绝对路径
// dir: "./src/components"   ---- "E:/share/myapp/src/components"
function resolve(dir) {
  return path.join(__dirname, dir)
}
module.exports = {
  lintOnSave: false,// 禁用eslint检查
  //设置路径别名
  chainWebpack(config) {
    config.resolve.alias
      //用com这个别名代表./src/components的完整路径
      .set('com', resolve('./src/components'))
  }
}
  1. 在vue项目开发阶段实现跨域

如果后端没有设置cors,实现开发阶段跨域就需要在vue.config.js进行服务器代理的配置

  • 去掉后端跨域的代码
JavaScript 复制代码
//去掉以下代码
const cors = require("cors")
app.use(cors())
  • 在config.js中修改baseURL
Plain 复制代码
//原设置
baseURL: 'http://localhost:3000'
//修改为
baseURL: '/api'
  • 在vue.config.js的添加proxy代理
JSON 复制代码
devServer: {
  open: true, // 配置自动启动浏览器
    proxy: {
    '/api': {
      target: "http://localhost:3000/", //访问的服务器地址
        changeOrigin: true,
        ws: true, //启用websocket
        pathRewrite: {
        '^/api': ''  //替换规则
      }
    },
    '/admin': {
      target: "http://xx.xxx.xxx.xxx/",
        changeOrigin: true,
        ws: true,
        pathRewrite: {
        '^/admin': ''
      }
    }
  }
}
相关推荐
你真的可爱呀4 小时前
uniapp+vue3项目中的常见报错情况以及解决方法
前端·vue.js·uni-app
差点GDP8 小时前
模拟请求测试 Fake Rest API Test
前端·网络·json
酒尘&9 小时前
Hook学习-上篇
前端·学习·react.js·前端框架·react
houyhea9 小时前
从香港竹脚手架到前端脚手架:那些"借来"的发展智慧与安全警示
前端
哈哈~haha9 小时前
Step 14: Custom CSS and Theme Colors 自定义CSS类
前端·css·ui5
Ndmzi9 小时前
Matlab编程技巧:自定义Simulink菜单(理解补充)
前端·javascript·python
勇气要爆发10 小时前
物种起源—JavaScript原型链详解
开发语言·javascript·原型模式
我命由我1234510 小时前
VSCode - VSCode 修改文件树缩进
前端·ide·vscode·前端框架·编辑器·html·js
SoaringHeart10 小时前
Flutter组件封装:验证码倒计时按钮 TimerButton
前端·flutter