优化了一下版心宽度修改的逻辑,原来是修改全部带有某个类名的dom的行内样式,现在用一个css变量作为版心宽度,直接修改这个css变量就行了,方便很多(应该还有更好的方法,暂时想不出来了)
博客
-
Vue打包优化
打包优化
1.异步组件,路由按需加载 (解决首屏加载过慢)
component: () => import('@/views/Home/index')
2.排除一些依赖包,将依赖包(不太会变化的包,如Vue、Element UI等)存在cdn上,可以加快打包速度,也可以让不同地域的用户在请求资源时得到更快的响应
webpack排除打包
找到
vue.config.js
,在configureWebpack
配置项中添加externals
选择填入不打包的依赖包configureWebpack: { ... externals: { // key(要排除的包名), value(引入的CDN包的全局变量名) 'vue': 'Vue', 'element-ui': 'ELEMENT', ... }, }
此时这些包已经被排除打包了,因为缺少这些包,项目无法正常运行,接下来还需要配置CDN
vue.config.js
const cdn = { css: [ 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // element-ui css 样式表 ], js: [ // vue must at first! 'https://unpkg.com/vue/dist/vue.js', // vuejs 'https://unpkg.com/element-ui/lib/index.js', // element-ui js ... ] }
开发环境没有必要使用CDN来引入包,可以通过环境变量来判断是否使用CDN
const isProduction = process.env.NODE_ENV === 'production' // 判断是否是生产环境 let externals = {} let cdn = { css: [], js: [] } if (isProduction) { externals = { // key(要排除的包名), value(引入的CDN包的全局变量名) 'vue': 'Vue', 'element-ui': 'ELEMENT', ... } cdn = { css: [ 'https://unpkg.com/element-ui/lib/theme-chalk/index.css' // element-ui css 样式表 ], js: [ // vue must at first! 'https://unpkg.com/vue/dist/vue.js', // vuejs 'https://unpkg.com/element-ui/lib/index.js', // element-ui js ... ] } } ··· // 使用externals module.exports = { configureWebpack: { ... externals: externals, } }
将CDN文件链接注入到模板
chainWebpack(config) { // it can improve the speed of the first screen, it is recommended to turn on preload config.plugin('preload').tap(() => [ { rel: 'preload', // to ignore runtime.js // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171 fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/], include: 'initial' } ]) // 注入cdn变量 (打包时会执行) //https://cli.vuejs.org/zh/guide/webpack.html#修改插件选项 config.plugin('html').tap(args => { args[0].cdn = cdn // 配置cdn给插件 return args }) ... }
找到
public/index.html
<head> <!-- 引入CSS --> <% for(var css of htmlWebpackPlugin.options.cdn.css) { %> <link rel="stylesheet" href="<%=css%>"> <% } %> </head> <!-- 引入JS --> <% for(var js of htmlWebpackPlugin.options.cdn.js) { %> <script src="<%=js%>"></script> <% } %>
打包
yarn build
-
ElementUI配合Vue-I18n实现多语言切换
安装
npm i vue-i18n element-ui
引入
src目录下新建lang/index.js
import Vue from 'vue' import VueI18n from 'vue-i18n' // 引入国际化的插件包 import elementEN from 'element-ui/lib/locale/lang/en' // 引入饿了么的英文包 import elementZH from 'element-ui/lib/locale/lang/zh-CN' // 引入饿了么的中文包 import customZH from './zh' // 引入自定义中文包 import customEN from './en' // 引入自定义英文包 Vue.use(VueI18n) const messages = { en: { message: 'hello', ...enLocale // 或者用 Object.assign({ message: 'hello' }, enLocale) }, zh: { message: '你好', ...zhLocale // 或者用 Object.assign({ message: '你好' }, zhLocale) } } export default new VueI18n({ locale: 'en', // set locale messages, // set locale messages })
main.js
··· // 配置ElementUI的中英切换逻辑 Vue.use(ElementUI, { i18n: (key, value) => i18n.t(key, value) }) new Vue({ el: '#app', ··· i18n, render: h => h(App) })
使用
当我们全局注册i18n的时候,每个组件都会拥有一个
$t
的方法, $t 方法会被挂载到 vue 原型上它会根据传入的key,自动的去寻找当前语言的文本,
$t('title')
<div> {{ $t('title') }} <span>{{ $t('hello') }}</span> </div>
语言切换
this.$i18n.locale = 'en'
-
利用vue-print-nb实现打印功能
安装
Vue2
npm install vue-print-nb --save
Vue3
npm install vue3-print-nb --save
引入
import Print from 'vue-print-nb' Vue.use(Print)
给要打印的盒子指定 id
<div id="print">
使用v-print指令的方式进行打印
<button v-print="{ id: 'printbox' }">打印</button>
注意点
- Callback函数中this指向当前print object对象,that返回Vue对象
- 不需要页眉页脚可以在打印弹窗页面的更多设置里面取消选择
- 不设置popTitle参数页眉标题为undifined
- popTitle参数为空时,页眉标题默认为Document Title
-
Vue使用NProgress
NProgress是页面跳转是出现在浏览器顶部的进度条
官网:http://ricostacruz.com/nprogress/
github:https://github.com/rstacruz/nprogress安装
npm install --save nprogress 或者 yarn add nprogress //用法 NProgress.start(); NProgress.done();
使用
//导入 import NProgress from 'nprogress' import 'nprogress/nprogress.css' router.beforeEach((to, from, next) => { NProgress.start() next() }) router.afterEach(() => { NProgress.done() })
注意
··· next('/login') NProgress.done() ···
被next拦截走的, 不会自动关闭, 因为没有进入到 afterEach, 需要手动关闭
-
Vue虚拟DOM与diff算法
就地复用
Vue会尽可能的就地(同层级,同位置),对比虚拟dom,复用旧dom结构,进行差异化更新。
虚拟DOM
真实DOM
- HTML渲染出来的DOM树
- 每个标签都是树的节点
- 每个节点拥有非常多的属性 由于真实DOM的属性过多,导致对比差异会消耗过多的性能,且有很多无需遍历对比的属性,这样效率很低。
虚拟DOM
本质是JS对象,保存渲染真实DOM时的必要属性。
<template> <div id="app"> <h1 class="title">标题</h1> </div> </template> <script> const virtualDOM = { type:'div', attributes:[{id:'app'}], children:[{ type:'h1', attributes:[{class:"title"}], text:'标题' }] } </script>
渲染过程
- template渲染成虚拟DOM
- 根据虚拟DOM渲染成真实的DOM
数据发生更新
- 重新生成一份新的虚拟DOM
- 对比新的虚拟DOM和旧的虚拟DOM,找到不同的地方
- 最后统一更新真实的DOM
虚拟DOM的作用
可以在内存中创建虚拟DOM,快速比较变化的部分, 然后给真实DOM打补丁(更新)
虚拟DOM总结
虚拟DOM相比真实DOM只保留了渲染时必要的属性,可以更高效地对比DOM新旧差异,进行差异化更新。
diff算法
虚拟DOM内部的比对过程称为diff算法
策略一
先同层级根元素比较,如果根元素变化,那么不考虑复用,整个dom树删除重建
策略二
对比同级兄弟元素时,默认按照下标进行对比复用。如果数组顺序没有发生改变,性能是高效的。
如果数组的顺序发生了变化,性能并不高
策略三
同级兄弟元素,在设置了
key
后,会让相同key
的元素进行对比。key
必须是字符串或者数字,且必须唯一(尽量不用遍历的索引作为
key
,参考策略二中数组的顺序发生变化)总结
- 设置了
key
在DOM更新时会按照相同的key
进行新旧元素比较(不设置则默认为索引) - 目的:提高更新时的性能
key
必须是字符串或者数字,且必须唯一
-
初识Promise
目的:
Promise
是书写异步代码的另一种方式, 解决回调函数嵌套的问题(回调地狱)基本语法
创建
Promise
对象new Promise
的时候会执行传入的函数//Promise对象传入一个函数,函数提供两个函数参数resolve、reject const promise = new Promise((resolve, reject) => { // 内部封装一个异步操作 // 成功则调用resolve // 失败调用reject })
使用
promise.then((res) => { ... }).catch((err) => { ... })
Promise是一个构造函数
Promise.prototype上包含
then()
、catch()
方法通过
then
方法来指定成功的回调函数通过
catch
方法来指定失败的回调函数Promise的三种状态
- pending: 待定(等待结果)
- fulfilled: 成功 (已兑现), 调用了
resolve
, Promise的状态就会被标记成成功 - rejected: 失败 (已拒绝), 调用了
reject
, Promise的状态就会被标记成失败
一旦Promise的状态发生变化,状态就不会再改变了!就像他的名字Promise一样,承诺了就不会改变。
Promise链式调用
解决回调地狱的问题
因为
Promise.prototype.then
和Promise.prototype.catch
方法返回的是 promise,只要是 promise 对象都有这两个方法,所以它们可以被链式调用。import fs from 'then-fs' fs.readFile('1.txt', 'utf-8').then(res => { console.log('读取成功:' + res); return fs.readFile('2.txt', 'utf-8') }).then((res) => { console.log('读取成功:' + res); return fs.readFile('3.txt', 'utf-8') }).then((res) => { console.log('读取成功:' + res); }).catch(err => { console.log('读取失败:' + err); })