前端高频面试题(三)

507 阅读7分钟

你对路由守卫的理解

分析问题(不作为回答答案)

Vue Router 的底层原理是基于浏览器的 History API 和 Vue.js 的核心功能实现的。通过监听 URL 的变化、使用路由匹配系统和导航守卫机制。

也就是说我们要实现导航守卫,就是要给URL添加事件监听器,当检测到地址发生变化进入监听器的业务逻辑,这样你就可以进行身份验证。

回答问题

  1. Vue Router 利用 History API (浏览器提供的History对象)可以监听 URL 的变化,并在 URL 发生改变时触发路由的更新。
  2. Vue Router 在底层实现了一套路由匹配系统,用来匹配 URL 和路由配置之间的关系。当 URL 发生变化时,Vue Router 会根据路由匹配系统来找到与之匹配的路由配置,并将对应的组件渲染到页面上。
  3. 当你设计了路由守卫后,我们检测到地址发生变化,可以先进入事件函数,根据返回值来决定是否进行路由映射,或者进行重定向的过程。其中next这个函数就是用于跳转映射和重定向。

vue中如何在data中动态添加数据

分析问题(不作为回答答案)

vue的响应式原理采用了数据劫持的方式来实现。在我们加载项目的时候,new Vue({})过程就会加载data的数据,并实现数据的劫持。当底层调用render的时候,实现了数据的动态渲染。

这个时候,如果你动态修改了data里面定义好的字段数据,vue会劫持到获取和修改。

但是如果你新增了data数据,或者新增删除某个对象的属性,无法将这个字段进行数据劫持,就无法进行响应式变化。

回答问题

默认给data新增属性,或者给data中对象新增属性或者删除属性,vue默认检测不到这个内容。

vue官方也提供了解决方案

  1. $set函数可以添加响应式的属性

    this.$set(对象,属性,值)
    
  2. 覆盖原来的对象

    this.对象 = 新对象
    

sass的函数

分析问题(不作为回答答案)

sass作为目前使用比较多的css预处理器,我们平时用的最多的嵌套功能、还有一个变量的定义。

但实际上sass还提供了很多的功能,比如循环语句、混入、函数等等。

比如bootstrap4及以前版本,底层的样式就完全采用less的函数、混入和函数来实现的响应式珊格系统。

在之后的版本中bootstrap底层采用了scss来设计,依然用到了这些功能。

平时项目业务开发很少直接使用,除非是做工具开发。

回答问题

在css开发的过程中我们其实也接触到了函数的概念。比如var函数、calc函数等等。这是css3新增的一些函数内容。在scss中也可以使用函数来进行开发。默认已经提供很很多的函数

比如rgb函数定义颜色

$color: rgb(255, 0, 0);

比如mix混合两种颜色

$mixed-color: mix($color1, $color2);

比如将数值转化为百分比percentage

$percentage: percentage(0.5);  // 50%

websocket的错误码有哪些

分析问题(不作为回答答案)

webscoket可以实现双工通信,基于ws协议来进行通信。

但是底层还是基于tcp构建而来的,跟http请求一样,也会涉及到状态码和错误码。

监听到状态码或者错误码来反馈成功还是失败,失败是什么原因.

回答问题

websocket在进行通信的过程中虽然用的ws协议,但和http一样都有状态码的变化。前端在开发过程中可以获取状态码,一般很多操作都封装为了api,所以自己取状态码就比较少.一般只有在连接关闭或者失败的时候,我们会打印错误码。

var socket = new WebSocket('ws://example.com');
console.log(scket.readyState);  // 打印当前状态码

// WebSocket 的状态改变时触发的事件
socket.onopen = function(event) {
  console.log(socket.readyState);  // 打印当前状态码
};

socket.onclose = function(event) {
  console.log(socket.readyState);  // 打印当前状态码
  console.log(event.code);         // 打印错误码
};

socket.onerror = function(event) {
  console.log(socket.readyState);  // 打印当前状态码
  console.log(event.code);         // 打印错误码
};

readyState这个属性可以获取当前webscoket的状态码。

主要状态码如下:

  • 0CONNECTING,连接尚未建立。
  • 1OPEN,WebSocket 连接已建立并且可以进行通信。
  • 2CLOSING,连接正在关闭。
  • 3CLOSED,连接已关闭或无法建立连接。

event.code可以获取到错误码:

  1. 1000:表示连接正常关闭
  2. 1002:协议错误关闭了连接
  3. 1008:表示收到的数据违反了策略,服务器关闭连接。

vue3数据更新,页面不同步原因?

分析问题(不作为回答答案)

vue3的底层响应式采用proxy来实现,摈弃了vue2的一些缺陷,比如对象属性新增删除检测不到更新,数组用下标来操作无法检测到更新。

但是vue3中也可能出现数据更新页面检测不到的情况。

回答问题

vue3采用proxy来实现响应式设计,已经可以检测到对象属性新增、修改、删除了。

有些操作会导致我们还是无法更新

  1. 意外的刷新

    当你在页面使用按钮或者超链接进行时间绑定更新的时候,意外的刷新了页面,导致更新后页面数据还是原始数据

  2. 未使用响应式的api来存放数据

    Vue 3 中需要使用 refreactive 函数将数据包装成响应式属性,以便 Vue 可以追踪数据变化并更新页面。如果没有使用响应式属性。也会出现无法更新

  3. 异步更新导致

    Vue 3 默认使用异步更新策略,修改了数据可能dom还没进行更新。但是在这个时候,你操作了dom原始,拿到的还是原始数据,可能误以为更新失败。

  4. 模版中修改数据

    比如在模版中使用v-for来进行数据遍历的时候,如果直接修改循环中的数据,页面将不会同步更新。

  5. 跨组件通信

    如果当前页面响应式数据,是来自于其他组件。可能会存在数据传输的问题。导致无法更新

小程序中如何根据不同权限的用户,显示不同的底部 tabbar?

分析问题(不作为回答答案)

小程序登录后,不同权限看到不同tabbar,要解决的问题,动态修改tabbar就能实现。

类似于vue的动态路由,登录成功后调用addRouter来动态新增路由列表。

回答问题

要根据不同用户显示不同的tabbar,那可以动态构造小程序中的tabbar。虽然tabbar是在json文件中定死的数据,但是我们依然可以进行访问并修改。

开发步骤:

  1. 先在本地json文件中配置好所有的tabbar

    {
      "tabBar": {
        "list": [
          {
            "pagePath": "pages/home/home",
            "text": "首页",
            "iconPath": "images/home.png",
            "selectedIconPath": "images/home-selected.png",
            "roles": ["普通管理员"]
          },
          {
            "pagePath": "pages/center/center",
            "text": "个人中心",
            "iconPath": "images/center.png",
            "selectedIconPath": "images/center-selected.png",
            "roles": ["超级管理员"]
          }
        ]
      }
    }
    

    每个tabbar都有一个role角色名字来控制谁能访问

  2. 登录:获取不同用户的角色或者权限。比如:超级管理员、普通管理员

  3. 在小程序onShow生命周期中筛选

    onShow(){
       // 根据用户权限设置底部 tabbar 的配置
        const tabBarList = this.getTabBar().data.list;
      // 筛选并设置不同的tabbar
      	this.getTabBar().setData({
          list: tabBarList.filter(tab => {
            // 没有设置 roles 属性或用户权限匹配,则返回 true
            return !tab.roles || tab.roles.indexOf(userRole) !== -1;
          })
        });
    }