ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

前端高频面试题(含答案)

前端高频面试题(含答案) 总结前端常见面试题不断更新中...一、html和css面试题1. 语义化标签每一个标签都有自己的含义能够清晰表达内容含义的html标签p段落 、h2 标题、nav导航、footer页脚等。优点1无障碍性语义化标签可以更好地支持屏幕阅读器和其他辅助技术2可读性高有利于开发与维护3搜索引擎优化搜索引擎可以更好的理解页面内容从而提升排名2. 块级元素和行内元素区别1块级元素独占一行行内元素水平显示2块级元素默认宽度100%行内元素默认宽度由内容撑开3块级元素可以设置宽高行内元素设置宽高不生效4块级元素可以设置margin和padding的四周行内元素只能设置margin和padding的左右5块级元素默认display:block;行内元素默认display:inline;6块级元素 div、ul、li、ol、dl、dt、dd、hn、p、header、nav、footer、aside、section、srticle等7行内元素 a、span、img、input、button、b、i、u等8布局时块级元素可以包含块级元素和行内元素行内元素不可以包含块级元素3. css选择器的优先级优先级!important 行内样式 ID选择器 类选择器 元素选择器 全局选择器权重 1000 100 10 14. display:none;和visibility:hidden;的区别1display:noen; 隐藏元素隐藏后不占据位置2visibility:hidden; 隐藏元素隐藏后占据位置3transform:scale(0); 缩放隐藏元素4opacity:0; 元素透明度为0隐藏元素占据位置5overflow:hidden; 溢出部分隐藏5. position的取值分别是相对于谁进行定位的1属性position:static; /*元素定位*/2属性值①static默认值 静态定位②relative相对定位相对于自己原位置定位定位后原位置保留配合left、right、bottom、top移动应用配合绝对定位使用、元素小范围移动③fixed固定定位相对于浏览器窗口定位定位后原位置不保留配合left、right、bottom、top移动应用固定在窗口某个位置④sticky粘性定位相当于相对定位和固定定位的结合⑤absolute绝对定位相当于已经定位(static除外)的父元素如果父元素没有定位逐级往上找最后相对于初始包含框(视口)定位子绝父相定位后原位置不保留配合left、right、bottom、top移动应用形成独立的一层6. 浮动1原理元素浮动后排除到文档流之外元素浮动后不占据位置元素浮动是碰到父元素的边框或者浮动元素的边框就会停止元素只有左右浮动浮动元素不会重叠任意元素都可以浮动浮动后转换为块级元素2清除浮动的方法元素浮动后不占据位置父元素的高度坍塌对后面的元素产生影响① 父元素设置高度(高度已知)② 父元素设置overflow:hidden;自动找高③ 受影响的元素加clear:both;元素回到正常的位置父元素的高度没有找到④ 空div法页面新增空元素在浮动元素后加一个空div空div{clear:both;}⑤ 伪对象法父元素::after{ content:; display:block; clear:both; }7.盒模型CSS 的盒子模型是网页设计中的一个基础概念它描述了元素在页面上的布局方式。盒子模型由四个部分组成内容content、内边距padding、边框border和外边距margin。1盒子模型的组成① 内容区域content盒子中呈现实际内容的部分如文本、图片等。使用width和height属性来指定内容区域的高度和宽度。width:;元素宽度 height:;元素高度 min-width:;最小宽度 max-width:;最大宽度 min-height:;最小高度 max-height:;最大高度② 内边距padding内容区域与边框之间的空白区域用于控制内容与边框之间的距离。内边距的属性有五种即padding-top上内边距、padding-bottom下内边距、padding-left左内边距、padding-right右内边距以及综合了以上四种方向的快捷填充属性padding。设置盒子背景色属性时背景色可以延伸到填充区域。padding-top:; 上内边距 padding-bottom:; 下内边距 padding-left:; 左内边距 padding-right:; 右内边距 padding:; 简写 取一个值表示四个方向取两个值表示上下和左右取三个值表示上、左右和下取四个值表示上、右、下和左。③ 边框border包围内容区域和内边距的线条可以设定边框的样式、宽度和颜色等。边框的属性有border-style边框样式、border-width边框宽度和border-color边框颜色以及综合了以上三类属性的快捷边框属性border。边框样式border-style可以设置的值包括none无边框样式不显示边框、solid实线边框样式使用实线绘制边框、dashed虚线边框样式使用间隔的短横线绘制边框、dotted点线边框样式使用小圆点绘制边框等。border-style是必须属性必须设置border-width和border-color是可选属性默认为3px、黑色。border-style:; 边框样式 border-width:; 边框宽度 border-color:; 边框颜色 border:style color widht; 四周边框 简写 border-top:style color widhth; 上边框 简写 border-bottom:style color width; 下边框 简写 border-left:style color width; 左边框 简写 border-right:style color width; 右边框 简写④ 外边距margin盒子与周围元素之间的空白区域用于控制盒子与其他元素之间的距离。外边距的属性有五种即margin-top上外边距、margin-bottom下外边距、margin-left左外边距、margin-right右外边距以及综合了以上四种方向的快捷空白边属性margin。对于两个相邻的水平或垂直方向且设置有外边距值的盒子它们邻近部分的外边距将不是二者外边距的相加而是二者的并集。若二者邻近的外边距值大小不等则取二者中较大的值。垂直方向外边距合并margin-top:; 上外边距 margin-bottom:; 下外边距 margin-left:; 左外边距 margin-right:; 右外边距 margin:; 简写 取一个值表示四个方向取两个值表示上下和左右取三个值表示上、左右和下取四个值表示上、右、下和左。2)盒子模型的box-sizing属性①content-box默认值 标准盒模型当设置为content-box时用CSS设置的width和height是被设置在了content上。此时盒子的总宽度 width paddingleft、right borderleft、right marginleft、right高度同理。②border-box 怪异盒模型当设置为border-box时用CSS设置的width和height值为content、padding和border的总值。此时盒子的总宽度 width marginleft、right。3盒子模型的常见问题①外边距合并问题当两个上下方向的盒子垂直相邻时会发生外边距的叠加叠加后的高度等于合并前两个盒子中外边距较高的那个值。这种外边距叠加的现象只会出现在普通文档流中。②margin越界问题在某些情况下如父元素没有边框时设置第一个子元素的margin-top值可能会导致margin-top值加在父元素上。解决方法包括给父元素加边框、给父元素设置padding值、父元素加overflow:hidden;等。二、JavaScript和ES6面试题1. 和 、Object.is()区别?宽松判断只判断值两端的数据类型不同会隐式转换严格判断即判断值又判断类型两端的数据类型不同不会隐式转换Object.is()进行相等判断时一般情况和三等号的判断结果相同它处理了一些特殊情况比如-0和0不再相等两个NaN是相等的。5 5 //true 基本数据类型比较值 5 5//false [] [] //false 对象类型比较的是引用 [] [] //false2. 传值和传址1传值基本数据类型赋值let a 10; let b a;//传值复制一份值赋值以后不再有任何联系 console.log(a);//10 console.log(b);//10 b 100; console.log(a);//10 console.log(b);//1002传址引用类型赋值let a [10]; let b a;//传址把堆中的地址赋值左侧的变量指向同一个地址 console.log(a);//[10] console.log(b);//[10] b[0] 100; console.log(a);//[100] console.log(b);//[100]3. undefined和null的区别?1undefined和null都是基本数据类型中一个特殊的值2undefined表示声明变量没有赋值未定义3null表示空对象4undefined typeof返回undefinednull typeof返回object返回undefined的情况1声明变量没有赋值2函数没有返回值默认返回undefined3形参没有赋值返回undefined4数组下标越界访问没有赋值的下标返回undefined5读取对象没有的属性返回undefined6构造函数中开启严格模式并且没有new的情况下this返回undefined4. var、const 和 let 的主要区别是什么1作用都是声明变量2var有声明提升提升到所在作用域的顶部let和const没有声明提升3var可以使用写在声明之前let和const必须先声明再使用4let和const有块级作用域块级作用域中有暂时性死区5var同一个作用域中可以重复声明let和const不可以重复声明5.双感叹号有什么作用!取反!!返回值隐式转换后的布尔值!!0 //false !! //false !!undefined //false !!null //false !!NaN //false !!false //false6. 箭头函数和普通函数区别1语法箭头函数const add (a, b) a b;普通函数// 函数声明 function add(a, b) { return a b; } ​ // 函数表达式 const add function(a, b) { return a b; };2this绑定箭头函数不绑定自己的this而是继承父执行上下文中的this值。function Person() { this.age 0; ​ setInterval(() { this.age; // this 指向 Person 实例 console.log(this.age); }, 1000); } ​ const p new Person();普通函数有自己的this值通常是在调用时确定的。function Person() { this.age 0; ​ setInterval(function() { this.age; // this 指向全局对象在严格模式下为 undefined console.log(this.age); }, 1000); } ​ const p new Person(); // 不会按预期工作3arguments对象箭头函数没有arguments对象。const func () { console.log(arguments); // ReferenceError: arguments is not defined };普通函数有arguments对象。function func() { console.log(arguments); // Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] } ​ func(1, 2, 3);4prototype属性箭头函数没有prototype属性因此不能用作构造函数。const MyFunc () {}; console.log(MyFunc.prototype); // undefined ​ // 尝试用作构造函数会报错 const obj new MyFunc(); // TypeError: MyFunc is not a constructor普通函数有prototype属性可以用作构造函数。function MyFunc() {} console.log(MyFunc.prototype); // {constructor: ƒ} ​ const obj new MyFunc(); // 正常工作7. 如何判断一个对象是不是数组?1Array.isArray()let myArray [1, 2, 3]; let myObject {a: 1, b: 2}; console.log(Array.isArray(myArray)); // 输出: true console.log(Array.isArray(myObject)); // 输出: false2obj instanceof Array3Object.prototype.toString.call(obj) Array4obj.constructor Array5obj.__proto__ Array.prototype8. new操作符具体干了什么在 JavaScript 中new操作符用于创建一个类的实例。当你使用new操作符调用一个构造函数时它会执行以下步骤创建一个新的空对象。将这个新对象的__proto__属性设置为构造函数的prototype属性。执行构造函数将this绑定到新创建的对象上。如果构造函数返回一个对象则new操作符返回这个对象否则返回新创建的对象。下面是一个简单的示例展示了如何使用new操作符创建一个类的实例function Person(name, age) { this.name name; this.age age; } Person.prototype.sayHello function() { console.log(Hello, my name is ${this.name} and I am ${this.age} years old.); }; const person new Person(Alice, 30); person.sayHello(); // 输出: Hello, my name is Alice and I am 30 years old.9. 如何判断一个对象是空对象1使用Object.keys()方法function isEmptyObject(obj) { return Object.keys(obj).length 0; }这个方法会返回一个对象所有可枚举属性的数组如果数组长度为 0则说明对象为空。2使用JSON.stringify()方法function isEmptyObject(obj) { return JSON.stringify(obj) {}; }这个方法会将对象转换为 JSON 字符串如果字符串为{}则说明对象为空。3遍历对象属性function isEmptyObject(obj) { for (let key in obj) { if (obj.hasOwnProperty(key)) { return false; } } return true; }这个方法会遍历对象的所有属性如果存在属性则说明对象不为空。4使用Object.getOwnPropertyNames()方法function isEmptyObject(obj) { return Object.getOwnPropertyNames(obj).length 0; }这个方法会返回一个对象所有自有属性的数组如果数组长度为 0则说明对象为空。10. JavaScript数据类型有哪些JavaScript的数据类型可以分为两类基本数据类型和引用数据类型1基本数据类型number数字类型用于表示整数和浮点数string字符串类型用于表示文本数据用单引号或双引号括起来boolean布尔类型用于表示逻辑值只有两个值true和falseundefined未定义类型表示变量声明但未初始化时的默认值null空类型表示一个空对象指针只有一个值nullsymbol符号类型用于创建唯一的、不可变的值通常用作对象属性的键2引用数据类型object对象类型用于存储键值对的集合array数组类型用于存储有序的元素集合function函数类型用于定义可执行的代码块11. typeof和instanceof的区别在JavaScript中typeof和instanceof都是用于检查变量类型的操作符但它们的用途和行为有所不同。1typeof操作符typeof操作符用于返回一个表示操作数类型的字符串。它可以用来检查基本类型如number、string、boolean、undefined、symbol以及函数和对象返回object。typeof 42; // number typeof Hello; // string typeof true; // boolean typeof undefined; // undefined typeof Symbol(); // symbol typeof function() {}; // function typeof {}; // object typeof null; // object这是一个历史遗留问题null 实际上是一个空对象指针2instanceof操作符instanceof操作符用于检查一个对象是否是某个构造函数的实例。它通过检查对象的原型链来确定对象是否是某个类的实例。function Person() {} const person new Person(); person instanceof Person; // true person instanceof Object; // true因为所有对象都是 Object 的实例 const array []; array instanceof Array; // true array instanceof Object; // true因为数组也是对象区别总结typeof:用于检查基本类型和函数。返回一个表示类型的字符串。对于null返回object这是一个历史遗留问题。instanceof:用于检查对象是否是某个构造函数的实例。通过检查对象的原型链来确定。对于基本类型返回false因为它们不是对象。12. 原型和原型链1原型在 JavaScript 中每个对象都有一个内部链接指向另一个对象这个对象就是原型。当你尝试访问一个对象的属性或方法时如果该对象本身没有这个属性或方法JavaScript 会沿着这个内部链接即原型链查找直到找到该属性或方法或者到达原型链的末端即Object.prototype。2原型链原型链是由一系列通过原型链接起来的对象组成的。当访问一个对象的属性或方法时如果对象本身没有该属性或方法JavaScript 会沿着原型链向上查找直到找到该属性或方法或者到达原型链的末端即Object.prototype。如果在整个原型链上都找不到该属性或方法JavaScript 会返回undefined。总结1在JS里万物皆对象。方法Function是对象方法的原型(Function.prototype)是对象。因此它们都会具有对象共有的特点。即对象具有属性__proto__可称为隐式原型一个对象的隐式原型指向构造该对象的构造函数的原型这也保证了实例能够访问在构造函数原型中定义的属性和方法。原型对象也有一个属性叫做constructor这个属性包含了一个指针指回原构造函数(__proto__和constructor属性是对象所独有的)。2函数这个特殊的对象除了和其他对象一样有上述__proto__属性之外还有自己特有的属性——原型属性prototype这个属性是一个指针指向一个对象这个对象的用途就是包含所有实例共享的属性和方法我们把这个对象叫做原型对象prototype属性是函数所独有的3__proto__属性的作用就是当访问一个对象的属性时如果该对象内部不存在这个属性那么就会去它的__proto__属性所指向的那个对象父对象里找一直找直到__proto__属性的终点null再往上找就相当于在null上取值会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。4prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法。5constructor属性的含义就是指向该对象的构造函数。13.call、apply、bind的区别bind、call和apply都是 JavaScript 中用于改变函数执行上下文this 指向的方法但它们之间有一些区别1call和apply功能相同call和apply的主要功能是相同的都是在调用函数时指定函数内部的this指向并立即执行函数。参数传递方式不同call方法接受的参数是一个一个传递的第一个参数是要绑定的this值后面的参数是函数调用时需要传递的参数。apply方法接受的参数是一个数组第一个参数是要绑定的this值第二个参数是一个数组数组中的元素是函数调用时需要传递的参数。2bind功能bind方法的主要功能是创建一个新的函数这个新函数的this指向被绑定到指定的对象并且可以在新函数中传递参数。延迟执行bind方法不会立即执行函数而是返回一个新的函数这个新函数可以在稍后的时间点被调用。const person { name: Alice, sayHello: function(greeting) { console.log(${greeting}, my name is ${this.name}); } }; const anotherPerson { name: Bob }; // 使用 call 方法 person.sayHello.call(anotherPerson, Hello); // 输出: Hello, my name is Bob // 使用 apply 方法 person.sayHello.apply(anotherPerson, [Hi]); // 输出: Hi, my name is Bob // 使用 bind 方法 const boundFunction person.sayHello.bind(anotherPerson); boundFunction(Hey); // 输出: Hey, my name is Bob在这个示例中person.sayHello是一个函数它有一个参数greeting。anotherPerson是一个对象它有一个属性name。call和apply方法立即执行了person.sayHello函数并将this指向anotherPerson。bind方法返回了一个新的函数boundFunction这个新函数的this指向anotherPerson并且可以在稍后的时间点被调用。总结call和apply用于立即调用函数并指定函数内部的this指向它们的区别在于参数传递方式不同。bind用于创建一个新的函数这个新函数的this指向被绑定到指定的对象并且可以在新函数中传递参数它不会立即执行函数。三、vue面试题1. v-if 和 v-show 有什么区别1v-if是动态的向DOM树内添加或者删除DOM元素v-show是通过设置DOM元素的display样式属性控制显隐2v-if也是惰性的如果在初始渲染时条件为假则什么也不做——直到条件第一次变为真时才会开始渲染条件块。相比之下v-show就简单得多——不管初始条件是什么元素总是会被渲染并且只是简单地基于 CSS 进行切换。v-if如果初始条件为false不渲染v-show不管初始条件是什么总是被渲染3v-if有更高的切换消耗v-show有更高的初始渲染消耗4v-if适合运行时条件很少改变v-show适合频繁切换。2. computed 和 watch有什么区别1对于Computed它支持缓存只有依赖的数据发生了变化才会重新计算不支持异步当Computed中有异步操作时无法监听数据的变化如果一个属性是由其他属性计算而来的这个属性依赖其他的属性一般会使用computed由现有属性计算得到一个新的属性如果computed属性的属性值是函数那么默认使用get方法函数的返回值就是属性的属性值在computed中属性有一个get方法和一个set方法当数据发生变化时会调用set方法。2对于Watch它不支持缓存数据变化时它就会触发相应的操作支持异步监听监听的函数接收两个参数第一个参数是最新的值第二个是变化之前的值当一个属性发生变化时就需要执行相应的操作 监听已有属性的变化监听数据必须是data中声明的或者父组件传递过来的props中的数据当发生变化时会触发其他操作函数有两个的参数immediate组件加载立即触发回调函数deep深度监听发现数据内部的变化在复杂数据类型中使用例如数组中的对象发生变化。需要注意的是deep无法监听到数组和对象内部的变化。3. 怎样理解 Vue 的单向数据流父传子通过props形成一个单行向下的数据流子组件不可以直接修改父组件的数据可以通过自定义事件$emit通知父组件修改所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定父级 prop 的更新会向下流动到子组件中但是反过来则不行。这样会防止从子组件意外变更父级组件的状态从而导致你的应用的数据流向难以理解。额外的每次父级组件发生变更时子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了Vue 会在浏览器的控制台中发出警告。4. data为什么是一个函数而不是对象JavaScript中的对象是引用类型的数据当多个实例引用同一个对象时只要一个实例对这个对象进行操作其他实例中的数据也会发生变化。而在Vue中更多的是想要复用组件那就需要每个组件都有自己的数据这样组件之间才不会相互干扰。所以组件的数据不能写成对象的形式而是要写成函数的形式。数据以函数返回值的形式定义这样当每次复用组件的时候就会返回一个新的data也就是说每个组件都有自己的私有数据空间它们各自维护自己的数据不会干扰其他组件的正常运行。5.vue2 生命周期对于 vue 来讲生命周期就是一个 vue 实例从创建到销毁的过程。在生命周期的过程中会运行着一些叫做生命周期的函数给予了开发者在不同的生命周期阶段添加业务代码的能力。1beforeCreate是new Vue()之后触发的第一个钩子在当前阶段data、methods、computed以及watch上的数据和方法都不能被访问。2created在实例创建完成后发生当前阶段已经完成了数据观测也就是可以使用数据更改数据在这里更改数据不会触发updated函数。可以做一些初始数据的获取在当前阶段无法与Dom进行交互如果非要想可以通过vm.$nextTick 延迟执行来访问Dom。最早发送网络请求的地方无法操作DOM3beforeMount发生在挂载之前在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成即将开始渲染。在此时也可以对数据进行更改不会触发updated。4mounted在挂载完成后发生在当前阶段真实的Dom挂载完毕数据完成双向绑定可以访问到Dom节点使用$refs属性对Dom进行操作。最早操作DOM的地方5beforeUpdate发生在更新之前也就是响应式数据发生更新虚拟dom重新渲染之前被触发你可以在当前阶段进行更改数据不会造成重渲染。数据是新的视图是旧的6updated发生在更新完成之后当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据因为这可能会导致无限循环的更新。数据是新的视图也是新的7beforeDestroy发生在实例销毁之前在当前阶段实例完全可以被使用我们可以在这时进行善后收尾工作比如清除计时器。8destroyed发生在实例销毁之后这个时候只剩下了dom空壳。组件已被拆解数据绑定被卸除监听被移出子实例也统统被销毁。9activated在keep-alive中可以使用activated代替mounted10deactivated在keep-alive中可以使用deactivated代替beforeDestroy11errorCaptured捕获后代组件的错误通过return false阻止错误向上传播keep-alive可以实现组件缓存当组件切换时不会对当前组件进行卸载。常用的两个属性include/exclude允许组件有条件的进行缓存。两个生命周期activated/deactivated用来得知当前组件是否处于活跃状态。6. vue子组件和父组件执行顺序6.1 加载渲染过程1父组件 beforeCreate2父组件 created3父组件 beforeMount4子组件 beforeCreate5子组件 created6子组件 beforeMount7子组件 mounted8父组件 mounted6.2 更新过程1父组件 beforeUpdate2子组件 beforeUpdate3子组件 updated4父组件 Updated6.3 销毁过程1父组件 beforeDestroy2子组件 beforeDestroy3子组件 destroyed4父组件 destroyed7. 在哪个生命周期内调用异步请求created最早网络请求的位置可以在钩子函数created、beforeMount、mounted中进行异步请求因为在这三个钩子函数中data已经创建可以将服务端返回的数据进行赋值。但是本人推荐在created钩子函数中调用异步请求因为在created钩子函数中调用异步请求有以下优点- 能更快获取服务端数据减少页面loading时间- ssr不支持beforeMount、mounted钩子函数所以放在created中有助于一致性8. 常用内置指令v-text替换元素之间的文本不识别html标签v-html替换元素之间的文本识别html标签v-if控制元素的渲染和卸载取布尔值v-else配合v-if、或者v-else-if使用不需要表达式v-else-if配合v-if或者v-else-if使用v-show控制元素的显示和隐藏控制display属性v-for遍历数组和对象配合:key使用v-bind动态绑定html属性简写为:v-on绑定事件简写为v-model表单输入绑定双向数据绑定v-slot插槽简写#v-pre不需要表达式不编译{{}}之间的内容v-once不需要表达式只渲染一次v-cloak不需要表达式这个指令保持在元素上直到关联实例结束编译9. vue组件通信9.1 props父组件通过props向子组件传递数据子组件通过$emit和父组件通信。步骤1父组件中调用子组件时自定义属性child msg我是你爸爸 :numnum/child2子组件中通过props接收props:{ msg:{ type:String,//类型 default:hello//默认值 }, num:{ type:Number, require:true//必填项 } }9.2 $emit$emit绑定一个自定义事件当这个事件被执行的时候就会将参数传递给父组件而父组件通过v-on监听并接收参数。步骤1子组件中自定义事件this.$emit(事件名,实参1,实参2,...)2父组件v-on绑定自定义事件child 事件名方法名/child methods: { 方法名(参数) { // 方法体 } }9.3 refvue中通过ref可以获取子组件实例和DOM元素步骤1给DOM元素或者子组件添加ref属性child refmyChild/child2通过this.$refs获取this.$refs.myChild9.4 边界处理1$root当前组件树的跟vue实例如果当前实例没有父实例此实例将会是其自己。用于获取根组件上的数据2$parent使用$parent可以让组件访问父组件的实例访问的是上一级父组件的属性和方法3$children使用$children可以让组件访问子组件实例但是$children并不能保证顺序也不是响应式的。9.5 EventBus这种方法通过一个空的vue实例作为中央事件总线事件中心用它来触发事件和监听事件从而实现任何组件间的通信包括父子、隔代、兄弟组件。步骤1新建bus文件空vue实例//bus.js import Vue from vue export default new Vue;2A兄弟传值import bus from /common/bus bus.$emit(事件名称,数据)3B兄弟接收import bus from /common/bus bus.$on(自定义事件,(data){ //data是A组件数据 })9.6 provide|inject这种方式就是vue中的依赖注入该方法用于父子组件之间的通信。当然这里所说的父子不一定是真正的父子也可以是祖孙组件在层数很深的情况下可以使用这种方法来进行传值。就不用一层一层的传递了。provide用来发送数据和方法inject用来接收数据和方法步骤1父组件提供数据provided() { return { key: this.data中的数据 } },2后代组件接收数据inject: [key,key2],9.7 $attrs和$listeners用于多级组件嵌套需要传递数据9.8 vuexvuex是一个转为vue.js应用程序开发的状态管理模式。vuex的状态存储是响应式的当vue组件从store中读取状态的时候若store中的状态发生变化那么相应的组件也会相应的得到高效更新。10. 导航守卫10.1 全局守卫router.beforeEach((to, from, next) {}) router.beforeResolve((to, from, next) {}) router.afterEach((to, from) {})10.2 路由独享守卫beforeEnter:(to,from,next){}10.3 组件内守卫beforeRouteEnter(to, from, next){ //不能获取组件实例this }, beforeRouteUpdate(to, from, next){}, beforeRouteLeave(to, from, next){}11.Vue2 和 Vue3 的核心区别1. 响应式原理不同最本质的区别Vue 2Object.defineProperty递归遍历 data把每个属性转成 getter/setter 来劫持读写。缺点无法检测对象新增/删除属性要用Vue.set/Vue.delete。无法直接通过下标修改数组arr[0] x不触发更新Vue 2 重写了数组的 7 个方法。初始化时要递归遍历所有属性数据量大时性能差。Vue 3Proxy用Proxy代理整个对象配合Reflect操作。优点能检测新增/删除属性、数组下标修改。惰性代理只有访问到深层属性才递归初始化更快。支持Map、Set、WeakMap等新数据结构。2. API 风格Options API vs Composition APIVue 2主要用 Options API逻辑按data、methods、computed、watch分散组织。Vue 3引入Composition APIsetup、ref、reactive、computed、watch可以按功能逻辑聚合代码更适合大型组件和逻辑复用。3. 虚拟 DOM 重写 编译优化性能更好TS 支持更友好4. 生命周期变化Vue 2Vue 3beforeCreate / createdsetupbeforeMount / mountedonBeforeMount / onMountedbeforeUpdate / updatedonBeforeUpdate / onUpdatedbeforeDestroy / destroyedonBeforeUnmount / onUnmountedsetup在beforeCreate之前执行替代了 created 阶段的逻辑。12. 权限路由和按钮级权限你怎么实现的参考RUOYI框架。路由权限用动态路由登录后根据后端返回的菜单/权限码在前端路由表里过滤出有权限的部分通过router.addRoute动态注册并在全局守卫里做拦截和刷新恢复。未授权直接 404 兜底。按钮权限封装v-permission指令按权限码控制v-if显示隐藏状态配合统一的权限 map避免在模板里硬写判断。刷新页面路由丢失怎么办→ 守卫里判断routesLoaded标志重新拉权限注册再next({...to, replace:true})。权限码太多怎么管理→ 按模块分组或直接用后端菜单树。动态路由 404 页面怎么处理→ 404 要最后注册否则会拦截所有路由。Vue2 和 Vue3 区别→addRoutesvsaddRouteVue3 还可用 Pinia 存权限、script setup写指令。13. Excel 导入导出你怎么做导出用后端返回 Blob 流前端URL.createObjectURL触发下载并记录文件名导入走FormData上传 模板下载前端做文件类型和大小校验、读取预览。14. 国产化适配银河麒麟/统信 UOS你踩过哪些坑怎么统一收敛典型坑浏览器内核差异导致 flex 布局错位、CSS 变量/某些 API 不支持、滚动条和字体渲染不同、脚本时序问题。我抽了一层全局兼容方案统一 reset、用变量替代差异属性、对不支持 API 做 polyfill、异常拦截层兜底。把散落的 12 类问题收敛成统一处理新页面直接继承不再逐页打补丁。15. Vuex 和 Pinia 你都用过怎么看Vue2 项目用 Vuex模块化 命名空间Vue3 新项目用 Pinia去掉 mutations、API 更简洁、TS 推导好、DevTools 体验佳。我的建议是按框架版本选不强行混用迁移时可先并存再逐步把 Vuex module 改写成 store。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进