• 前端面试问题(jwt/布局/vue数组下标/扁平化/菜单树形/url api/新版本)


    前端面试问题(jwt/布局/vue数组下标/扁平化/菜单树形/url api/新版本)

    1. jwt鉴权逻辑

    前端 JWT 鉴权逻辑通常涉及在发起请求时携带 JWT,并在接收到响应后处理可能的授权问题。

    1. 用户登录:

    1. 用户提供凭证: 用户在登录界面输入用户名和密码。

    2. 请求后端认证: 前端通过发送用户提供的凭证(通常是用户名和密码)到后端进行身份验证

    3. 接收并存储Token: 如果身份验证成功,后端生成 JWT 并将其发送给前端。前端通常会将 JWT 存储在客户端(通常是浏览器)的本地存储(localStorage 或 sessionStorage)中。

    2. 请求时的鉴权:

    1. 构建请求头: 在每次发送请求时,前端将存储的 JWT 添加到请求头中。

      // 使用 Axios 发送请求的方式
      const token = localStorage.getItem('jwtToken');
      axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
      
      • 1
      • 2
      • 3
    2. 发送请求: 发送请求到后端,后端会检查请求头中的 JWT 是否有效。

    3. 处理响应: 前端接收到响应后,可以根据响应状态码和内容进行相应的处理。

      • 如果响应状态码为 401(未授权)或 403(禁止访问),可能表示 JWT 已过期或用户无权限,需要处理重新登录或其他操作。

      • 如果响应状态码为 200,表示请求成功,前端可以继续处理返回的数据。

    3. 处理过期的Token:

    1. 捕获过期错误: 前端需要捕获过期错误。当后端返回 401 状态码时,可以视为 JWT 过期。

    2. 刷新Token: 如果服务器支持,可以尝试使用 refresh token 来获取新的 JWT,避免用户重新登录。

    注意事项:

    • 安全存储: JWT 存储在前端,因此需要确保它被安全地存储。一般来说,避免将敏感信息存储在 JWT 中,因为它可以被解码。

    • 定期刷新: 定期检查 JWT 是否过期,如果过期,需要进行刷新操作。

    • 前端安全性: 前端只能负责存储和传递 JWT,实际的用户身份验证和授权逻辑仍然应该由后端负责。

    2. 实现顶部导航+左侧菜单+右侧主内容区域布局

    在前端,实现顶部导航、左侧菜单、右侧主内容区域布局通常有多种方式,取决于项目的需求和开发者的技术偏好。以下是其中三种常见的实现方式:

    1. Flexbox 布局:

    使用 CSS 的 Flexbox 布局是一种简单而灵活的方法,它能够轻松地实现顶部导航、左侧菜单和右侧主内容区域的布局。

    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Flexbox Layouttitle>
      <style>
        body {
          margin: 0;
          display: flex;
          flex-direction: column;
          height: 100vh;
        }
    
        header, main {
          flex: 0 0 auto;
        }
    
        main {
          display: flex;
        }
    
        nav {
          width: 200px;
          background-color: #333;
          color: #fff;
        }
    
        section {
          flex: 1;
          padding: 20px;
        }
      style>
    head>
    <body>
      <header>
         
          <h1>顶部h1>
      header>
      <main>
        <nav>
           
            <h1>左侧h1>
        nav>
        <section>
          
            <h1>右侧h1>
        section>
      main>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    2. Grid 布局:

    CSS Grid 布局也是一种强大的布局方式,允许更复杂的网格结构。

    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Grid Layouttitle>
      <style>
        body {
          margin: 0;
          display: grid;
          grid-template-columns: 200px 1fr;
          grid-template-rows: auto 1fr;
          grid-template-areas:
            "header header"
            "nav main";
          height: 100vh;
        }
    
        header, nav, main {
          padding: 20px;
        }
    
        header {
          grid-area: header;
          background-color: #ddd;
        }
    
        nav {
          grid-area: nav;
          background-color: #333;
          color: #fff;
        }
    
        main {
          grid-area: main;
          display: flex;
        }
      style>
    head>
    <body>
      <header>
        
           <h1>顶部h1>
      header>
      <nav>
        
           <h1>左侧h1>
      nav>
      <main>
      
           <h1>右侧h1>
      main>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    3. Bootstrap:

    使用 Bootstrap 框架是一种快速搭建响应式布局的方法。Bootstrap 提供了许多现成的组件和样式,使得实现这种布局变得非常容易。

    DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
      <title>Bootstrap Layouttitle>
    head>
    <body>
      <header class="bg-light p-3">
        
          <h1>顶部h1>
      header>
      <div class="container-fluid">
        <div class="row">
          <nav class="col-md-2 bg-dark text-light">
            
              <h1>左侧h1>
          nav>
          <main class="col-md-10">
            
              <h1>右侧h1>
          main>
        div>
      div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4. CSS Float 布局

    使用float属性可以实现一种简单的布局,但需要注意清除浮动以避免影响后续布局。

    <div class="header">顶部导航div>
    <div class="menu">左侧菜单div>
    <div class="content">右侧主内容区域div>
    
    <style>
      .header { clear: both; }
      .menu { float: left; width: 20%; }
      .content { margin-left: 20%; }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. Vue数组下标改值时响应式丢失,为什么

    在Vue中,数组下标改值导致响应式丢失的原因通常是由于Vue对数组的监听机制的限制。Vue的响应式系统对于数组的变更检测有一些局限性,主要涉及到以下情况:

    1. 直接通过索引设置数组元素时,无法触发视图更新: Vue的响应式系统不能检测到直接通过索引设置数组元素的变化。例如,array[index] = value 这种方式不会触发响应式更新。

    2. 通过splice方法添加或删除元素时能够触发更新: 使用Vue提供的数组变异方法(例如splice)来添加或删除元素时,Vue能够监听到变化并触发相应的更新。

    // 在Vue组件中的data
    data() {
      return {
        myArray: [1, 2, 3]
      };
    },
    methods: {
      updateValue() {
        // 这种方式修改数组的元素,不会触发响应式更新
        this.myArray[0] = 99;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    直接通过索引修改数组元素的值 this.myArray[0] = 99; 不会触发Vue的响应式系统。

    为了确保能够触发响应式更新,可以使用Vue提供的变异方法,比如使用Vue.set方法:

    methods: {
      updateValue() {
        // 使用 Vue.set 来确保触发响应式更新
        Vue.set(this.myArray, 0, 99);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    或者使用splice方法:

    methods: {
      updateValue() {
        // 使用 splice 来确保触发响应式更新
        this.myArray.splice(0, 1, 99);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4. 数组扁平化

    1. 使用递归(原生 JavaScript):

      function flattenArray(arr) {
        return arr.reduce((acc, curr) => Array.isArray(curr) ? acc.concat(flattenArray(curr)) : acc.concat(curr), []);
      }
      
      const nestedArray = [[0, 1], [2, [3, 4]], [5, 6]];
      const flattenedArray = flattenArray(nestedArray);
      console.log(flattenedArray);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    2. 使用 Array.flat() 方法(ECMAScript 2019):

      const nestedArray = [[0, 1], [2, [3, 4]], [5, 6]];
      const flattenedArray = nestedArray.flat(Infinity);
      console.log(flattenedArray);
      
      • 1
      • 2
      • 3
    3. 使用 lodash 库:

      const _ = require('lodash');
      
      const nestedArray = [[0, 1], [2, [3, 4]], [5, 6]];
      const flattenedArray = _.flattenDeep(nestedArray);
      console.log(flattenedArray);
      
      • 1
      • 2
      • 3
      • 4
      • 5

    Array.flat() 方法和 lodash 的 _.flattenDeep() 都可以递归地将数组扁平化,而原生的递归方法Array.reduce()` 方法需要手动处理递归。

    5. 菜单数组转换为嵌套树形结构

    [{ id: 1, menu: '水果', level: 1 }, { id: 2, menu: '橘子', level: 2, parentId: 1 } ]
    
    • 1
    [{ id: 1, menu: '水果', level: 1, children: [{ id: 2, menu: '橘子', level: 2, parentId: 1 }] }]
    
    • 1
    function convertToNestedTree(menuArray) {
        const idToMenuMap = {}; // 用于存储菜单项的映射,通过id快速查找
    
        // 构建映射
        menuArray.forEach(item => {
            idToMenuMap[item.id] = item;
        });
    
        // 构建树形结构
        const tree = [];
        menuArray.forEach(item => {
            if (!item.parentId) {
                // 如果没有parentId,说明是根节点,直接添加到树中
                tree.push(item);
            } else {
                // 如果有parentId,将当前项添加到父级的children数组中
                const parentMenu = idToMenuMap[item.parentId];
                if (parentMenu) {
                    if (!parentMenu.children) {
                        parentMenu.children = [];
                    }
                    parentMenu.children.push(item);
          
                }
            }
        });
    
        return tree;
    }
    
    
    const menuArray = [
        { id: 1, menu: '水果', level: 1 },
        { id: 2, menu: '橘子', level: 2, parentId: 1 },
    
    ];
    
    const nestedTree = convertToNestedTree(menuArray);
    console.log(nestedTree);//[{ id: 1, menu: '水果', level: 1, children: [{ id: 2, menu: '橘子', level: 2, parentId: 1 }] }]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    6. url 参数获取的 API

    在前端,使用 URLSearchParams 对象来获取 URL 参数。这是一个原生 JavaScript 对象,可用于解析 URL 查询参数。

    // 假设 URL 为 https://example.com/page?name=John&age=25
    
    const urlParams = new URLSearchParams(window.location.search);
    
    // 获取单个参数
    const name = urlParams.get('name'); // 返回 'xx'
    const age = urlParams.get('age');   // 返回 '25'
    
    // 获取所有参数
    const allParams = {};
    urlParams.forEach((value, key) => {
        allParams[key] = value;
    });
    
    console.log(allParams);
    // 输出:{ name: 'xx', age: '25' }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    使用 URLSearchParams 对象从当前页面的 URL 中提取参数。

    7. 新版本发布后,怎么用技术手段通知用户刷新页面

    在前端中,可以使用以下几种技术手段来通知用户刷新页面以加载新版本:

    1. Service Worker 和 Cache 更新:

      • 使用 Service Worker 来缓存资源并控制页面加载。
      • 当新版本发布时,Service Worker 可以检测到更新,然后发送消息到页面,通知用户有新版本可用。
      • 页面收到消息后,可以显示一个通知或提示,引导用户刷新页面。
    2. WebSocket 或 Server-Sent Events (SSE):

      • 使用 WebSocket 或 SSE 与服务器建立实时通信通道。
      • 当新版本发布时,服务器通过通道向客户端发送消息。
      • 客户端收到消息后,可以显示通知并提示用户刷新页面。
    3. Polling:

      • 定期向服务器发起请求检查是否有新版本。
      • 当服务器检测到新版本时,返回相应的信息。
      • 页面收到信息后,显示通知并引导用户刷新页面。
    4. LocalStorage 或 IndexedDB 标记:

      • 在本地存储(LocalStorage)或 IndexedDB 中保存一个标记,表示当前页面的版本。
      • 当新版本发布时,将新版本的标记写入本地存储或 IndexedDB。
      • 页面加载时检查标记,如果检测到新版本,显示通知并引导用户刷新页面。
    5. 使用 Service Worker 的 skipWaitingclients.claim

      • 在 Service Worker 中使用 self.skipWaiting()clients.claim() 来立即激活新版本的 Service Worker。
      • 在新版本的 Service Worker 中发送消息到页面,通知用户有新版本可用。
      • 页面接收到消息后,显示通知并引导用户刷新页面。
  • 相关阅读:
    ContentProvider 属性介绍
    教你如何使用API接口获取数据
    TNF1AUX OSN1800全新原装辅助接口板
    占位,稍后补上
    shell脚本文件遍历 str转数组 字符串拼接
    Java解析微信获取手机号信息
    Java 之SpringBoot+Vue实现后台管理系统的开发【一、前端】
    `算法知识` 哈希
    python---socket套接字,粘包问题
    ORA-12560:TNS:协议适配器错误
  • 原文地址:https://blog.csdn.net/Robinwang1128/article/details/136193204