问题总结

181 阅读10分钟

1. H5新特性

  • 1.1 语义化标签
  • header footer nav aside article section
  • 1.2 音频、视频(audio video)
  • 1.3 画布(Canvas)
  • 在canvas上绘制我们需要的图形。Canvas本身是一个HTML元素,需要HTML元素的配合高度和宽度属性而定义出的一块可绘制区域,定义区域之后可被用来通过JavaScript来绘制图形及图形动画
  • 1.4 localstorage 和 sessionstorage 缓存方式

2. css3新特性

  • 2.1 圆角border-radius

  • 2.2 阴影之box-shadow

  • 2.3 阴影之text-shadow

  • 2.4 背景渐变linear-gradient

  • 2.5 转换transform

      translate()移动 rotate()旋转 scale()缩放 skew()倾斜 3D转换之rotateX() 3D转换之rotateY()  translate3d()
    
  • 2.6 过渡transition

  • 2.7 动画animation

  • @keyframes创建动画

  • animation执行动画

  • 2.7 绘制特殊图形

  • 2.8 媒体查询

  • 设置meta标签

  • 媒体查询语句

  • 2.9 响应式布局

  • 3.0 栅格系统

  • 3.1 多列

  • 创建多列

  • 设置每列之间的间隙

  • 列边框

3. es6新特性

4. vue路由的两种模式:hash与history的区别

  • hash模式url带#号,history模式不带#号
  • hash的传参是基于url的,如果要传递复杂的数据,会有体积的限制,而history模式不仅可以在url里放参数,还可以将数据存放在一个特定的对象中
  • history模式需要后端配合将所有访问都指向index.html,否则用户刷新页面,会导致404错误

5. axios的封装

- 新建一个utils文件

  • 建立request.js
import axios from 'axios'
axios.defaults.baseURL = 'http://129.211.169.131:5000'

// 设置请求拦截
axios.interceptors.request.use(config => {
    // 登录之后得到token,将token放入本地,token的添加
    return config
})
// 设置响应拦截
axios.interceptors.response.use(res => {
    // 解构res
    // 统一的错误处理
    // 监听到token是否过期, 如果token过去就会返回一个状态码
    return res
})
//暴露出去
export default axios
  • 建立api.js
// 先引入axios从reque.js
import axios from '@/utils/request'

// 封装api
export const getGoodsList = () => axios.get('/goods/goods_list')
  • 在页面使用api
// 先引入
import { getGoodsList } from '@/utils/api'

// 调用
created() {
        // 获取商品列表
        getGoodsList().then(res => {
            console.log(res.data.data);
            this.goodsList = res.data.data
            // console.log(this.goodsList);
        })
}

6. 面包屑的原理

7. 动态路由, vue的按钮权限如何进行控制

8. 跨域

9. 防抖节流

- 防抖

  • 防抖: 就是延时操作, 多次触发只执行最后一次
  • 应用场景:input框搜索,多次输入操作最终作为一次操作
<!--简单版本-->
var timer ;
function debounce(){
    if(timer){
        clearTimeout(timer)
    }
    timer = setTimeout(()=>{
        console.log("一秒后发请求")
    },1000)
}
debounce();

- 节流

  • 节流:固定时间内只执行一次
  • 应用场景:btn提交,多次点击只提交一次,需要一个标识,为false时不提交
<!--简单版本-->
var flag = true;
function throttle() {
    if (!flag) return false;
    flag = false;
    setTimeout(() => {
        console.log('2秒内如论调用多少次此函数,都只会打印一次结果')
        flag = true;
    }, 2000)
}
throttle();

10. 请求拦截和响应拦截

11. 前置路由守卫

12. promise解决回调地狱

13. 解释双向绑定

  • MVVM的双向绑定
Model  <-Object.defineProperty>  ViewModel  <watch通知更新-> View
VM层实现双向绑定
1. 拦截model层所有的key, 产生getter/setter, 能够知道属性的变化
2. 用户操作, 触发setter, 通知VM的watch函数
3. watch函数通知view层进行视图更新
  • v-model的双向绑定(v-model底层原理)
1. 使用:value绑定data动态值
2. 监听input的改变事件, 在事件中修改data

14. 页面性能优化

  • keep-alive

15. data中数据更新后, 页面没有变化是什么原因

16. 404页面的配置

  • router/index.js
{
    path:'*',
    redirect:'/404'
  },
  {
      path:'/404',
      component:()=>import('@/views/404/404.vue')
  },

17. 前置路由守卫-非法路由拦截

  • 前置路由守卫: 每一次 路由跳转的时候之前,触发这个守卫函数
  • 路由的实例对象.beforeEach()
  • 退出登录:清除所有的本地存储数据---跳转到登录
  • 如果当前系统的本地存储没有登录 ---只能打开登录页
const router = new VueRouter({
  routes
})
// 路由前置守卫--验证用户是否登录--如果没有登录-只能访问login
// to 前往的页面路由对象
//from 来自于 当前页面路由对象
//next 函数  next()继续下一步执行   next('/路由') 前往xx页面
router.beforeEach((to,from,next)=>{
    if(to.path =='/login'){
      	next()
    }else if(localStorage.getItem('user')){
        next()
    }else{
        next('/login')
    }
})
export default router;

18. 动态路由拆分方案-用户权限验证

  • 用户权限验证 : 根据用户不同的角色 给用户不同的访问权限===能够访问的路由
  • 动态路由拆分: 为了实现 权限的不同,最完美方案: 能不能把路由拆分两个路由数组
  • 静态路由: 不区分角色 大家都可以访问的页面 ---只有基础页面---登录页
  • 动态路由: 动态路由数组---通过 角色 生成的数组【关键--难点】

方法一: 写独立json /2个js数组 --有缺陷

  • 将路由拆分为两个路由 routes 数组 只有 login * 404
  • 其他的对象都放到 动态路由数组中
  • src/router/routes.js
import Layout from '@/views/layout/Layout.vue'

//超级管路员的权限列表
export const  superRoutes = [
    {
        path:'/layout',
        component:Layout,
        redirect:'/home',
        meta:{title:"首页"},
        children:[
          {
            path:'/home',
            meta:{title:"首页"},
            component:()=>import('@/views/home/Home.vue')
          }
      ]
      },
  
      //全是二级路由
      //账号管理
      {
          path:'/account',
          component:Layout,
          meta:{title:"账号管理"},
          // 重定向
          redirect:'/accountList',
          children:[
            {
              path:'/accountList',
              meta:{title:"账号列表"},
              component:()=>import('@/views/account/AccountList.vue')
            },
            {
              path:'/accountCenter',
              meta:{title:"个人中心"},
              component:()=>import('@/views/account/AccountCenter.vue')
            },
            {
              path:'/accountEdit',
              meta:{title:"修改密码"},
              component:()=>import('@/views/account/AccountEdit.vue')
            },
            {
              path:'/accountAdd',
              meta:{title:"添加账号"},
              component:()=>import('@/views/account/AccountAdd.vue')
            }
          ]
      },
      //商品管理
      {
        path:'/goods',
        component:Layout,
        redirect:'/goodsList',
        meta:{title:"商品管理"},
        children:[
          {
            path:'/goodsList',
            meta:{title:"商品列表"},
            component:()=>import('@/views/goods/GoodsList.vue')
          },
          {
            path:'/goodsAdd',
            meta:{title:"商品添加"},
            component:()=>import('@/views/goods/GoodsAdd.vue')
          },
          {
            path:'/goodsType',
            meta:{title:"商品分类"},
            component:()=>import('@/views/goods/GoodsType.vue')
          },
        ]
      },
  
      //订单管理
      {
        path:'/order',
        redirect:'/orderList',
        component:Layout,
        meta:{title:"订单管理"},
        children:[
          {
            path:'/orderList',
            meta:{title:"订单管理" },
            component:()=>import('@/views/order/OrderList.vue')
          },
        ]
      },
  
        //店铺管理
      {
        path:'/layout',
        redirect:'/shop',
        component:Layout,
        meta:{title:"店铺管理"},
        children:[
          {
            path:'/shop',
            meta:{title:"店铺管理"},
            component:()=>import('@/views/shop/Shop.vue')
          },
        ]
      },
  
      //销售同级
      {
          path:'/statistics',
          redirect:'/goodsStatistics',
          meta:{title:"销售统计"},
          component:Layout,
          children:[
            {
              path:'/goodsStatistics',
              meta:{title:"商品统计"},
              component:()=>import('@/views/statistics/GoodsStatistics.vue')
            },
            {
              path:'/orderStatistics',
              meta:{title:"订单统计"},
              component:()=>import('@/views/statistics/OrderStatistics.vue')
            },
          ]
      }
]



//普通管理员的权限列表
export const normalRoutes = [
    
    {
        path:'/layout',
        component:Layout,
        redirect:'/home',
        meta:{title:"首页"},
        children:[
          {
            path:'/home',
            meta:{title:"首页"},
            component:()=>import('@/views/home/Home.vue')
          }
      ]
      },
  
      //全是二级路由
      //账号管理
      {
          path:'/account',
          component:Layout,
          meta:{title:"账号管理"},
          // 重定向
          redirect:'/accountList',
          children:[
            {
              path:'/accountList',
              meta:{title:"账号列表"},
              component:()=>import('@/views/account/AccountList.vue')
            },
            {
              path:'/accountCenter',
              meta:{title:"个人中心"},
              component:()=>import('@/views/account/AccountCenter.vue')
            },
            {
              path:'/accountEdit',
              meta:{title:"修改密码"},
              component:()=>import('@/views/account/AccountEdit.vue')
            }
          ]
      },
      //商品管理
      {
        path:'/goods',
        component:Layout,
        redirect:'/goodsList',
        meta:{title:"商品管理"},
        children:[
          {
            path:'/goodsList',
            meta:{title:"商品列表"},
            component:()=>import('@/views/goods/GoodsList.vue')
          },
          {
            path:'/goodsAdd',
            meta:{title:"商品添加"},
            component:()=>import('@/views/goods/GoodsAdd.vue')
          },
          {
            path:'/goodsType',
            meta:{title:"商品分类"},
            component:()=>import('@/views/goods/GoodsType.vue')
          },
        ]
      },
  
      //订单管理
      {
        path:'/order',
        redirect:'/orderList',
        component:Layout,
        meta:{title:"订单管理"},
        children:[
          {
            path:'/orderList',
            meta:{title:"订单管理" },
            component:()=>import('@/views/order/OrderList.vue')
          },
        ]
      }
]
  • 定义并暴露一个函数 做动态路由的拼接
// src/router/index.js
//在 router 实例对象后面
export const  createFullRoutes=(role)=>{
    if(role =='super'){
      router.addRoutes([...routes,...superRoutes]);
    }else{
      router.addRoutes([...routes,...normalRoutes]);
    }
}
  • 在登录 login.vue 登录接口的成功
import { createFullRoutes} from '@/router/index.js'


// 登录的点击事件中 axios 陈功了之后 调用 该函数
    let {code,id,role,token,msg}= await login(this.formData);
            if(code ==0){
              localStorage.setItem('user',JSON.stringify({id,role,token}));

                //调用动态路由的拼接函数
                createFullRoutes(role);
            
              this.$message.success('登录成功');
              //跳转
              this.$router.push('/home');
                
   }
  • 测试:登录一个普通管理员账号---点击一下 店铺管理---数据统计

方法二: 递归生成

方法三: 后端返回 +管理系统配置页面

19. 全局自定义指令-权限指令

方法一: 按钮级权限

  • v-if 本地存储 获取 当前用户的 role ==' super '

方法二: 自定义指令

  • main.js 加上指令 v-permission
// 自定义指令
Vue.directive('permission',{
  // el: 获取当前绑定这个指令的dom节点
  //  data: 指令传递的表达式的结果
  inserted(el,data){
      let {role} = JSON.parse(localStorage.getItem('user'));
      //如果当前用户的role 不被包含在该按钮定义时传递的字符串中 就删除这个dom
      if(!data.value.includes(role)){
            el.remove();
      }
  }
})
  • 只有 super 权限才可显示
 <el-button type="primary" slot="btn" v-permission="'super'">添加分类</el-button>  
  • 只有 super normal 权限才可显示
 <el-button type="primary" slot="btn" v-permission="'super,normal'">添加分类</el-button> 

20. 拿数据后我这边渲染很慢,怎么去优化? 优化的问题?

21. 一个页面最多请求多少个接口? 一个页面请求十几个接口,是怎么解决的?

22. 路由的优化?

23. 事件冒泡?

24. 缓存?

25. 打开后白屏的原因与解决方式?

分为网页与小程序app的情况

26. 最大访问量的项目?

27. 页面转换pdf下载?

28. 加载网页,跳转的时候怎么去设置? vue动态修改网页tile?

29. vue怎么对搜索引擎进行优化? 实现单页面eso优化?

30. 事件循环

1. js异步的执行机制就是事件循环机制

  • 所有的任务都在主线程执行, 形成一个执行栈

  • 主线程之外存在一个任务队列(task queue),只要异步任务有了运行结果, 就会放置在任务队列中等待

  • 当同步任务全部完成后就会去任务队列中读取异步任务,进入执行栈执行

  • 主线程不断的重复上面三个步骤,所以叫事件循环机制

image.png

31. vite和webpack的底层打包有什么区别?

32. webpack的五大核心,plugin和loader?

33. generator?

34. 懒加载实现的原理?

35. 前端渲染遇到js阻塞怎么办? 遇到掉帧怎么办? 掉帧的原理?

36. js的事件循环?

37. requestAnimationFrame (请求动画帧)? 用了之后怎么防止他掉帧?

38. CDN? 为什么用CDN? 前端资源都会上CDN!

39. 面对对象编程?

- 概念

  • 面向对象是把事务分解为一个个对象, 然后由对象之间分工合作, 是以对象的功能来划分问题, 而不是步骤

- 优点

  • 具有灵活, 代码可复用, 易维护和开发的优点

- 特性

  • 封装性
  • 继承性
  • 多态性

image.png

image.png

image.png

40.scss的用法

安装: yarn add sass sass-loader -D

- 定义变量

  • 用$去定义变量

image.png

- mixin代码重用,混入(提取公共部分)

  • 用 @mixin 提取公共代码, 然后在要使用的地方用 @include 引入; 将不同的地方当作参数传进去

image.png image.png

- 定义函数

  • 用@定义一个函数,然后在函数里面编写逻辑

image.png image.png

41.less用法

安装: yarn add less less-loader -D

- 定义变量

  • 用@去定义

image.png

- mixin

  • 直接 .名字(@参数){} 提取公共部分; 用 .名字()引用

image.png

42.移动端适配

设计师只会出一份设计稿(375 750)。前端会根据这个设计稿适配到各个机型。

vw: 就是屏幕宽度的百分之1,

假如我们设计稿宽度750, 设计稿上有一个板块宽度为375

请问一个问题: 实际机型 375 板块的宽度:187.5 屏幕的一半 50vw

实际机型414 板块的宽度: 207 屏幕的一半 50vw

实际的机390 板块的宽度: 195 屏幕的一半 50vw

结论:变换的实际的宽度,不变的是相对于屏幕的百分比。 将px转换为vw就能适配各个机型! 重点问题:把css中的所有px单位转换vw。借助第三方插件:postcss-px-to-viewport

- 安装插件:yarn add postcss-px-to-viewport -D

- 在项目根目录下创建一个文件:postcss.config.js

module.exports = {
    plugins: {
      'postcss-px-to-viewport': {
        // options
        // 配置设计稿的宽度, 不需要你做换算,设计稿量出的宽度是多少,css中就写多少
        viewportWidth: 375
      }
    }
}

43.vant ui框架的引入

vant官网: vant-contrib.gitee.io/vant/v2/#/z…

  • 安装vue2版本的vant : yarn add vant@latest-v2

  • 在mian.ts中全局引入vant的样式文件

  • 按需注册组件,main.ts

    import { Button } from 'vant'
    Vue.use(Buttton)
    
  • 去页面中使用