掌握前端技术面试核心知识点:HTML、CSS、JavaScript与Vue

2026-01-01 02:26:51 · 作者: AI Assistant · 浏览: 3

面试准备需要系统性地掌握HTML、CSS、java script和Vue等前端核心技术,理解其原理与应用场景,并能够灵活运用在实际项目中。本文将从高频考点出发,结合实战技巧,帮助你在技术面试中脱颖而出。

HTML&CSS

::before 和 :after 中双冒号和单冒号有什么区别?

在CSS中,::before:after 是伪元素选择器,用于在元素的内容前后插入生成内容。双冒号(::)用于伪元素,而单冒号(:)用于伪类。这是CSS3中引入的更明确的语法,帮助开发者更容易识别伪元素和伪类。

  • ::before:用于在元素内容之前插入内容。
  • :after:用于在元素内容之后插入内容。

清除浮动的方式都有哪些,优缺点是什么?

浮动会导致父元素高度塌陷,因此需要清除浮动。常见的清除浮动方式包括:

  1. 使用 clear 属性:如 .clearfix:after { content: ""; clear: both; display: table; },优点是简单直接,适用于大多数情况,缺点是需要额外的标签或类。
  2. 使用 overflow: hidden:将父元素设置为 overflow: hidden,优点是简单,缺点是可能影响布局。
  3. 使用 display: flow-root:适用于现代浏览器,优点是简洁且不影响布局,缺点是兼容性较差。
  4. 使用 flex 布局:将父元素设置为 display: flex,优点是现代且简单,缺点是兼容性不好。
  5. 使用 grid 布局:将父元素设置为 display: grid,优点是现代且简洁,缺点是兼容性差。

垂直水平居中的几种方式?

方法一:flex 布局(推荐)

.parent {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center;     /* 垂直居中 */
}
  • 优点:代码简洁,现代浏览器支持好
  • 缺点:IE10 以下不支持

方法二:绝对定位 + transform

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
  • 优点:兼容性好,不依赖父元素尺寸
  • 缺点:需要父元素设置 position: relative

方法三:绝对定位 + margin 负值

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 100px;
  margin-top: -50px;  /* 高度的一半 */
  margin-left: -100px; /* 宽度的一半 */
}
  • 优点:兼容性好
  • 缺点:需要知道子元素尺寸

方法四:绝对定位 + margin: auto

.child {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  width: 200px;
  height: 100px;
}
  • 优点:兼容性好
  • 缺点:需要知道子元素尺寸

方法五:table-cell

.parent {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
.child {
  display: inline-block;
}
  • 优点:兼容性好
  • 缺点:父元素会变成表格单元格,可能影响布局

方法六:grid 布局

.parent {
  display: grid;
  place-items: center;
}
  • 优点:代码最简洁
  • 缺点:IE 不支持

方法七:line-height(仅文本)

.parent {
  height: 200px;
  line-height: 200px;
  text-align: center;
}
  • 优点:简单
  • 缺点:只适用于单行文本

盒模型的理解,什么是标准盒模型,什么是怪异盒模型?

CSS盒模型由四部分组成:content(内容区)padding(内边距)border(边框)margin(外边距)

标准盒模型(W3C Box Model)

  • 特点:width 和 height 只包含 content 的宽高
  • 总宽度 = width + padding + border + margin
  • 总高度 = height + padding + border + margin
.box {
  box-sizing: content-box; /* 默认值 */
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  margin: 10px;
  /* 实际总宽度 = 200 + 20*2 + 5*2 + 10*2 = 270px */
}

怪异盒模型(IE Box Model / Border Box)

  • 特点:width 和 height 包含 content + padding + border
  • 总宽度 = width + margin
  • 总高度 = height + margin
.box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  margin: 10px;
  /* 实际总宽度 = 200 + 10*2 = 220px */
  /* content 实际宽度 = 200 - 20*2 - 5*2 = 150px */
}

对比总结

特性 标准盒模型(content-box) 怪异盒模型(border-box)
width/height 包含 仅 content content + padding + border
计算方式 需要手动计算总尺寸 直接设置总尺寸
使用场景 传统布局 现代布局(更直观)
默认值 不是(需设置) 不是(需设置)

实际应用

现代开发推荐使用 border-box,因为它更直观,能够避免内容溢出。可以通过全局设置来统一:

* {
  box-sizing: border-box;
}

这样设置 width: 100% 时不会超出父容器,布局更加稳定。

java script

java script 原型,原型链?

原型(Prototype)

每个 java script 对象(除 null 外)都有一个 proto 属性,指向它的原型对象(prototype)。

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log('Hello, ' + this.name);
};

const person = new Person('Alice');
person.sayHello(); // Hello, Alice

// person.__proto__ === Person.prototype
console.log(person.__proto__ === Person.prototype); // true

原型链(Prototype Chain)

当访问对象的属性或方法时,java script 会沿着原型链向上查找:

  1. 先在对象自身查找
  2. 如果找不到,在对象的 proto(即构造函数的 prototype)中查找
  3. 如果还找不到,继续在 proto.proto 中查找,直到找到 Object.prototype,如果还找不到则返回 undefined
function Animal() {}
Animal.prototype.eat = function() {
  console.log('eating...');
};

function Dog() {}
Dog.prototype = new Animal(); // 继承 Animal
Dog.prototype.bark = function() {
  console.log('barking...');
};

const dog = new Dog();
dog.eat();  // eating... (从 Animal.prototype 继承)
dog.bark(); // barking... (从 Dog.prototype)

// 原型链:dog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null

关键概念

  • constructor:每个原型对象都有一个 constructor 属性,指向构造函数
  • Object.create():创建以指定对象为原型的新对象
  • hasOwnProperty():判断属性是否为对象自身属性(非继承)

实际应用

原型继承是一个常见场景:

function Parent(name) {
  this.name = name;
}
Parent.prototype.getName = function() {
  return this.name;
};

function Child(name, age) {
  Parent.call(this, name); // 调用父构造函数
  this.age = age;
}
Child.prototype = Object.create(Parent.prototype); // 继承原型
Child.prototype.constructor = Child; // 修正 constructor

const child = new Child('Tom', 10);
console.log(child.getName()); // Tom

事件代理是什么?冒泡和捕获?

事件冒泡(Event Bubbling)

事件从子元素向上传播到父元素,直到到达文档的顶部。

事件捕获(Event Capturing)

事件从父元素向下传播到子元素,这是事件流的第三阶段。

事件流三个阶段

  1. 捕获阶段(从最外层到目标元素)
  2. 目标阶段(事件到达目标元素)
  3. 冒泡阶段(从目标元素向上传播)

事件代理(Event Delegation)

将事件监听器绑定到父元素上,而不是每个子元素,这样可以减少内存占用并提高性能。

document.getElementById('parent').addEventListener('click', function(e) {
  if (e.target.matches('.child')) {
    // 处理子元素的点击事件
  }
});

事件代理的优势

  • 减少内存占用:避免为每个子元素添加事件监听器
  • 提高性能:尤其是对大量动态元素

阻止事件传播

可以通过 stopPropagation()stopImmediatePropagation() 来阻止事件传播:

element.addEventListener('click', function(e) {
  e.stopPropagation(); // 阻止事件冒泡
});

如何解决跨域问题?

什么是跨域?

当请求的资源与当前页面的源(协议、域名、端口)不同时,就会产生跨域问题。

解决方案

  1. CORS(跨域资源共享) - 推荐
  2. 通过设置响应头 Access-Control-Allow-Origin 来允许跨域访问
  3. JSONP
  4. 通过动态创建 <script> 标签实现跨域请求
  5. 代理服务器
  6. 在服务器端设置代理,将请求转发到目标服务器
  7. postMessage(跨窗口通信)
  8. 使用 window.postMessage() 实现跨窗口通信
  9. document.domain(仅限主域相同)
  10. 适用于子域名间通信
  11. WebSocket
  12. 建立持久连接,实现双向通信

方案对比

方案 优点 缺点
CORS 安全、灵活 需要服务器配置
JSONP 简单、兼容性好 只能处理 GET 请求
代理服务器 灵活、安全 需要服务器支持
postMessage 简单、兼容性好 通信复杂
document.domain 简单 仅限主域相同
WebSocket 双向通信、实时 需要服务器支持

for 循环和 forEach 循环,哪个性能更好?

性能对比

for 循环通常比 forEach 更快,因为它是原生的 java script 循环,而 forEach 是数组的方法,内部调用了 for 循环的实现。

性能测试详细对比

const arr = [1, 2, 3, 4, 5];

// for 循环
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

// forEach 循环
arr.forEach(function(item) {
  console.log(item);
});

特殊情况

  1. 优化后的 for 循环:避免使用 arr.length 而是使用 let i = 0; while (i < arr.length) { ... }
  2. for...of 循环:适用于可迭代对象,性能与 for 循环相当
  3. 需要中断时for 循环可以使用 breakreturn,而 forEach 不能中断

实际建议

在需要高性能的场景中,推荐使用 for 循环。如果只是遍历数组元素,for...of 也是一个不错的选择。

变量提升的理解?

什么是变量提升?

在 java script 中,变量和函数声明会被提升到当前作用域的顶部,但这并不意味着它们在代码执行前被赋值。

var 的变量提升

console.log(name); // undefined,但 name 被提升
var name = 'Alice';

函数声明提升

console.log(sayHello); // function sayHello() { ... }
function sayHello() {
  console.log('Hello');
}

函数表达式不提升

console.log(sayHello); // 报错,因为 sayHello 未定义
const sayHello = function() {
  console.log('Hello');
};

let 和 const 的暂时性死区(TDZ)

console.log(name); // 报错,因为 name 在 TDZ 中
let name = 'Alice';

提升优先级

函数声明优先于变量声明提升。

实际示例

console.log(name); // undefined
var name = 'Alice';

console.log(name); // Alice
let name = 'Bob';

块级作用域(let/const)

if (true) {
  let name = 'Alice';
  console.log(name); // Alice
}
console.log(name); // 报错,因为 name 是块级作用域

避免变量提升的问题

  • 使用 letconst 替代 var
  • 避免在函数内部直接访问未声明的变量
  • 明确变量声明位置,避免混淆

防抖和节流的理解?

防抖(Debounce)

防抖是指在事件被触发后,等待一段时间再执行函数,如果在这段时间内事件再次触发,则重新计时。

function debounce(fn, delay) {
  let timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

节流(Throttle)

节流是指在一定时间间隔内只执行一次函数,防止函数被频繁调用。

function throttle(fn, delay) {
  let last = 0;
  return function() {
    const now = Date.now();
    if (now - last > delay) {
      fn.apply(this, arguments);
      last = now;
    }
  };
}

防抖 vs 节流

特点 防抖 节流
执行时机 事件停止后执行 一定时间间隔执行
使用场景 防止频繁触发(如输入搜索) 控制触发频率(如滚动监听)
是否中断 可以中断 不能中断

数组去重的方式都有哪些?

方法一:Set(推荐)

const arr = [1, 2, 3, 2, 1];
const unique = [...new Set(arr)];

方法二:filter + indexOf

const unique = arr.filter((item, index, array) => array.indexOf(item) === index);

方法三:reduce

const unique = arr.reduce((acc, item) => {
  if (!acc.includes(item)) {
    acc.push(item);
  }
  return acc;
}, []);

方法四:for 循环 + 新数组

const unique = [];
for (let i = 0; i < arr.length; i++) {
  if (unique.indexOf(arr[i]) === -1) {
    unique.push(arr[i]);
  }
}

方法五:对象/Map 去重

const unique = Object.keys(arr.reduce((acc, item) => {
  acc[item] = true;
  return acc;
}, {})).map(Number);

方法六:Map 去重(推荐处理对象)

const unique = Array.from(new Map(arr.map(item => [item, true])).keys());

方法对比

方法 优点 缺点
Set 简洁、高效 不适用于对象
filter + indexOf 适用于简单数组 性能较差
reduce 灵活、可拓展 代码较长
for 循环 + 新数组 易于理解 代码较长
对象/Map 去重 可处理对象 需要额外处理
Map 去重 推荐处理对象 仅适用于对象

手写深拷贝的逻辑,讲述一下?

什么是深拷贝?

深拷贝是将对象的所有属性和嵌套对象都进行复制,确保新对象与原对象完全独立。

基础版本(只处理对象和数组)

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  const clone = Object.assign({}, obj);
  for (let key in clone) {
    if (typeof clone[key] === 'object') {
      clone[key] = deepClone(clone[key]);
    }
  }
  return clone;
}

完整版本(处理各种边界情况)

function deepClone(obj) {
  if (obj === null) return obj;
  if (typeof obj !== 'object') return obj;
  const clone = Object.create(Object.getPrototypeOf(obj));
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
}

使用示例

const original = { name: 'Alice', age: 30 };
const cloned = deepClone(original);
console.log(cloned); // { name: 'Alice', age: 30 }

其他实现方式

  1. JSON 序列化(简单但不完美)
  2. 适用于简单对象
  3. 无法处理函数、undefined、Symbol 类型

  4. 使用 structuredClone(现代浏览器)

  5. 支持更复杂的对象
  6. 适用于现代浏览器

核心要点总结

  • 使用 JSON.stringifyJSON.parse 是最简单的深拷贝方式
  • 处理嵌套对象、函数、Symbol 等边界情况需要更复杂的逻辑
  • 现代浏览器推荐使用 structuredClone

this 指向的理解?

this 是什么?

在 java script 中,this 是一个关键字,它指向当前执行上下文的上下文对象。

绑定规则

  1. 默认绑定(独立函数调用):this 指向全局对象(在浏览器中是 window)
  2. 隐式绑定(对象方法调用):this 指向调用该方法的对象
  3. 显式绑定(call/apply/bind):this 可以被显式绑定到特定对象
  4. new 绑定(构造函数调用):this 指向新创建的对象
  5. 箭头函数(词法绑定):this 由外层作用域决定

优先级总结

默认绑定 < 隐式绑定 < 显式绑定 < new 绑定 < 箭头函数

常见面试题总结

  • this 在函数中指向谁?
  • this 在对象方法中如何绑定?
  • 如何手动绑定 this

如何使用 Promise 封装原生 Ajax?

原生 Ajax 回顾

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(xhr.responseText);
  }
};
xhr.send();

Promise 封装 GET 请求

function get(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error('请求失败'));
      }
    };
    xhr.onerror = function() {
      reject(new Error('网络错误'));
    };
    xhr.send();
  });
}

Promise 封装 POST 请求

function post(url, data) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error('请求失败'));
      }
    };
    xhr.onerror = function() {
      reject(new Error('网络错误'));
    };
    xhr.send(JSON.stringify(data));
  });
}

通用封装(支持所有请求方法)

function request(method, url, data) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url, true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onload = function() {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error('请求失败'));
      }
    };
    xhr.onerror = function() {
      reject(new Error('网络错误'));
    };
    xhr.send(data ? JSON.stringify(data) : null);
  });
}

使用 async/await

async function fetchData() {
  try {
    const response = await request('GET', 'https://api.example.com/data');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

核心要点

  • Promise 是处理异步操作的现代方式
  • async/await 是 Promise 的语法糖,使代码更清晰
  • 封装 Ajax 请求可以提高代码的复用性和可维护性

箭头函数和普通函数的区别?

语法对比

特点 普通函数 箭头函数
this 指向 由执行上下文决定 由外层作用域决定
构造函数 可以作为构造函数 不可以作为构造函数
arguments 支持 arguments 对象 不支持 arguments 对象
prototype 有 prototype 属性 没有 prototype 属性
yield 可以使用 yield 不可以使用 yield
词法绑定 不是

对比表格

特点 箭头函数 普通函数
this 指向 词法绑定 运行时绑定
构造函数 不可以 可以
arguments 不支持 支持
prototype 没有
yield 不支持 支持
适用场景 作为回调函数、事件处理 作为构造函数、生成器函数

使用场景

  • 适合使用箭头函数:作为回调函数、事件处理、对象方法
  • 不适合使用箭头函数:作为构造函数、生成器函数、需要修改 this 的情况

总结

箭头函数在语法和功能上与普通函数有很多不同,选择使用时需要根据具体场景。在需要 this 绑定和生成器功能时,应该使用普通函数。

浏览器环境中事件循环的理解?

什么是事件循环?

事件循环是浏览器中处理异步任务的核心机制,它允许 java script 在等待异步操作完成时继续执行代码。

java script 执行机制

java script 是单线程语言,所有代码按顺序执行。当遇到异步操作时,会将任务放入任务队列中,等待事件循环处理。

执行顺序

  1. 同步代码按顺序执行
  2. 异步代码被放入任务队列
  3. 事件循环从任务队列中取出任务并执行

宏任务和微任务

  • 宏任务(MacroTask):如 setTimeoutsetIntervalsetImmediate(Node.js)
  • 微任务(MicroTask):如 Promise.thenPromise.catchMutationObserverqueueMicrotask

宏任务(MacroTask)

console.log('Start');
setTimeout(() => {
  console.log('Timeout');
}, 0);
console.log('End');

微任务(MicroTask)

console.log('Start');
Promise.resolve().then(() => {
  console.log('Promise');
});
console.log('End');

执行规则

  • 同步代码执行
  • 执行所有微任务
  • 执行所有宏任务
  • 重复上述过程

经典示例

console.log('Start');
setTimeout(() => {
  console.log('Timeout');
}, 0);
Promise.resolve().then(() => {
  console.log('Promise');
});
console.log('End');

复杂示例

console.log('Start');
setTimeout(() => {
  console.log('Timeout');
}, 0);
Promise.resolve().then(() => {
  console.log('Promise');
});
console.log('End');

async/await 的执行

async function example() {
  console.log('Start');
  await new Promise(resolve => setTimeout(resolve, 0));
  console.log('Awaited');
}
example();
console.log('End');

实际应用场景

  • 处理异步请求
  • 控制流程顺序
  • 提高代码可读性

总结

事件循环是浏览器中处理异步任务的核心机制,理解其原理和执行顺序是 java script 面试中的高频考点。掌握宏任务和微任务的区别,以及 async/await 的执行机制,能够帮助你在面试中展现出扎实的 java script 基础。

=== 和 Object.is() 的区别?

=== 严格相等

严格相等运算符(===)在比较值时,会同时比较类型和值,如果类型不同则直接返回 false。

Object.is() 同值相等

Object.is() 是严格相等的增强版本,支持处理 NaN 和 +0 与 -0 的比较问题。

核心区别

  1. NaN 的比较=== 认为 NaN 不等于 NaN,而 Object.is() 认为 NaN 等于 NaN
  2. +0 和 -0 的比较=== 认为 +0 等于 -0,而 Object.is() 认为它们不相等

对比表格

比较 === Object.is()
NaN false true
+0 和 -0 true false

使用场景

  • 推荐使用 ===,因为它在大多数情况下足够,并且性能更好
  • Object.is() 适用于特殊场景,如需要区分 +0 和 -0

实际应用

在需要精确比较数值时,使用 Object.is() 可以避免一些常见的错误:

console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true

console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false

Promise 的理解?

Promise 是什么?

Promise 是用于处理异步操作的对象,它有三种状态:pending(等待中)fulfilled(已解决)rejected(已拒绝)

三种状态

  • pending:初始状态
  • fulfilled:操作成功
  • rejected:操作失败

基本用法

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    resolve('Success');
  }, 1000);
});

promise.then(result => {
  console.log(result); // Success
}).catch(error => {
  console.error(error);
});

核心方法

  1. then() - 处理成功
  2. catch() - 处理失败
  3. finally() - 无论成功或失败都执行
promise.then(result => {
  console.log(result); // Success
}).catch(error => {
  console.error(error);
}).finally(() => {
  console.log('Finally');
});

静态方法

  1. Promise.resolve() - 快速创建成功的 Promise
  2. Promise.reject() - 快速创建失败的 Promise
  3. Promise.all() - 等待所有 Promise 完成
  4. Promise.race() - 谁先完成用谁
  5. Promise.allSettled() - 等待所有 Promise 完成(不管成功失败)

async/await(Promise 的语法糖)

async function example() {
  try {
    const result = await new Promise((resolve) => {
      setTimeout(() => resolve('Success'), 1000);
    });
    console.log(result); // Success
  } catch (error) {
    console.error(error);
  }
}

实际应用

  • 封装 Ajax 请求:使用 Promise 封装 Ajax 请求,提高代码可读性
  • 处理异步流程:使用 async/await 控制异步流程顺序
  • 错误处理:使用 catch() 或 try/catch 处理异步错误

总结

Promise 是处理异步操作的强大工具,理解其原理和方法对于前端开发至关重要。掌握 async/await 的执行机制和错误处理方式,可以写出更加清晰和高效的异步代码。

递归函数的理解?

什么是递归?

递归是指函数在执行过程中调用自身,常用于处理树形结构、分治算法等。

基本结构

function factorial(n) {
  if (n === 0) return 1;
  return n * factorial(n - 1);
}

经典示例

  1. 计算阶乘
  2. 斐波那契数列
  3. 数组求和
  4. 树形结构遍历

递归 vs 循环

优点 缺点
代码简洁 可能导致栈溢出
适合处理树形结构 递归深度受限制

优缺点

  • 优点:代码简洁,适合处理树形结构
  • 缺点:可能导致栈溢出,递归深度受限制

优化:尾递归

尾递归是指递归调用是函数的最后一步操作,可以被优化成循环。

实际应用场景

  • 计算阶乘
  • 遍历树形结构
  • 分治算法

总结

递归是一种强大的编程技巧,但在使用时需要注意递归深度和栈溢出的问题。掌握递归与循环的区别,以及如何优化递归,是面试中的常见考点。

Vue

Vue 的修饰符都有哪些?

Vue 的修饰符是用于修改事件或表单的默认行为的,常见的修饰符包括:

  • .prevent:阻止默认事件行为(如表单提交)
  • .stop:阻止事件冒泡
  • .capture:使用事件捕获阶段
  • .self:阻止事件冒泡到父元素
  • .once:只触发一次事件

Vue 自定义指令的理解?

自定义指令是 Vue 提供的一种扩展机制,允许我们自定义一些指令来操作 DOM。

Vue.directive('highlight', {
  bind(el, binding) {
    el.style.backgroundColor = binding.value;
  }
});

v-if 和 v-show 的区别?

  • v-if:根据条件判断是否渲染元素
  • v-show:根据条件控制元素的显示状态

v-model 可以用在哪些表单上?

v-model 可以用于:

  • text:文本输入框
  • number:数字输入框
  • checkbox:复选框
  • radio:单选框
  • select:下拉框
  • textarea:多行文本框

Vue 中 computed 和 watch 和 methods 的区别?

  • computed:计算属性,基于响应式依赖进行缓存,提高性能
  • watch:监听数据变化,适合执行异步操作
  • methods:方法,适合执行同步操作

watch 监听对象,新值和旧值一样,如何区分新旧值?

在监听对象时,新值和旧值一样,但可以通过 deep true 来监听属性变化。

watch: {
  someObject: {
    handler(newVal, oldVal) {
      // 处理新旧值变化
    },
    deep: true
  }
}

Vue 的组件通讯?

组件通讯是 Vue 中的一个重要概念,主要方式包括:

  1. props 和 $emit:父子组件之间通信
  2. $root:全局通信
  3. $event:向上传递参数
  4. provide/inject:祖孙组件之间通信
  5. Vuex:状态管理
  6. Event Bus:全局事件总线

Vue 的生命周期钩子函数?

Vue 2.x 生命周期钩子

  • 创建阶段(Creation):
  • beforeCreate
  • created

  • 挂载阶段(Mounting):

  • beforeMount
  • mounted

  • 更新阶段(Updating):

  • beforeUpdate
  • updated

  • 销毁阶段(Destruction):

  • beforeDestroy
  • destroyed

Vue 3.x 生命周期钩子

  • 创建阶段(Creation)
  • onBeforeCreate
  • onCreated

  • 挂载阶段(Mounting)

  • onBeforeMount
  • onMounted

  • 更新阶段(Updating)

  • onBeforeUpdate
  • onUpdated

  • 销毁阶段(Destruction)

  • onBeforeUnmount
  • onUnmounted

Vue 2.x 与 Vue 3.x 生命周期钩子对比

钩子 Vue 2.x Vue 3.x
创建阶段 beforeCreate, created onBeforeCreate, onCreated
挂载阶段 beforeMount, mounted onBeforeMount, onMounted
更新阶段 beforeUpdate, updated onBeforeUpdate, onUpdated
销毁阶段 beforeDestroy, destroyed onBeforeUnmount, onUnmounted

vue-router 的导航守卫?

导航守卫是 vue-router 提供的一种机制,用于在导航过程中进行拦截和处理。

全局守卫
  1. 全局前置守卫 beforeEach
  2. 全局解析守卫 beforeResolve
  3. 全局后置钩子 afterEach
路由独享守卫 beforeEnter
const router = new VueRouter({
  routes: [
    {
      path: '/user',
      component: User,
      beforeEnter: (to, from, next) => {
        // 检查权限
        if (user.isLoggedIn()) {
          next();
        } else {
          next('/login');
        }
      }
    }
  ]
});
组件内守卫
  1. beforeRouteEnter:在组件创建前执行
  2. beforeRouteUpdate:在组件更新前执行
  3. beforeRouteLeave:在组件离开前执行

执行顺序

  • 全局前置守卫 beforeEach
  • 路由独享守卫 beforeEnter
  • 组件内守卫 beforeRouteEnter
  • 组件内守卫 beforeRouteUpdate
  • 组件内守卫 beforeRouteLeave
  • 全局后置钩子 afterEach

vuex 的 state、getters、mutations、actions 的区别?

  • state:保存应用