软通外包面试总结

Vue3 和 Vue2 的区别有哪些

  • 响应式系统的底层实现完全不同

    Vue2 用的是Object.defineProperty来监听数据变化,但这种方案对数组和新增属性的支持不够友好,比如直接修改数组下标或者给对象新增属性时不会触发更新,得用Vue.set之类的特殊方法。而 Vue3 换成了Proxy,它能直接监听整个对象,无论是数组操作还是新增属性都能自动捕获,底层实现更干净,性能也更好。

  • 代码组织方式的变化

    Vue2 用的是 Options API,比如把数据、方法、生命周期都写在datamethods这些固定选项里。这在简单组件里很清晰,但复杂组件容易让代码分散在不同区域,比如一个功能的逻辑可能分散在datamethods里。Vue3 引入了 Composition API,也就是setup函数,允许我们像写函数一样按功能组织代码。比如一个搜索功能,可以把相关的响应式变量、方法和生命周期都写在一个useSearch函数里,复用起来也更方便。

  • 性能优化

    性能优化方面,Vue3 做了很多改进。比如它的虚拟 DOM 算法更智能,能跳过静态节点的比对,还支持了 Fragment(组件可以有多个根节点)、Teleport(把组件渲染到 DOM 任意位置)这些新特性。另外打包体积也更小,因为 Vue3 支持 Tree-shaking,没用到的模块不会被打包进去。

  • TypeScript 的支持

    Vue3 本身是用 TypeScript 重写的,类型推断更友好,写起来比 Vue2 顺手很多。比如在 Vue2 里用 TS,有时候得用装饰器或者特殊的类型声明,而 Vue3 直接就能和 TS 无缝配合。

  • API 变化

    比如生命周期钩子名字变了,beforeDestroy改成了beforeUnmountdestroyed变成unmounted;全局 API 的创建方式从new Vue()变成了createApp(),这样能避免全局配置污染。还有v-model的用法更灵活了,Vue2 里一个组件只能有一个v-model,Vue3 可以绑定多个,比如同时用v-model:titlev-model:content,相当于替代了 Vue2 的.sync修饰符。


Vue3 的静态标记

静态标记是 Vue3 性能优化里的一个关键点。简单来说,Vue3 在编译模板的时候,会‘聪明’地把那些永远不会变的元素标记出来。比如说,模板里写了个静态的<div class="title">我是标题</div>,或者一个纯展示用的<p>这段文字永远不会改</p>,Vue3 在生成虚拟 DOM 的时候会给这些节点打上标记,告诉后续的更新流程:‘这些内容不用再检查了,反正不会变’。

这样做最大的好处是跳过无用的比较。比如当数据变化导致组件重新渲染时,Vue2 的虚拟 DOM 会从头到尾对比新旧节点树,而 Vue3 因为有静态标记,遇到这些标记过的节点就直接跳过了,省去了大量没必要的计算。如果页面上有很多静态内容(比如企业官网的页头、页脚),性能提升会特别明显。


隐藏元素的方式

  • display:none

    该元素不但被隐藏了,而且该元素原本占用的空间也会从页面布局中消失,也就无法响应事件。

  • html 的 hidden 属性

    1
    <div hidden>隐藏</div>

    设置 hidden 属性,会应用浏览器默认样式[hidden] {display: none;},所以注意不要和 display 属性同时使用。

  • 设置尺寸

    1
    2
    3
    height: 0;
    padding: 0;
    overflow: hidden;

    可以通过使用最小化其尺寸被隐藏 width,height,padding,border-width 和/或 font-size。还需多设置一个 overflow: hidden;以确保内容不会溢出。

  • position

    1
    2
    position: absolute;
    left: -999px;

    利用 position 属性,设置较大的值,将元素移除屏幕以实现隐藏的效果。

  • clip/clip-path

    1
    2
    3
    4
    5
    6
    7
    .hide {
    position: absolute; /*fixed*/
    clip: rect(top, right, bottom, left); /* 占据空间,无法点击 */
    }
    .hide_2 {
    clip-path: polygon(0px 0px, 0px 0px, 0px 0px, 0px 0px);
    }

    隐藏元素的另一种方法是通过剪裁它们来实现。在以前,这可以通过 clip 属性来实现,但是这个属性被废弃了(现在浏览器依然支持),换成一个更好的属性叫做 clip-path。

  • z-index

    1
    2
    3
    4
    .hide {
    position: absolute;
    z-index: -1000; /* 不占据空间,无法点击 */
    }
  • transform

    1
    2
    3
    .hide {
    transform: scale(0, 0); /* 占据空间,无法点击 */
    }
  • opacity

    1
    2
    3
    4
    5
    6
    7
    .hide {
    opacity: 0; /* 占据空间,可以点击 */
    }
    .hide_2 {
    -webkit-filter: opacity(0);
    filter: opacity(0); /* 占据空间,可以点击 */
    }

    opacity 是用来设置元素透明度的,但当设置成 0 的时候也就相当于隐藏元素了。因此,元素依然存在原来的位置,占据空间也可响应事件。如果你打算使用 opacity 属性在读屏软件中隐藏元素,很不幸,你并不能如愿。元素和它所有的内容会被读屏软件阅读,就像网页上的其他元素那样。换句话说,元素的行为就和它们不透明时一致。

  • visibility

    1
    2
    3
    .hide {
    visibility: hidden; /* 占据空间,无法点击 */
    }

    如同 opacity 属性,被隐藏的元素依然会对我们的网页布局起作用。与 opacity 唯一不同的是它不会响应任何用户交互。此外,元素在读屏软件中也会被隐藏


有哪些性能优化的方式方法

  1. 减少资源体积和请求数量

    比如图片用 WebP 压缩,小图标合并成雪碧图或者转成 SVG,第三方库尽量用按需加载(比如只引入 Lodash 用到的函数)。还有像路由懒加载,比如用 Vue Router 时,把不同页面的组件拆开,用户点进页面再下载对应代码,这样首屏能快很多。

  2. 代码层面的优化

    比如用 Vue 的时候,避免在v-for里用复杂计算,必要时用computed缓存结果;高频触发的操作(比如搜索框输入)用防抖节流控制;还有像v-ifv-show分场景用——频繁切换的用v-show,不常用的用v-if

  3. 浏览器缓存

    比如给静态资源(JS、CSS、图片)加Cache-ControlETag,让用户第二次访问直接读本地缓存。

  4. 工具链上打包优化

    比如 Webpack 做代码分割(SplitChunksPlugin),把第三方库单独打包,利用浏览器并行下载

  5. 体验优化

    一个是骨架屏,数据没加载完先展示占位图,用户会觉得没那么‘卡’;另一个是预加载,比如用户鼠标悬停在菜单时,偷偷提前加载下一页的资源

  6. 其他

    图片懒加载;用 CDN 托管静态资源(比如把 Vue、React 这些库换成 CDN 链接);代码压缩混淆、开启 Gzip/Brotli 压缩;


Gzip

Gzip是一种用来压缩文件的技术,简单来说就像给文件‘瘦身’,让它们在网络上传输得更快。比如一个100KB的JavaScript文件,压缩后可能变成30KB,用户下载时省流量还省时间。浏览器收到压缩后的文件会自动解压,整个过程对用户是无感的。

在项目里主要用过两种方式开启Gzip:

  1. 服务器配置(比如Nginx)

    1
    2
    3
    4
    gzip on;  # 开启Gzip
    gzip_types text/html text/css application/javascript; # 指定压缩的文件类型
    gzip_min_length 1k; # 超过1KB的文件才压缩
    gzip_comp_level 5; # 压缩级别,数字越高压得越小(但CPU消耗更多)
  2. 前端构建工具压缩(比如Webpack)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // webpack.config.js
    const CompressionPlugin = require('compression-webpack-plugin');

    module.exports = {
    plugins: [
    new CompressionPlugin({
    algorithm: 'gzip', // 算法
    test: /\.(js|css|html)$/, // 压缩js/css/html
    threshold: 10240 // 超过10KB才压缩
    })
    ]
    }

    这样打包时会生成.gz文件(比如app.js.gz),上传到服务器后,如果服务端支持Gzip,会优先发送这个预压缩好的版本。


代码压缩

目前最流行的代码压缩工具主要有两个:UglifyJsTerser

UglifyJs是一个传统的代码压缩工具,已存在多年,曾经是前端应用的必备工具,但由于它不支持ES6语法,所以目前的流行度已有所下降。

Terser是一个新起的代码压缩工具,支持ES6+语法,因此被很多构建工具内置使用。webpack安装后会内置Terser,当启用生产环境后即可用其进行代码压缩。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
mode: 'production', // 生产模式自动压缩JS
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true, // 启用多线程压缩
terserOptions: {
compress: {
drop_console: true, // 移除所有console.log
},
format: {
comments: false, // 移除注释
}
}
}),
new CssMinimizerPlugin(), // 压缩CSS
],
},
};