样式穿透
在vue中定义scoped
后样式产生作用域,但是一些ui组件需要我们局部修改样式,在scoped
内修改经常不生效。除了新增一个没有scoped
的style
标签外,还可以选择穿透scoped
:
老写法
1
.parent >>> .ui-component
有些Sass 之类的预处理器无法正确解析
>>>
。更建议使用/deep/
或::v-deep
:1
2.parent /deep/ .ui-component
.parent ::v-deep .ui-component
注意:穿透不是成为全局样式,新增没有scoped的style标签才会成为全局样式污染全局。因此穿透仅在父子关系时在父组件使用有效,兄弟组件无效
防止同路由报错
1 | const originalPush = VueRouter.prototype.push |
keep-alive
时此组件内部的组件缓存,不被重新渲染
属性,参数都是组件实例暴露的的
name
属性,多个用,
隔开,也可以使用正则exclude
指定name
的组件不会被缓存include
指定name
的组件会被缓存,优先级比exclude
更高max
指定缓存的组件最大数量
生命周期,被缓存的组件不会重复进行创建、挂载和销毁的生命周期,但会多出两个钩子:
activated
组件激活deactivated
组件停用
也可在组件路由的meta元数据中定义是否缓存,然后通过
v-if
判断是否放到keep-alive内实现部分组件缓存:1
2
3
4
5
6//当这种方法嵌套组件时,子组件没有keepAlive会造成误判,可以尝试用
//$route.matched[0].meta.keeyAlive
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
正常组件切换时不会触发更新生命周期,而缓存的组件在第一次进入创建后,显示离开切换时都会触发updated和beforeUpdate
递归组件
vue组件可以在内部直接调用自己,且需要以下条件:
- **需要给组件提供一个name选项(内部调用自己时根据name当作标签名)**或者直接全局注册,防止Vue编译的时候,将内部调用的组件认为是未定义组件
- 必须要有
v-for
或v-if
等终止条件,防止无限递归,造成调用栈溢出
打包
静态路径问题
将最终版打包至dist目录时,里面的静态资源默认是以盘服根路径开始,若项目静态资源未存放至服务器根目录路径会错误。可配置打包后为相对路径:
1 | //vue-cli3中: vue.config.js |
请求路径问题
项目配置了代理跨域,请求路径设置为/api
。而打包时生产环境必须将路径切换至真实的接口路径,不希望手动切换可以判断环境变量process.env.NODE_ENV
1 | const req_path = { |
history模式
刷新页面空白 设置为history模式后,打包的文件只能在放到服务上才能正常显示,并且需要后端配置匹配不到资源重定向到首页,否则刷新会空白(刷新页面history模式会根据路径向服务端get请求)
图片资源路径 history模式时,publicPath不可设置为相对路径(
'./'
或''
),否则图片在当前路由地址处请求静态文件,解决方式后端配置匹配不到资源就去根路径下找,若是vue-cli开启的本地代理服务可以在vue.config.js中配置:
1
2
3
4
5
6
7
8module.exports = {
devServer: {
historyApiFallback: {
//将请求指向index.html文件,打包后还是需要在后端配,方式见vue-router官方文档
index: '/index.html'
},
},
}publicPath使用绝对路径(默认)
若使用绝对路径后项目文件不想放到服务器根目录,需要根据环境设置打包后资源绝对路径:
1 | publicPath: process.env.NODE_ENV === "production" ? '/mystatic/' : "/" |
环境变量文件
文件名 在项目根目录新建这样的文件:*.env* - 什么环境都会生效 .env.development - 开发环境生效
.env-production - 生产环境生效
或者可以自定义环境名称,文件名为*.env.xx* 并在package.json中配置scripts:
1
2
3
4
5//xx对应文件名后根的xx,
//打包
"build:xx": "vue-cli-service build --mode xx"
//本地服务
"dev": "vue-cli-service serve --mode xx"环境变量设置
1
2
3
4#可以设置NODE_ENV(默认run serve为development, run build为production)
NODE_ENV = production
#普通变量必须以`VUE_APP_`开头:
VUE_APP_API = '/api'项目中通过
process.env.xx
使用,对应环境会成为对应文件的变量值默认
npm run serve
开发环境npm run build
生产环境。自定义环境名称时之后
npm run build:xx
也可对应各环境打包。输出文件名默认为dist,也可以通过在环境文件中指定变量来设置:
1
2
3
4
5
6
7
8//vue.config.js中
module.exports = {
outputDir: process.env.outputDir || 'dist',
}
//环境文件中设置打包输出的文件名
outputDir = xxx
//git提交记得在.gitignore设置忽略输出文件
忽略打包三方库 + cdn引入
vue.config.js中:
1 | const isProduction = process.env.VUE_APP_MODE === 'production' |
public/index.html中
1 | <!-- 使用CDN的CSS文件 --> |
原文链接:https://blog.csdn.net/xzwwjl1314/article/details/108233321
工程化使用SVG图标
vue.config.js
中配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const path = require('path')
//获取绝对路径
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack(config) {
//修改默认svg配置,排除icons目录
config.module.rule('svg').exclude.add(svgs)
//新增rule添加icons中的svg
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(svgs)
.end()
.use('svg-sprite-loader') //要安装此loader
.loader('svg-sprite-loader')
.options({ symbolId: 'icon-[name]' }) //之后加载svg图标的xlink:href就是#icon-文件名
},
}svg目录上级定义工程文件index.js:
1
2
3
4//让webpack创建以svg目录为上下文的require函数
const req = require.context('./svg', false, /\.svg$/)
//keys获取所有svg文件全部加载(遍历取到的文件名并将其require)
req.keys().map(req)在main.js导入工程文件:
1
import '@/assets/icons'
直接使用:
1
2
3<svg>
<use :xlink:href="#icon-iconName"></use>
</svg>
SVG 2删除了对
xlink
命名空间的需要,所以不xlink:href
应该使用href
。
虚拟列表
最近使用两款基于vue的虚拟列表组件来优化大数据的渲染问题,但都有各自的优缺点:
vue-virtual-scroll-list
- 该组件需要将使用的每一行组件以属性方式传入,行组件的prop要通过
extra-props
对象方式传入 keeps
约束每次实际渲染的条数,默认30。数据量大时滚动留白时间较久,略卡- 每行高度需要一致,否则容易错乱,通过
estimate-size
预设每行高 - 有ts支持
vue-virtual-scroller
Akryum/vue-virtual-scroller: ⚡️ Blazing fast scrolling for any amount of data (github.com)
每行组件通过插槽传入,更方便
只需设置
min-item-size
设置每行最小高度,会自动计算行高,或者在每一项数据中手动设置size
每次实际渲染量由组件自动计算,不能手动设置。但留白和性能相比vue-virtual-scroll-list更优
没有ts支持和
@/types
下载,只能定义声明文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17declare module 'vue-virtual-scroller' {
import Vue, { ComponentOptions, PluginObject, Component } from 'vue';
interface PluginOptions {
installComponents?: boolean;
componentsPrefix?: string;
}
const plugin: PluginObject<PluginOptions> & { version: string };
export const RecycleScroller: Component<any, any, any, any>;
export const DynamicScroller: Component<any, any, any, any>;
export const DynamicScrollerItem: Component<any, any, any, any>;
export function IdState(options?: { idProp?: (vm: any) => any }): ComponentOptions<Vue> | typeof Vue;
export default plugin;
}每次内容渲染会重新触发行组件内watch,需要注意
每行的dom会被复用,有输入框焦点问题:
滚动后当前焦点的输入框及内容会被使用到后续渲染的行中,导致显示重复。官方暂时没有修复这个问题,处理方法如下
暴力解决方法
滚动需要手动失去焦点
每滚动渲染会触发每行的watch,在这当中重新设置输入框文本
通过该库提供的mixin
IdState
标识每行组件,只能确保data差异,其他如父级传来的props仍会复用,但active
时可以在watch中监听到然后赋值恢复
在使用虚拟列表处理大数据量时,由于产品要求,需要对特定行做
translate
偏移同步外部滚动条。使用props
+:style
,事件监听,Event等动态修改样式时会卡顿,猜测是由于数据过多,参数响应到每行组件有时间差,导致渲染不同步造成。使用css3变量,在虚拟列表外层定义动态的
translate
变量,特定行使用该变量值解决,这样传参就不会有时间差了
- 本文作者: MR-QXJ
- 本文链接: https://mr-qxj.github.io/2021/04/30/框架/vue优化/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!