axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第1张图片

作者:东起

转发链接:https://zhuanlan.zhihu.com/p/103763164

目录

Vue常见的面试知识点汇总(上)「附答案」

Vue常见的面试知识点汇总(下)「附答案」本篇

由于Vue常见的面试知识点汇总内容比较多,本篇分为上下两部分。小编建议从上一篇看起

⑤ 服务器端SSR渲染

除了上面的方案以外,另一种方案也不容小视

我们先说说通常项目中是如何加载页面数据:Vue组件生命周期中请求异步接口,在mounted之前应该都可以,据我了解绝大部分同学是在mounted的时候执行异步请求。但是我们可以把页面需要的请求放到Vue-Router的守卫中执行,意思是在路由beforeEnter之前就可以请求待加载页面中所有组件需要的数据,此时待加载页面的Vue组件还没开始渲染,而Vue组件开始渲染的时候我们就可以用Vuex里面的数据了。

以上方法的实现思路:

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第2张图片

图意:每个页面(Page)中都会有很多个Vue组件,可以在Vue组件中添加自定义属性fetchData,fetchData里面可以执行异步请求(图中执行Vuex的Action),但是我们怎么获取到所有组件的fetchData方法并执行呢?如图所示,在router.beforeResolve守卫中,我们看看router.beforeResolve的定义,所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用,意思是即使页面中有异步组件,它会等待异步组件解析之后执行,并且解析守卫在beforeEnter之前执行。那我们怎么在解析守卫中获取到待加载页面的所有组件呢?通过router.getMatchedComponents方法。

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第3张图片
axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第4张图片

这样我们就可以在解析守卫中获取到所有待加载组件的fetchData方法并执行,这样无疑会在组件开始渲染之后获取到所有数据,提高页面加载速度。

很多人可能有个疑问,如果异步请求放在beforeCreate和created不是一样吗?答案是否定的,因为这种方式可以将异步请求放到beforeCreate之前!

22、你了解vue的diff算法吗?

推荐网站:https://www.cnblogs.com/wind-lanyan/p/9061684.html

23、vue能监听到数组变化的方法有哪些?为什么这些方法能监听到呢?

Vue.js观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse)

大家知道,通过Object.defineProperty()劫持数组为其设置getter和setter后,调用的数组的push、splice、pop等方法改变数组元素时并不会触发数组的setter,继而数组的数据变化并不是响应式的,但是vue实际开发中却是实时响应的,是因为vue重写了数组的push、splice、pop等方法

从源码中可以看出,ob.dep.notify()将当前数组的变更通知给其订阅者,这样当使用重写后方法改变数组后,数组订阅者会将这边变化更新到页面中

24、说说你对proxy的理解?

Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。

var target = {   name: 'zhangsan',   age:20,   sex:'男' }var logHandler = {  get(target, key) {    console.log(`${key}被读取`)    return target[key]   },  set(target, key, value) {    console.log(`${key}被设置为${value}`)    target[key] = value  }}var demo = new Proxy(target, logHandler)demo.name  //name被读取

var proxy = new Proxy(target, handler);

Proxy对象的所有用法,都是上面的这种形式。不同的只是handle参数的写法。其中new Proxy用来生成Proxy实例,target是表示所要拦截的对象,handle是用来定制拦截行为的对象。

我们可以将Proxy对象,设置到object.proxy属性,从而可以在object对象上调用。

var object = { proxy: new Proxy(target, handler) };

Proxy对象也可以作为其它对象的原型对象。

var proxy = new Proxy({}, {  get: function(target, property) {    return 35;  }});let obj = Object.create(proxy);obj.time // 35

上面代码中,proxy对象是obj的原型对象,obj本身并没有time属性,所以根据原型链,会在proxy对象上读取属性,从而被拦截。

同一个拦截函数,可以设置多个操作。

var handler = {  get: function (target, name) {    if (name === 'prototype') {       return Object.prototype;    }    return 'Hello, ' + name;  },   apply: function (target, thisBinding, args) {    return args[0];  },   construct: function (target, args) {    return { value: args[1] };  }}; var fproxy = new Proxy(function (x, y) {    return x + y;}, handler); fproxy(1, 2) // 1new fproxy(1, 2) // {value: 2}fproxy.prototype === Object.prototype // truefproxy.foo === "Hello, foo" // true

25、怎么缓存当前的组件?缓存后怎么更新?

{  path: '',  name: '',  component: ,  meta: {keepAlive: true} // 这个是需要keepalive的},{  path: '',  name: '',  component: ,  meta: {keepAlive: false} // 这是不会被keepalive的}

如果缓存的组件想要清空数据或者执行初始化方法,在加载组件的时候调用activated钩子函数,如下:

activated: function () {    this.data = '';}

26、axios怎么解决跨域的问题?

使用axios直接进行跨域访问不可行,我们需要配置代理

代理可以解决的原因:

因为客户端请求服务端的数据是存在跨域问题的,而服务器和服务器之间可以相互请求数据,是没有跨域的概念(如果服务器没有设置禁止跨域的权限问题),也就是说,我们可以配置一个代理的服务器可以请求另一个服务器中的数据,然后把请求出来的数据返回到我们的代理服务器中,代理服务器再返回数据给我们的客户端,这样我们就可以实现跨域访问数据

1.配置BaseUrl

import axios from 'axios'Vue.prototype.$axios = axiosaxios.defaults.baseURL = '/api'  //关键代码

2.配置代理

在config文件夹下的index.js文件中的proxyTable字段中,作如下处理:

proxyTable: { '/api': {   target:'http://api.douban.com/v2', // 你请求的第三方接口   changeOrigin:true, // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,//这样服务端和服务端进行数据的交互就不会有跨域问题   pathRewrite:{  // 路径重写,    '^/api': ''  // 替换target中的请求地址,也就是说以后你在请求http://api.douban.com/v2/XXXXX//这个地址的时候直接写成/api即可。   }  }}

1. 在具体使用axios的地方,修改url如下即可

axios.get("/movie/top250").then((res) => {  res = res.data  if (res.errno === ERR_OK) {    this.themeList=res.data;  } }).catch((error) => {  console.warn(error)})

原理:

因为我们给url加上了前缀/api,我们访问/movie/top250就当于访问了:localhost:8080/api/movie/top250(其中localhost:8080是默认的IP和端口)。

在index.js中的proxyTable中拦截了/api,并把/api及其前面的所有替换成了target中的内容,因此实际访问Url是http://api.douban.com/v2/movie/top250。

至此,纯前端配置代理解决axios跨域得到解决

27、怎么实现路由懒加载呢?

第一种(最常用):

const Foo = () => import('./Foo.vue')const router = new VueRouter({  routes: [    { path: '/foo', component: Foo }  ]})

第二种:

const router = new Router({  routes: [   {     path: '/index',     component: (resolve) => {        require(['../components/index'], resolve) // 这里是你的模块 不用import去引入了     }    }  ]})

第三种(官方推荐):

// r就是resolveconst list = r => require.ensure([], () => r(require('../components/list/list')), 'list');// 路由也是正常的写法  这种是官方推荐的写的 按模块划分懒加载 const router = new Router({  routes: [  {    path: '/list/blog',    component: list,    name: 'blog'  } ]})

28、怎样动态加载路由?

一、思路

① 在vue-router对象中首先初始化公共路由,比如(首页,404,login)等

② 用户登陆成功后,根据用户的角色信息,获取对应权限菜单信息menuList,并将后台返回的menuList转换成我们需要的router数据结构

③ 通过router.addRouter(routes)方法,同时我们可以将转后的路由信息保存于vuex,这样我们可以在我们的SideBar组件中获取我们的全部路由信息,并且渲染我们的左侧菜单栏,让动态路由实现。

二、实现

① 初始化公共路由

//只显示主要代码export const routes= [ { path: '/login', component: () => import('@/views/login/index'), hidden: true }, { path: '/404', component: () => import('@/views/404'), hidden: true }]export default new Router({ scrollBehavior: () => ({ y: 0 }), routes: routes})

② 登陆成功后,获取菜单信息 menuList,并转换成router数组的结构

router.beforeEach((to, from, next) => { NProgress.start()//进度条包 npm安装 if (getToken()) {   /*有 token,已经登录成功*/  if (to.path === '/login') {   next({ path: '/' })   NProgress.done()   } else {   if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息    store.dispatch('GetInfo').then(res => { // 拉取user_info     const roles = res.roles     store.dispatch("GetMenu").then(data => {      initMenu(router, data);     });     next()    }).catch((err) => {     store.dispatch('FedLogOut').then(() => {      Message.error(err || 'Verification failed, please login again')      next({ path: '/' })     })    })   } else {    next()   }  } } else {  /* 无 token*/  if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入   next()  } else {   next('/login') // 否则全部重定向到登录页   NProgress.done()   } }})router.afterEach(() => { NProgress.done() })

③ 动态加载路由

import store from '../store'export const initMenu = (router, menu) => { if (menu.length === 0) {  return } let menus = formatRoutes(menu);  let unfound = { path: '*', redirect: '/404', hidden: true } menus.push(unfound) //404组件最后添加 router.addRoutes(menus) store.commit('ADD_ROUTERS',menus)}export const formatRoutes = (aMenu) => { const aRouter = [] aMenu.forEach(oMenu => {  const {   path,   component,   name,   icon,   childrens  } = oMenu  if (!validatenull(component)) {   let filePath;   const oRouter = {    path: path,    component(resolve) {     let componentPath = ''     if (component === 'Layout') {      require(['../views/layout/Layout'], resolve)      return     } else {      componentPath = component     }     require([`../${componentPath}.vue`], resolve)    },    name: name,    icon: icon,    children: validatenull(childrens) ? [] : formatRoutes(childrens)   }   aRouter.push(oRouter)  } }) return aRouter}

④ 渲染菜单

就这样我们动态加载路由就是实现了,关键点就是router.addRoute方法

⑤ 防坑

点击刷新的时候页面空白 控制台也不报错?

点击刷新,vue-router会重新初始化,那么我们之前的动态addRoute就不存在了,此时访问一个不存在的页面,所以我们的sidebar组件也就不会被访问,那么也无法获取菜单信息,就导致页面空白。所以我们需要把加载菜单信息这一步放在router的全局守卫beforeEach中就可以了。

export const initMenu = (router, menu) => { if (menu.length === 0) {  return } let menus = formatRoutes(menu); // 最后添加 let unfound = { path: '*', redirect: '/404', hidden: true } menus.push(unfound) router.addRoutes(menus) store.commit('ADD_ROUTERS',menus)}//404组件一定要放在动态路由组件的最后,不然你刷新动态加载的页面,会跳转到404页面的

29、切换到新路由时,页面要滚动到顶部或保持原先的滚动位置怎么做呢?

当创建一个 Router 实例,可以提供一个 scrollBehavior 方法:

注意: 这个功能只在 HTML5 history 模式下可用。const router = new VueRouter({ routes: [...], scrollBehavior (to, from, savedPosition) {  // return 期望滚动到哪个的位置 }})

scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

scrollBehavior (to, from, savedPosition) { return { x: 0, y: 0 }}对于所有路由导航,简单地让页面滚动到顶部。
返回 savedPosition,在按下 后退/前进 按钮时,在滚动条位置,就会像浏览器的原生表现那样:scrollBehavior (to, from, savedPosition) { if (savedPosition) {  return savedPosition } else {  return { x: 0, y: 0 } }}
模拟『滚动到锚点』的行为scrollBehavior (to, from, savedPosition) { if (to.hash) {  return {   selector: to.hash  } }}

还可以利用路由元信息更细颗粒度地控制滚动。

routes: [ { path: '/', component: Home, meta: { scrollToTop: true }}, { path: '/foo', component: Foo }, { path: '/bar', component: Bar, meta: { scrollToTop: true }}]const scrollBehavior = (to, from, savedPosition) => { if (savedPosition) {  return savedPosition } else {  const position = {}  if (to.hash) {   position.selector = to.hash  }   if (to.matched.some(m => m.meta.scrollToTop)) {   position.x = 0   position.y = 0  }  return position }}

还可以在main.js入口文件配合vue-router写这个

router.afterEach((to,from,next) => {  window.scrollTo(0,0);});

30、vue-router如何响应路由参数的变化?

当使用路由参数时,比如:

{path:’/list/:id’component:Foo}

从 /list/aside导航到 /list/foo,原来的组件实例会被复用。

因为两个路由都渲染同个组件Foo,比起销毁再创建,复用则更加高效。

不过,这也意味着组件的生命周期钩子不会再被调用

如果跳转到相同的路由还会报以下错误

bb03caa98ab36ecdd44e88743d1f3e2b.png

这个时候我们需要重写push方法,在src/router/index.js 里面import VueRouter from 'vue-router'下面写入下面方法即可

const routerPush = VueRouter.prototype.pushVueRouter.prototype.push = function push(location) {  return routerPush.call(this, location).catch(error=> error)}

如何响应不同的数据呢?

① 复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象

const User = {  template: '...',  watch: {    '$route' (to, from) {      // 对路由变化作出响应...    }  }}

② 使用beforeRouteUpdate

const User = {  template: '...',  beforeRouteUpdate (to, from, next) {    // react to route changes...    // don't forget to call next()  }}

注意:

(1)从同一个组件跳转到同一个组件。

(2)生命周期钩子created和mounted都不会调用。

31、vue模板中为什么以_、$开始的变量无法渲染?

名字以 _ 或 $开始的属性不会被 Vue 实例代理,因为它们可能与 Vue 的内置属性与 API 方法冲突。用 vm.$data._property 访问它们。

32、vue中,如何监听一个对象内部的变化?

方法①:对整个obj深层监听

watch:{ obj:{  handler(newValue,oldValue){   console.log('obj changed')  },  deep: true,//深度遍历  immediate: true //默认第一次绑定的时候不会触发watch监听,值为true时可以在最初绑定的时候执行 }}

方法② :指定key

watch: {    "dataobj.name": {      handler(newValue, oldValue) {        console.log("obj changed");      }    }  }

方法③:computed

computed(){ ar(){  return this.obj.name }}

33、v-for循环时为什么要加key?

key的作用主要是为了高效的更新虚拟DOM,是因为Virtual DOM 使用Diff算法实现的原因。

当某一层有很多相同的节点时,也就是列表节点时,Diff算法的更新过程默认情况下也是遵循以上原则。

比如一下这个情况

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第5张图片

我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的:

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第6张图片

即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?

所以我们需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点,找到正确的位置去插入新的节点。

axios vue 加载效果动画_Vue常见的面试知识点汇总(下)「附答案」_第7张图片

34、$nextTick用过吗,有什么作用?

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

解决的问题:有些时候在改变数据后立即要对dom进行操作,此时获取到的dom仍是获取到的是数据刷新前的dom,无法满足需要,这个时候就用到了$nextTick。

35、vue和react的区别是什么?

① React严格上只针对MVC的view层,Vue则是MVVM模式

② virtual DOM不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树.而对于React而言,每当应用的状态被改变时,全部组件都会重新渲染,所以react中会需要shouldComponentUpdate这个生命周期函数方法来进行控制

③ 组件写法不一样, React推荐的做法是 JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即'all in js'; Vue推荐的做法是webpack+vue-loader的单文件组件格式,即html,css,jd写在同一个文件;

④ 数据绑定: vue实现了数据的双向绑定,react数据流动是单向的

⑤ state对象在react应用中不可变的,需要使用setState方法更新状态;在vue中,state对象不是必须的,数据由data属性在vue对象中管理

推荐Vue学习资料文章:

《Kbone原理详解与小程序技术选型》

《为什么我不再用Vue,改用React?》

《让Jenkins自动部署你的Vue项目「实践」》

《20个免费的设计资源 UI套件背景图标CSS框架》

《Deno将停止使用TypeScript,并公布五项具体理由》

《前端骨架屏都是如何生成的》

《Vue原来可以这样写开发效率杠杠的》

《用vue简单写一个音乐播放组件「附源码」》

《为什么Vue3.0不再使用defineProperty实现数据监听?》

《「干货」学会这些Vue小技巧,可以早点下班和女神约会》

《探索 Vue-Multiselect》

《细品30张脑图带你从零开始学Vue》

《Vue后台项目中遇到的技术难点以及解决方案》

《手把手教你Electron + Vue实战教程(五)》

《手把手教你Electron + Vue实战教程(四)》

《手把手教你Electron + Vue实战教程(三)》

《手把手教你Electron + Vue实战教程(二)》

《手把手教你Electron + Vue实战教程(一)》

《收集22种开源Vue模板和主题框架「干货」》

《如何写出优秀后台管理系统?11个经典模版拿去不谢「干货」》

《手把手教你实现一个Vue自定义指令懒加载》

《基于 Vue 和高德地图实现地图组件「实践」》

《一个由 Vue 作者尤雨溪开发的 web 开发工具—vite》

《是什么让我爱上了Vue.js》

《1.1万字深入细品Vue3.0源码响应式系统笔记「上」》

《1.1万字深入细品Vue3.0源码响应式系统笔记「下」》

《「实践」Vue 数据更新7 种情况汇总及延伸解决总结》

《尤大大细说Vue3 的诞生之路「译」》

《提高10倍打包速度工具Snowpack 2.0正式发布,再也不需要打包器》

《大厂Code Review总结Vue开发规范经验「值得学习」》

《Vue3 插件开发详解尝鲜版「值得收藏」》

《带你五步学会Vue SSR》

《记一次Vue3.0技术干货分享会》

《Vue 3.x 如何有惊无险地快速入门「进阶篇」》

《「干货」微信支付前后端流程整理(Vue+Node)》

《带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」》

《「干货」Vue+高德地图实现页面点击绘制多边形及多边形切割拆分》

《「干货」Vue+Element前端导入导出Excel》

《「实践」Deno bytes 模块全解析》

《细品pdf.js实践解决含水印、电子签章问题「Vue篇」》

《基于vue + element的后台管理系统解决方案》

《Vue仿蘑菇街商城项目(vue+koa+mongodb)》

《基于 electron-vue 开发的音乐播放器「实践」》

《「实践」Vue项目中标配编辑器插件Vue-Quill-Editor》

《基于 Vue 技术栈的微前端方案实践》

《消息队列助你成为高薪 Node.js 工程师》

《Node.js 中的 stream 模块详解》

《「干货」Deno TCP Echo Server 是怎么运行的?》

《「干货」了不起的 Deno 实战教程》

《「干货」通俗易懂的Deno 入门教程》

《Deno 正式发布,彻底弄明白和 node 的区别》

《「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台》

《「实践」深入对比 Vue 3.0 Composition API 和 React Hooks》

《前端网红框架的插件机制全梳理(axios、koa、redux、vuex)》

《深入Vue 必学高阶组件 HOC「进阶篇」》

《深入学习Vue的data、computed、watch来实现最精简响应式系统》

《10个实例小练习,快速入门熟练 Vue3 核心新特性(一)》

《10个实例小练习,快速入门熟练 Vue3 核心新特性(二)》

《教你部署搭建一个Vue-cli4+Webpack移动端框架「实践」》

《2020前端就业Vue框架篇「实践」》

《详解Vue3中 router 带来了哪些变化?》

《Vue项目部署及性能优化指导篇「实践」》

《Vue高性能渲染大数据Tree组件「实践」》

《尤大大细品VuePress搭建技术网站与个人博客「实践」》

《10个Vue开发技巧「实践」》

《是什么导致尤大大选择放弃Webpack?【vite 原理解析】》

《带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】》

《带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】》

《实践Vue 3.0做JSX(TSX)风格的组件开发》

《一篇文章教你并列比较React.js和Vue.js的语法【实践】》

《手拉手带你开启Vue3世界的鬼斧神工【实践】》

《深入浅出通过vue-cli3构建一个SSR应用程序【实践】》

《怎样为你的 Vue.js 单页应用提速》

《聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总》

《【新消息】Vue 3.0 Beta 版本发布,你还学的动么?》

《Vue真是太好了 壹万多字的Vue知识点 超详细!》

《Vue + Koa从零打造一个H5页面可视化编辑器——Quark-h5》

《深入浅出Vue3 跟着尤雨溪学 TypeScript 之 Ref 【实践】》

《手把手教你深入浅出vue-cli3升级vue-cli4的方法》

《Vue 3.0 Beta 和React 开发者分别杠上了》

《手把手教你用vue drag chart 实现一个可以拖动 / 缩放的图表组件》

《Vue3 尝鲜》

《总结Vue组件的通信》

《Vue 开源项目 TOP45》

《2020 年,Vue 受欢迎程度是否会超过 React?》

《尤雨溪:Vue 3.0的设计原则》

《使用vue实现HTML页面生成图片》

《实现全栈收银系统(Node+Vue)(上)》

《实现全栈收银系统(Node+Vue)(下)》

《vue引入原生高德地图》

《Vue合理配置WebSocket并实现群聊》

《多年vue项目实战经验汇总》

《vue之将echart封装为组件》

《基于 Vue 的两层吸顶踩坑总结》

《Vue插件总结【前端开发必备】》

《Vue 开发必须知道的 36 个技巧【近1W字】》

《构建大型 Vue.js 项目的10条建议》

《深入理解vue中的slot与slot-scope》

《手把手教你Vue解析pdf(base64)转图片【实践】》

《使用vue+node搭建前端异常监控系统》

《推荐 8 个漂亮的 vue.js 进度条组件》

《基于Vue实现拖拽升级(九宫格拖拽)》

《手摸手,带你用vue撸后台 系列二(登录权限篇)》

《手摸手,带你用vue撸后台 系列三(实战篇)》

《前端框架用vue还是react?清晰对比两者差异》

《Vue组件间通信几种方式,你用哪种?【实践】》

《浅析 React / Vue 跨端渲染原理与实现》

《10个Vue开发技巧助力成为更好的工程师》

《手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】》

《1W字长文+多图,带你了解vue的双向数据绑定源码实现》

《深入浅出Vue3 的响应式和以前的区别到底在哪里?【实践】》

《干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》

《基于Vue/VueRouter/Vuex/Axios登录路由和接口级拦截原理与实现》

《手把手教你D3.js 实现数据可视化极速上手到Vue应用》

《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】》

《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】》

《吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【下】》

《Vue3.0权限管理实现流程【实践】》

《后台管理系统,前端Vue根据角色动态设置菜单栏和路由》

作者:东起

转发链接:https://zhuanlan.zhihu.com/p/103763164

你可能感兴趣的:(axios,vue,加载效果动画)