(十五)前端性能优化

一、主要包含方面:(加载优化、执行优化、渲染优化、脚本优化)

1、加载优化:

减少HTTP请求、缓存资源、压缩代码、无阻塞、首屏加载、按需加载、预加载、压缩图像、减少Cookie、避免重定向、异步加载第三方资源。

(1)减少http请求、尽量减少页面的请求数。(首次加载同事请求数不超过4个)
  • 合并css和js
  • 使用css雪碧图
(2)缓存资源:使用缓存可减少向服务器的请求数,节省加载时间,所有静态资源都要放在服务器设置缓存,并且尽量使用长缓存(使用时间戳更新缓存)
  • 缓存一切可缓存的资源
  • 使用长缓存
  • 使用外联的样式和脚本
(3)压缩代码:减少资源大小可加快网页显示速度,对代码进行压缩,并在服务器端设置GZip
  • 压缩代码(多余的缩进、空格、换行符)
  • 启用Gzip
(4)无阻塞:头部内联的样式和脚本会阻塞页面的渲染,样式放在又不并使用link方式引入,脚本放在尾部使用异步方式加载。
(5)首屏加载优化:模块懒加载、.异步加载非首屏css(CSS会阻塞DOM的渲染,所以我们将首屏关键CSS内联后,剩余的非首屏CSS内容可以使用外部CSS,并且异步加载,防止非首屏CSS内容阻塞页面的渲染。)
(6)按需加载:将不影响首屏的资源和当前屏幕不用的资源放到用户需要时加载,可大大提升显示速度、降低总体流量(到那时按需加兹安会导致大量重绘、影响渲染性能)
  • 按需加载
  • 滚动加载
  • Media Query加载
(7)预加载:大型资源页面可使用Loading,资源加载完毕后再显示页面,但加载时间过长,会造成用户流失
  • 可感知Loading:进入页面时Loading
  • 不可感知Loading:提前加载下一页
(8)压缩图像:使用图像时选择最合适的格式大小,然后使用工具压缩,同事在代码中使用srcset来按需显示过度压缩图像大小影响图像的显示效果
  • 使用TinyJpg和TinyPng压缩图像
  • 使用css3、SVG、IconFont代替图像
  • 使用img的srcset按需加载图像
  • 选择合适的图像:webp优于jpg,png8优于gif
  • 选择合适的大小:首次加载不大于1014kb、不 宽于640px
    PS切图时D端图像保存质量为80,M端图像保存质量为60。
(9)减少cookie:cookie影响加载速度,静态资源域名不使用cookie
(10)避免重定向:重定向会影响加载速度,在服务器正确设置避免重定向
(11)异步加载第三方资源:第三方资源不可控会影响页面的加载和现实,要异步加载第三方资源

2、执行加载:

(1)css写在头部,js写在尾部并异步
(2)避免img、iframe等src为空,空src会重新加载当前页面,影响速度和效率。
(3)尽量避免重置图像大小,多次重置图像大小会引发图像的多次重绘,影响性能
(4)图像尽量避免使用DataURL,DataURL图像没有使用图像的压缩算法,文件会变大,并且要解码后再渲染,加载慢耗时长。(DataURL 图片被转换成base64编码的字符串形式,并存储在URL中https://blog.csdn.net/liuliuliuliumin123/article/details/107774725)

3、渲染加载:

(1)设置viewport

(viewport 是用户网页的可视区域。常用的针对移动网页优化过的页面的 viewport meta 标签大致如下:<meta name="viewport" content="width=device-width, initial-scale=1.0">

(2)减少DOM节点,DOM节点太多影响页面的渲染,尽量减少DOM节点。
(3)优化动画:
  • 尽量使用css3动画
  • 合理使用requestAnimationFrame动画代替setTimeout.
  • 适当使用canvas动画:5个元素以内使用css动画,5个元素使用canvas动画,iOS8+可使用WebGL动画。
(4)优化高频事件:
  • 函数节流
  • 函数防抖
  • 使用requestAnimationFrame监听帧变化:使得在正确的时间进行渲染
  • 增加响应变化的时间间隔:减少重绘次数
(5)GPU加速:使用某些html5标签和css3属性触发GPU渲染,请合理使用(过渡使用会引发手机耗电量增加)。
  • html标签:video,canvas,webgl
  • css属性,opacity,transform,transition

4、样式优化:

避免在HTML中书写style、避免CSS表达式、移出CSS控规则、正确使用display、不滥用float(1、导致父元素高度塌陷;2、浮动元素不占用原文档流会对后面的元素排版产生影响)

(1)避免在HTML中书写style
(2)避免CSS表达式:CSS表达式的执行需跳出CSS树的渲染
(3)移除CSS空规则:CSS空规则增加了css文件的大小,影响CSS树的执行
(4)正确使用display:display会影响页面的渲染
  • display:inline后不应该再使用float、margin、 padding、width和height
  • display:inline-block后不应该再使用float
  • display:block后不应该再使用vertical-align
  • display:table-*后不应该再使用float和margin
(5)不滥用float:float在渲染时计算量比较大,尽量减少使用
(6)不滥用Web字体:Web字体需要下载、解析、重绘当前页面,尽量减少使用
(7)不声明过多的font-size:过多的font-size影响CSS树的效率
(8)值为0时不需要任何单位:为了浏览器的兼容性和性能,值为0时不要带单位
(9)标准化各种浏览器前缀
  • 无前缀属性应放在最后
  • CSS动画属性只用-webkit-、无前缀两种
  • 其它前缀为-webkit-、-moz-、-ms-、无前缀四种:
  • Opera改用blink内核,-o-已淘汰
  • 避免让选择符看起来像正则表达式:高级选择符执行耗
  • 时长且不易读懂,避免使用

5、脚本优化:

(1)减少重绘和回流
  • 避免不必要的DOM操作
  • 避免使用document.write
  • 减少drawImage
  • 尽量改变class而不是style,使用classList代替className
(2)缓存DOM选择与计算,每次DOM选择都要计算和缓存
(3)缓存.length的值,每次.length计算用一个变量保存值
(4)尽量使用事件代理,避免批量绑定事件
(5)尽量使用id选择器,id选择器选择元素是最快的
(6)touch(触模)事件优化,使用tap(touchstart和touchend)代替click(注意touch响应过快,易引发误操作)。

在前端开发中,此规则作为一种开发指导思路,针对浏览器页面的性能优化。

1、用户在2秒内得到响应,会感觉页面的响应速度很快 Fast
2、用户在2~5秒间得到响应,会感觉页面的响应速度还行 Medium
3、用户在5~8秒间得到响应,会感觉页面的响应速度很慢,但还可以接受 Slow
4、用户在8秒后仍然无法得到响应,会感觉页面的响应速度垃圾死了。

6、使用CDN加速:

使用CDN可以将静态资源分发到多个节点,减少请求延迟,提高页面加载速度。
CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。
CDN 的核心点有两个:一个是缓存,一个是回源
**缓存:**将从根服务器请求来的资源按要求缓存。
**回源:**当有用户访问某个资源的时候,如果被解析到的那个 CDN 节点没有缓存响应的内容,或者是缓存已经到期,就会回源站去获取。没有人访问,CDN 节点不会主动去源站请求资源。
加速::默认会对资源文件进行压缩,减少文件体积,提高了相应的速度 。
CDN & 静态资源
静态资源本身具有访问频率高、承接流量大的特点,因此静态资源加载速度始终是前端性能的一个非常关键的指标。
CDN是静态资源提速的重要手段。

7、响应式布局优化:

使用响应式布局可以使页面适应不同设备屏幕,提高用户体验。

8、HTML优化:

(1)压缩 HTML

HTML代码压缩,将注释、空格和新行从生产文件中删除。删除所有不必要的空格、注释和中断行将减少HTML的大小,加快网站的页面加载时间,并显著减少用户的下载时间。

(2)删除不必要的注释

注释对用户来说是没有用的,应该从生产环境文件中删除。可能需要保留注释的一种情况是:保留远端代码库(keep the origin for a library)。

我们可以使用HTML minify插件删除注释。

remove-html-comments - npm

(3)删除不必要的属性

像 type=“text/javascript” or type=“text/css” 这样的属性应该被移除。类型属性不是必需的,因为HTML5把text/css和text/javascript作为默认值。没用的代码应在网站或应用程序中删除,因为它们会使网页体积增大。

<!-- Before HTML5 -->
<script type="text/javascript">
    // Javascript code
</script>
 
<!-- Today -->
<script>
    // Javascript code
</script>
(4).使用语义化标签

使用语义化标签可以提高代码的可读性和可维护性,并有助于搜索引擎优化。例如,使用 标签来定义页面头部,使用 标签来定义导航等。
在这里插入图片描述
语义化优势:
易于用户阅读,样式丢失的时候能让页面呈现清晰的结构。
有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重。
方便其他设备解析,如盲人阅读器根据语义渲染网页
有利于开发和维护,语义化更具可读性,代码更好维护,与CSS3关系更和谐。

(5)减少iframe数量

尽量少用iframe标签,爬虫是不会读取iframe的内容的。

(6)削减DOM数量和层级数量

HTML 中标签元素越多,标签的层级越深,浏览器解析 DOM 并制作到浏览器中所花的时间就越长,所以应尽或许坚持 DOM 元素简洁和扁平化的层级。

(7)减少 HTTP 请求次数

重排:

当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

哪些操作可以影响重排:

  • 添加/删除元素
  • display:none
  • 移动元素位置
  • 操作styles
  • offsetLeft, scrollTop, clientWidth
  • 修改浏览器大小,字体大小

重绘:
重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。

重排必定会引发重绘,但重绘不一定会引发重排。

9、图片优化:

(1)根据实际需要选择色深,压缩。

减小图片的大小可以减少页面加载时间。可以使用图片压缩工具来压缩图片,以减小文件大小。

(2)小图片引入雪碧图。

雪碧图(CSS Sprite)又叫CSS精灵图主要用于把一堆小图标整合在一张背景透明的大图上,通过设置对应的位置来显示不同的图片,目的是大幅减轻服务器对图片的请求数量,是前端性能优化的一种方式。
优势:
1、减少网页的HTTP请求,提高页面性能
2、减少图片命名的困扰
劣势:
1、需要计算每个图片的位置
2、后期维护困难

(3)图片懒加载。

一般来说,我们访问网站页面时,其实很多图片并不在首屏中,如果我们都加载的话,相当于是加载了用户不一定会看到图片, 这显然是一种浪费。解决的核心思路就是懒加载:实现方式就是先不给图片设置路径,当图片出现在浏览器可视区域时才设置真正的图片路径。

(4)缩小 favicon.ico 并缓存。

有利于 favicon.ico 的重复加载,由于一般一个 Web 运用的 favicon.ico 是很少改动的。

(5)img图片的alt属性要写, 合理使用target=“_blank”
<img src="图片地址" alt="图片keyword"/> alt属性一定要写
(6)采用svg图片或者字体图标

因为字体图标或者SVG是矢量图,代码编写出来的,放大不会失真,而且渲染速度快。字体图标使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便,还有一个优点是生成的文件特别小。

(7)Base64。

将图片的内容以Base64格式内嵌到HTML中,可以减少HTTP请求数量。但是,由于Base64编码用8位字符表示信息中的6个位,所以编码后大小大约比原始值扩大了 33%。

10、webpack构建优化:

(1)线程加载器

多线程可以提高程序的效率,我们也可以在 Webpack 中使用。而thread-loader是一个可以在Webpack中启用多线程的加载器。

安装:

npm i thread-loader -D

webpack.config.js中配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve("src"),
        use: [
          {
            loader: "thread-loader",
            options: {
              workers: 2,
              workerParallelJobs: 50,
              workerNodeArgs: ['--max-old-space-size', '1024'],
              poolTimeout: 2000,
              poolParallelJobs: 50
            }
          },
          "expensive-loader"
        ]
      }
    ]
  }
}

注意:
不一定使用该Loader就一定能提升效率,因为进程之间的通信也会消耗时间,一般在处理文件比较耗时的Loader后面使用该Loader。

(2)缓存加载器

在我们的项目开发过程中,Webpack 需要多次构建项目。为了加快后续构建,我们可以使用缓存,与缓存相关的加载器是缓存加载器。
安装:

npm i cache-loader -D

Webpack 的配置如下 :

 
module.exports = {
    module: {
        // 如果babel-loader耗时比较长,配置cache-loader
        rules: [
            {
                test: /\.jsx?$/,
                use: ['cache-loader','babel-loader']
            }
        ]
    }
}
(3)Hot update

当我们在项目中修改一个文件时,Webpack 默认会重新构建整个项目,但这并不是必须的。我们只需要重新编译这个文件,效率更高,这种策略称为Hot update。Webpack 内置了Hot update插件,我们只需要在配置中开启Hot update即可。
Webpack 的配置如下 :

const webpack = require('webpack');
module.exports = {
    module: {
      plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        hot: true
    }
  }
}
(4)exclude & include

一些文件和文件夹永远不需要参与构建。所以我们可以在配置文件中指定这些文件,防止Webpack取回它们,从而提高编译效率。

exclude : 不需要编译的文件。
include : 需要编译的文件。

//webpack.config.js
const path = require('path');
module.exports = {
    //...
    module: {
        rules: [
            {
                test: /\.js[x]?$/,
                use: ['babel-loader'],
                include: [path.resolve(__dirname, 'src')]
            }
        ]
    },
}
(5)缩小 CSS 代码

css-minimizer-webpack-plugin 可以压缩和去重 CSS 代码。
安装:

npm i css-minimizer-webpack-plugin -D
webpack.config.js中配置:

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
 
module.exports = {
  module: {
    rules: [
      {
        test: /.s?css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
    ],
  },
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
    ],
  },
  plugins: [new MiniCssExtractPlugin()],
};

这将仅在生产环境开启 CSS 优化。

如果还想在开发环境下启用 CSS 优化,请将 optimization.minimize 设置为 true:

module.exports = {
  optimization: {
    // [...]
    minimize: true,
  },
}
(6)缩小 JavaScript 代码

terser-webpack-plugin 可以压缩和去重 JavaScript 代码。
安装:

npm i terser-webpack-plugin -D

webpack.config.js中配置:

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          ecma: undefined,
          parse: {},
          compress: {},
          mangle: true,
          module: false,
          output: null,
          format: null,
          toplevel: false,
          nameCache: null,
          ie8: false,
          keep_classnames: undefined,
          keep_fnames: false,
          safari10: false,
        },
      }),
    ],
  },
};
(7)tree-shaking

作用是把js文件中无用的模块或者代码删掉。而这通常需要借助一些工具。在webpack中tree-shaking就是在打包时移除掉javascript上下文中无用的代码,从而优化打包的结果。在webpack5中已经自带tree-shaking功能,在打包模式为production时,默认开启 tree-shaking功能。

module.exports = {
  mode: 'production'
}
(8)source-map

当我们的代码出现bug时,source-map可以帮助我们快速定位到源代码的位置。但是这个文件很大。因此根据不同的环境来配置。

开发模式:

生成更准确(但更大)的 source-map。

module.exports = {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map'
}

生产方式:

生成更小(但不那么准确)的源映射。

module.exports = {
  mode: 'production',
  devtool: 'nosources-source-map'
}
(9)Bundle Analyzer

可以使用 webpack-bundle-analyzer 来查看打包后的 bundle 文件的体积,然后进行相应的体积优化。

安装:

npm i webpack-bundle-analyzer -D

1.webpack.config.js配置:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports={
  plugins: [
    new BundleAnalyzerPlugin()  // 使用默认配置
    // 默认配置的具体配置项
    // new BundleAnalyzerPlugin({
    //   analyzerMode: 'server',
    //   analyzerHost: '127.0.0.1',
    //   analyzerPort: '8888',
    //   reportFilename: 'report.html',
    //   defaultSizes: 'parsed',
    //   openAnalyzer: true,
    //   generateStatsFile: false,
    //   statsFilename: 'stats.json',
    //   statsOptions: null,
    //   excludeAssets: null,
    //   logLevel: info
    // })
  ]
}

2.配置 package.json 文件

 
{
 "scripts": {
    "dev": "webpack --config webpack.dev.js --progress"
}

3.命令启动

npm run dev

看到项目资源包的交互式可视化树形分析图。

(10)模块懒加载

如果模块没有延迟加载,整个项目的代码会被打包成一个js文件,导致单个js文件体积非常大。那么当用户请求网页时,首屏的加载时间会更长。

使用模块来加载后,大js文件会被分割成多个小js文件,加载时网页按需加载,大大提高了首屏的加载速度。

const routes = [
  { // 未使用懒加载
    path: '/index',
    name: 'index,
    component: index
  },
  {
    path: '/detail',
    name: 'detail',
    // 启用懒加载
    component: () => import('../views/detail/detail.vue'),
  },
]
(11)压缩包

Gzip是一种常用的文件压缩算法,可以提高传输效率。但是,此功能需要后端配合。

安装:

npm i compression-webpack-plugin -D

修改vue.config.js配置:

const CompressionWebpackPlugin = require('compression-webpack-plugin');
const isProdOrTest = process.env.NODE_ENV !== 'development'
module.exports = {
    productionSourceMap: false,// 设为false,既可以减少包大小,也可以加密源码
    transpileDependencies: ['element-ui'],//指定某个库在打包的时候需要编译
    chainWebpack(config) {
        config.plugins.delete('prefetch');//默认开启prefetch(预先加载模块),提前获取用户未来可能会访问的内容 在首屏会把这十几个路由文件,都一口气下载了 所以我们要关闭这个功能模块
        if (isProdOrTest) {
            // 对超过10kb的文件gzip压缩
            config.plugin('compressionPlugin').use(
                new CompressionWebpackPlugin({
                    test: /\.(js|css|html)$/,// 匹配文件名
                    threshold: 10240,
                })
            );
        }
    }
}
(12)base64

对于一些小图片,可以转成base64编码,这样可以减少用户的HTTP请求次数,提升用户体验。url-loader 在 webpack5 中已被弃用,我们可以使用 assets-module 代替。

我也顺便也可以添加一些字体图片的配置、音频配置、Eslint配置、babel配置。

npm i eslint-webpack-plugin eslint -D
npm i babel-loader @babel/core @babel/preset-env -D
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
 
module.exports = {
  entry: "./src/main.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
    clean: true, // 自动将上次打包目录资源清空
  },
  presets: ["@babel/preset-env"],
  module: {
    rules: [
      {
        // 用来匹配 .css 结尾的文件
        test: /\.css$/,
        // use 数组里面 Loader 执行顺序是从右到左
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.less$/,
        use: ["style-loader", "css-loader", "less-loader"],
      },
      {
        test: /\.s[ac]ss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
      {
        test: /\.styl$/,
        use: ["style-loader", "css-loader", "stylus-loader"],
      },
      {
        test: /\.(png|jpe?g|gif|webp)$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
          },
        },
        generator: {
          // 将图片文件输出到 static/imgs 目录中
          // 将图片文件命名 [hash:8][ext][query]
          // [hash:8]: hash值取8位
          // [ext]: 使用之前的文件扩展名
          // [query]: 添加之前的query参数
          filename: "static/imgs/[hash:8][ext][query]",
        },
      },
      {
        test: /\.(ttf|woff2?)$/,
        type: "asset/resource",
        generator: {
          filename: "static/media/[hash:8][ext][query]",
        },
      },
      {
        test: /\.js$/,
        exclude: /node_modules/, // 排除node_modules代码不编译
        loader: "babel-loader",
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "src"),
    }),
  ],
  mode: "development",
};
(13)正确配置哈希

我们可以将哈希添加到捆绑文件中,这样可以更轻松地处理缓存。

output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/chunk-[contenthash].js',
    clean: true,
  },

11、资源加载优化:

(1)使用 Web Workers

Web Worker 是一个独立的线程(独立的执行环境),这就意味着它可以完全和 UI 线程(主线程)并行的执行 js 代码,从而不会阻塞 UI,它和主线程是通过 onmessage 和 postMessage 接口进行通信的。

Web Worker 使得网页中进行多线程编程成为可能。当主线程在处理界面事件时,worker 可以在后台运行,帮你处理大量的数据计算,当计算完成,将计算结果返回给主线程,由主线程更新 DOM 元素。

(2)DNS预解析

浏览器对网站第一次的域名DNS解析查找流程依次为:

浏览器缓存 ->系统缓存 ->路由器缓存 ->ISP DNS缓存 ->递归搜索
DNS预解析的实现:

用meta信息来告知浏览器, 当前页面要做DNS预解析:

在页面header中使用link标签来强制对DNS预解析: dns-prefetch最大的缺点就是使用它太多。过多的预获取会导致过量的DNS解析,对网络是一种负担。
(3)预加载 preload
  • 遇到link标签时,立刻下载并放到内存中,不执行js。
  • 遇到script标签时,将预加载的js执行。
  • 对跨域的文件进行preload时,必须加上 crossorigin 属性
<link rel="preload" crossorigin href="./zone.js" as="script">

基于标记语言的异步加载:

<link rel="preload" as="style" href="asyncstyle.css" onload="this.rel='stylesheet'">

12、代码优化:

(1)去掉页面上用于布局的table,table本身性能较低,且维护性差,是一种过时的布局方案。
(2)在去掉table布局的同时减少一些无意义的DOM元素,减少DOM元素的数量和嵌套。
(3)减少css选择器的嵌套。用sass,less这种css预处理器很容易造成多层嵌套。优化前代码里最多的有七八层嵌套,对性能有一定影响。重构后不超过三层。
(4)拆分函数,将功能复杂的函数拆分成小函数,让每个函数只做一件事。
(5)优化分支结构,用对象Object,代替if…else和switch…case

参考:
1、https://blog.csdn.net/chaoPerson/article/details/130743570
2、https://blog.csdn.net/qq_35789269/article/details/128211573
3、https://answer.baidu.com/answer/land?params=WWwhPqdkbENraL%2BIxL4MJEayjMSglmEkSLdoztpzgenWjMsauEvJpff1pDgK2L7OjhwIp2Xi9XTYj4CehDpFc5Z4tyJHDT%2B6p1rkXE0xX8LJvdeGRyR4%2FXBjWilaDWYR8aAdayXG9pgmh7qv%2FCJkl%2FFsrNFheTYaXt%2BHjWkYbEGDvqvWqGZMhjoWY9GnD6piZlxq7P4dlNsGuCI0QUwKElBxllMNr47rjKDM%2Fl%2BVIHQ%3D&from=dqa&lid=f36f50ef018de627&word=%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E6%9C%89%E5%93%AA%E4%BA%9B%E6%96%B9%E6%B3%95

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值