汗流浃背的45分钟–上海某公司一面

前言

书接上文,昨天刚拿下某公司的一面,瞬间有了信心,开始海投,结果迎来了这场面试,被面试官狠狠拷打。

image.png

rem与em

rem是通过动态设置html上的font-size来进行页面的自适应,基本原理就是rem表示的是root em,页面中所有的值都是基于html上的font-size,相对的进行对应的变化。

em是相对长度单位,相对于其父元素来设置大小,如果父元素没有的话,就会向上追溯。

vw与vh

vw和vh是CSS3引入的视口单位,可以根据浏览器的视口的尺寸来定义元素的尺寸,从而更容易地创建响应式和自适应的布局

height:80vh; 就是创建视口高度的80%

width:80wh; 就是创建视口宽度的80%

css选择器的优先级

这里有一个从高到低的优先级顺序:

  1. 内联样式(如 style 属性) – 特异性值为 1000。
  2. ID 选择器(如 #uniqueId) – 特异性值为 0100。
  3. 类选择器(如 .className)、属性选择器(如 [type=”text”])和伪类(如 :hover) – 特异性值为 0010。
  4. 标签名(如 div)和伪元素(如 ::before) – 特异性值为 0001。
  5. 通用选择器(如 *)、子代选择器、相邻兄弟选择器(如 +)、普通兄弟选择器(如 ~) – 特异性值为 0000

重要性 (!important)
在 CSS 中,使用 !important 可以增加规则的优先级。如果两个规则具有相同的特异性,并且其中一个带有 !important,那么带有 !important 的规则将覆盖另一个规则。

  • 说一下平时用到的选择器
    • 基础选择器 div,p,a
      • 类选择器 .xxx
      • ID 选择器 : #
      • 通用选择器 : *
    • 组合选择器
      • 分组选择器 h1,h2,xxx
      • 后代选择器 #container p{xxx}
      • 子元素选择器 #container > p {xxx}
      • 相邻兄弟选择器 h1 + p{xxx}
    • 伪类选择器
      • a:link , a:visited, a:active
    • 伪元素选择器
      • ::before ::after ::first-line
    • 选择器的组合
      • 如 article > p:first-child

== 与 === 的区别

当使用==进行比较时,如果两边的操作数不是相同的类型,js会将它们转换成相同的类型然后再进行比较。

如 :

5 == '5' 

使用 === 时,两边的数据类型的值必须要完全相同时才能认为是相等的

如 :

5 === 5 
5 === '5' 

防抖和节流

用过其他的库来代替防抖和节流吗?

可以使用第三方的库lodash来引入防抖和节流的方法。

先用node安装npm install lodash

import { debounce, throttle } from 'lodash';


const debouncedFunction = debounce(function() {
  console.log('Debounced function called');
}, 300);


const throttledFunction = throttle(function() {
  console.log('Throttled function called');
}, 300);


setInterval(() => {
  debouncedFunction();
  throttledFunction();
}, 100);

这样我们就不用手搓防抖和节流函数了

能进行异步操作的方法

最早之前使用的是callback回调函数的方法:

function asyncOperation(callback) {
  setTimeout(() => {
    const result = 'Data loaded';
    callback(result);
  }, 2000);
}

asyncOperation((data) => {
  console.log(data);
});

类似这种的回调函数的写法,在多层嵌套时会有回调地狱的产生,然后为了解决这个问题官方打造了Promise方法,是一种更优雅的处理异步操作的方式,可以避免回调地狱

function asyncOperation() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const result = 'Data loaded';
      resolve(result);
    }, 2000);
  });
}

asyncOperation()
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.error(error);
  });

后面官方大大觉得Promise方法还是太丑了,响应广大程序员的号召,基于Promise的语法糖打造出了一种更为优雅的解决方案,Async/Await,它可以让异步代码看起来和同步代码一样。

async function asyncOperation() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const result = 'Data loaded';
      resolve(result);
    }, 2000);
  });
}

async function fetchData() {
  try {
    const data = await asyncOperation();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

fetchData();

聊一聊vue3的生命周期

  1. 最早执行的生命周期 setup
  2. beforeCreate:在实例化之后,数据规则和事件方法绑定创建之前
  3. created: 在实例创建之后立即被调用,此时实例已经完成了数据规则、属性和方法的绑定
  4. beforeMount; 在挂载前被调用,在服务器渲染期间,此钩子不会被调用
  5. mounted: 挂载到实例上之后调用该钩子,就是挂载到了index.html的#app上
  6. beforeUpdate: 数据更新时调用,发生在虚拟DOM打补丁之前
  7. update: 组件的DOM已经更新之后调用
  8. beforeUnmount; 实例销毁之前调用,这一步实例仍然完全可用
  9. unmounted:实例销毁之后调用

vue的缓存机制(keep-alive)

Vue Router的缓存

组件级缓存

使用 组件可以对路由视图进行缓存。当切换到其他路由时,被缓存的组件实例不会被销毁,而是会被暂停,并在再次激活时恢复。

    
        <router-view>router-view>
    
命名视图缓存

可以通过命名视图来缓存多个不同的视图组件

     
        <router-view name="main">router-view>
        <router-view name="sidebar">router-view> 
    
细粒度缓存

可以使用includeexclude属性来指定哪些组件应该被缓存

    "MyComponent"> 
        <router-view>router-view>
    

keep-alive对应的生命周期

当引入keep-alive的时候,页面第一次进入,钩子函数的触发顺序 created > mounted > activated

退出时触发deactivated,当再次进入时只触发activated。

浏览器的回退会执行哪些生命周期

假设用户从页面B回退到页面A:

页面B上的组件会经历以下钩子:

1. beforeDestory
2. destroyed

页面A上的组件会经历以下钩子

如果组件未被缓存:
1.beforeCreate
2.created
3.beforeMount
4.mounted
如果组件被缓存(< keep-alive>)
activated

简单说一下axios的请求拦截与响应拦截场景

请求拦截

请求拦截可以应用在用户鉴权上,以登录场景为例。

如果用户成功登录后,则会将一个jwt令牌存储在本地,以后的每一次请求都会将本地存储的jwt令牌放到请求头,用于校验一些需要登录权限的操作。

响应拦截

  1. 处理响应数据

    在响应到达后对响应数据进行预处理,例如JSON数据、转换日期格式等。

    axios.interceptors.response.use(function (response) { 
    if (response.data && response.data.data) { 
        response.data = response.data.data;
    }
        return response;
    });
  1. 错误处理

    对于非成功的HTTP状态码(如4xx和5xx)进行统一处理

    axios.interceptors.response.use(
    function (response) {
        return response; 
    }, function (error) {
    if (error.response.status === 401) {
        
    } 
    return Promise.reject(error);
    } );

简单聊一下角色和菜单与权限如何实现

在 Vue 3 中实现角色和权限管理涉及以下几个步骤:

首先,设计角色、菜单和权限的数据结构,并确保后端 API 提供相应的接口。

接着,使用 Vue Router 创建基础路由,并通过动态路由加载功能根据用户权限动态生成路由。为了实现动态路由,我们需要从后端获取菜单数据,然后根据这些数据创建路由对象并添加到路由实例中。同时,利用路由守卫检查用户的权限,确保用户只能访问他们被授权的页面。

最后,使用 Pinia 管理用户的角色和权限信息,并在用户登录成功后获取这些信息,以便在后续的路由导航中进行权限检查。

vue里面的组件通信

父传子