前端面试自用总结--项目提问

205 阅读5分钟
组件的封装
 在使用 vue-cli 创建的项目中,组件的创建非常方便,只需要新建一个 .vue 文件,然后在 template 中写好 HTML 代码,一个简单的组件就完成了。一个完整的组件,除了 template 以外,还有 script和 style
 props参数(父对子传参)
 slot定制插槽
 event自定义事件
 ​
 接收方式为标题需要用户传入title属性,图标和显示内容是需要传入元素数据的,我们使用vue中的插槽进行封装,得出来的结果是
 <template>
     <div
         class="w-full h-[200]px bg-white rounded-md shadow-sm p-5 m-4 transition-shadow duration-700 hover:shadow-lg"
     >
         <div class="flex place-content-between align-center">
             <div class="text-xl">{{ props.title }}</div>
             <div>
                 <slot name="icon"></slot>
             </div>
         </div>
         <el-divider></el-divider>
         <div class="content">
             <slot></slot>
         </div>
     </div>
 </template>
 ​
 <script setup lang="ts">
 const props = defineProps<{ title: string }>()
 </script>
 ​
 当所有的组件封装好了之后,我们只需要通过import方式导入对应的组件并插入到template中即可。(别忘记传入数据哦)
axios的封装
 在vue项目中,和后台进行请求交互这块,我们通常都会选择axios库,它是基于promise的http库,可运行在浏览器端和node.js中。在本项目中主要实现了请求和响应拦截,get,post请求封装。
 ​
 import axios from 'axios'
 import Qs from 'qs' // 处理post请求数据格式
 import store from '@/store'
 import router from '@/router'
 import Vue from 'vue'
 import { Loading, Message } from 'element-ui' // 引用element-ui的加载和消息提示组件
 ​
 //初始化axios
 const $axios = axios.create({
   // 设置超时时间
   timeout: 30000,
   // 基础url,会在请求url中自动添加前置链接
   baseURL: process.env.VUE_APP_BASE_API
 })
 Vue.prototype.$http = axios // 这里并发请求以便在组件使用this.$http.all(),具体看dashborad页面
 // 在全局请求和响应拦截器中添加请求状态
 let loading = null
 /**
  * 请求拦截器
  * 用于处理请求前添加loading、判断是否已保存token,并在每次请求头部添加token
  */
 $axios.interceptors.request.use(
   config => {
     loading = Loading.service({ text: '拼命加载中' })
     const token = store.getters.token
     if (token) {
       config.headers.Authorization = token // 请求头部添加token
     }
     return config
   },
   error => {
     return Promise.reject(error)
   }
 )
 /**
  * 响应拦截器
  * 用于处理loading状态关闭、请求成功回调、响应错误处理
  */
 $axios.interceptors.response.use( 
   response => {
     if (loading) {
       loading.close()
     }
     const code = response.status
     // 请求成功返回response.data
     if ((code >= 200 && code < 300) || code === 304) {
       return Promise.resolve(response.data)
     } else {
       return Promise.reject(response)
     }
   },
   error => {
     if (loading) {
       loading.close()
     }
     console.log(error)
     if (error.response) {
       switch (error.response.status) {
         case 401:
           // 返回401 清除token信息并跳转到登陆页面
           store.commit('DEL_TOKEN')
           router.replace({
             path: '/login',
             query: {
               redirect: router.currentRoute.fullPath
             }
           })
           break
         case 404:
           Message.error('网络请求不存在')
           break
         default:
           Message.error(error.response.data.message)
       }
     } else {
       // 请求超时或者网络有问题
       if (error.message.includes('timeout')) {
         Message.error('请求超时!请检查网络是否正常')
       } else {
         Message.error('请求失败,请检查网络是否已连接')
       }
     }
     return Promise.reject(error)
   }
 )
 // get,post请求方法
 export default {
   post(url, data) {
     return $axios({
       method: 'post',
       url,
       data: Qs.stringify(data),
       headers: {
         'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
       }
     })
   },
   get(url, params) {
     return $axios({
       method: 'get',
       url,
       params
     })
   }
 }
用户权限和动态路由(vue-element-admin)
 前端在本地写好路由表,以及每个路由对应的角色,也就是哪些角色可以看到这个菜单 / 路由。
 登录的时候,向后端请求得到登录用户的角色(管理者,普通用户)
 ​
 利用路由导航守卫(router.beforeEach(全局前置守卫 进入路由之前)),根据取到的用户角色,跟本地的路由表进行对比,过滤出用户对应的路由,并利用路由进行菜单渲染
 每次更改页面路由
         你有没有token啊?
             有的
                 好的,你的权限是默认的权限0么?
                     是的。。我就是一游客
                         系统获取我的信息..拿到权限值,动态加载路由(GenerateRoutes)...通行...
                     不是。。我是权限汪(admin)
                         等等..我看看作者有没有把你降级
                             没有
                                 好了。。你还是权限汪 请进
                             有
                                 滚吧,你已经不是权限汪了,作者已经把你写成战斗力只有5的渣渣了
             没有
                 没有还敢闯这里?滚去关口(/login)
 ​
 我们将储存在将storage中的token作为用户是否登录的标志,如果当前storage中有token,表明当前系统已被登录
 将系统所有页面分为两类,需要登录才能查看的页面,不需要登录的login.vue, register.vue
动态路由
 前端将全部路由规定好,登录时根据用户角色权限来动态展示路由;
 路由是组织一个vue项目的关键,在对项目原型分析后,接下来的第一步就是编写路由,本项目中,主要分为两种路由,currencyRoutes 和 asyncRoutes
 currencyRoutes:代表通用路由,意思就是不需要权限判断,不同角色用户都显示的页面,如:登陆页、404等
 asyncRoutes: 代表动态路由,需要通过判断权限动态分配的页面,有关的权限判断的方法接下来会介绍。
项目优化
 路由懒加载
 传统的路由组件是通过import静态的打包到项目中,这样做的缺点是因为所有的页面组件都打包在同一个脚本文件中,导致生产环境下首屏因为加载的代码量太多会有明显的卡顿(白屏)
 通过import()使得ES6的模块有了动态加载的能力,让url匹配到相应的路径时,会动态加载页面组件,这样首屏的代码量会大幅减少,webpack会把动态加载的页面组件分离成单独的一个chunk.js文件
 ​
 预渲染
 由于浏览器在渲染出页面之前,需要先加载和解析相应的html,css和js文件,为此会有一段白屏的时间,如何尽可能的减少白屏对用户的影响,目前我选择的是在html模版中,注入一个loading动画,这里我拿D2-Admin中的loading动画举例
 在打包完成后,在这个index.html下方还会注入页面的脚本,当用户访问你的项目时,脚本还没有执行,但是可以显示loading动画,因为它是直接注入在html中的,等到脚本执行完毕后,Vue会新生成一个app的节点然后将旧的同名节点删除,这样可以有效的过渡白屏的时间
 loading动画只是一个让用户感知到你程序正在启动的效果,只是一个静态页面没有任何的功能
 ​
 element-ui按需加载的两种方式
 1.直接按需引入组件及样式
     import { Dialog } from 'element-ui'
     import 'element-ui/lib/theme-chalk/dialog.css'
     Vue.use(Dialog)
 2.使用babel-plugin-component按需引入
 ​
 cdn引入
 对于一些不常改动的模块库,例如: vue vueRouter vuex echarts element-ui 等, 我们让 webpack 不将他们进行打包,而是通过 cdn 引入,这样就可以减少代码大小,减少服务器带宽,并通过cdn将它们缓存起来,提高网站性能 。