前言
总结一些工作中常用的通用的代码,希望可以帮助到大家
一、对象操作
重置
导致界面刷新的操作
-
界面刷新:push,pop ,unshift,shift,reverse,sort,splice
-
界面不刷新:slice,concat ,filter,索引赋值,直接赋值,改变数组长度
使用Object.assign()
该方法用于将所有可枚举属性的值从一个或多个sources源对象复制到目标对象,返回target目标对象
Object.assign(target, ...sources)
重置效果
// 获取当前状态下的data
this.$data
// 获取该组件初始状态下的data
this.$options.data()
// 重置操作
Object.assign(this.$data, this.$options.data())
重置表单
// 表单重置
resetTableOne() {
this.tableOne = {
id: null,
deleteFlag: false,
createTime: null
}
this.resetForm("refName");
},
Vue.prototype.resetForm = function resetForm(refName) {
if (this.$refs[refName]) {
this.$refs[refName].resetFields();
}
}
重置单个
this.form= this.$options.data().form
合并对象
Object.assign({}, obj1, obj2, obj3)
属性
对象属性
-
动态添加属性
Vue.$set([想要添加字段的对象],‘字段名’,字段值)
this.$set(obj,key,value)
,obj为对象,key为属性,value属性值 -
判断对象是否包含某个属性
obj.hasOwnProperty(key),判断obj是否包含key这个属性
事件
原生事件
- 监听根元素的原生事件,使用
.native
修饰符 - 等同于子组件内部处理click事件然后向外发送click事件:
$emit("click".fn)
<el-switch
disabled
class="expire-class"
v-model="scope.row.expireFlag"
active-color="#13ce66"
inactive-color="#ff4949"
@click.native="updateExpire(scope.row)">
</el-switch>
// 修改缴费状态
async updateExpire(row) {
let self = this
this.$confirm('确定修改缴费状态吗?', this.$t('promptMessage'), {
confirmButtonText: this.$t('confirm'),
cancelButtonText: this.$t('close'),
type: 'warning'
})
.then(async() => {
row.expireFlag = !row.expireFlag
self.$http
.request({
url: '/api/customer/coupon/update/expire',
method: 'PUT',
data: {}
})
.then(function (resp) {
// ...
})
})
.catch(() => {
this.$message({type: 'info', message:this.$t('cancelOperation')})
})
},
回调延迟
this.$nextTick
将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中
二、工具类
路由类
页面跳转
Vue.prototype.jump = function(path) {
if (path == "back") {
this.$router.go(-1);
} else {
this.$router.push({ path: path });
}
}
全局
全局加载:loading.js
import { ElLoading } from 'element-ui';
let loadingCount = 0;
let loading;
const startLoading = () => {
loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(0, 0, 0, 0.8)'
});
};
const endLoading = () => {
loading.close();
};
export const showLoading = () => {
if (loadingCount === 0) {
startLoading();
}
loadingCount += 1;
};
export const hideLoading = () => {
if (loadingCount <= 0) {
return;
}
loadingCount -= 1;
if (loadingCount === 0) {
endLoading();
}
};
单例消息框
import { Message } from 'element-ui';
let messageInstance = null;
const resetMessage = (options) => {
if(messageInstance) {
messageInstance.close()
}
messageInstance = Message(options)
};
['error','success','info','warning'].forEach(type => {
resetMessage[type] = options => {
if(typeof options === 'string') {
options = {
message:options
}
}
options.type = type
return resetMessage(options)
}
})
export const message = resetMessage
响应拦截提示
let Message = message
if (error && error.response) {
switch (error.response.status) {
case 400:
Message.error("400:错误请求");
break;
case 401:
Message.error("401:已过期,请重新登录");
break;
case 403:
Message.error("403:拒绝访问");
break;
case 404:
Message.error("404:请求错误,未找到该资源");
break;
case 405:
Message.error("405:请求方法未允许");
break;
case 408:
Message.error("408:请求超时");
break;
case 500:
Message.error("500:服务器端出错");
break;
case 501:
Message.error("501:网络未实现");
break;
case 502:
Message.error("502:网络错误");
break;
case 503:
Message.error("503:服务不可用");
break;
case 504:
Message.error("504:网络超时");
break;
case 505:
Message.error("505:http版本不支持该请求");
break;
default:
Message.error(`连接错误${error.response.status}`);
}
} else {
// 超时处理
if (JSON.stringify(error).includes("timeout"))
Message.error("连接服务器失败");
else
Message.error("服务器响应超时,请刷新当前页");
}
地图坐标
坐标转换:腾讯百度互转
// 腾讯转百度
QQMapToBMap(lng, lat) {
if (lng == null || lng == '' || lat == null || lat == '') {
return { lng, lat }
}
// x_pi = 3.14159265358979324
let x_pi = Math.PI * 3000.0 / 180.0
let x = lng
let y = lat
let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi)
let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi)
let lngs = z * Math.cos(theta) + 0.0065
let lats = z * Math.sin(theta) + 0.006
return {
lng: lngs,
lat: lats
}
},
// 百度转腾讯
BMapToQQMap(lng,lat) {
if (lng == null || lng == '' || lat == null || lat == '') {
return { lng, lat }
}
let x_pi = Math.PI * 3000.0 / 180.0
let x = lng - 0.0065
let y = lat - 0.006
let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi)
let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi)
let lngs = z * Math.cos(theta)
let lats = z * Math.sin(theta)
return {
lng: lngs,
lat: lats
}
},
三、组件部分
父子通信
常用:prop 与 $emit
父向子传值
<child :msg="message"></child>
props: {
msg: {
type: String,
default: () => { return 'child'}
}
}
子向父传值
<child @setval="setVal"></child>
...
setVal(val) {
console.log(val)
}
triggerClick() {
this.$emit('setval', 'child message')
}
兄弟通信
常用:eventBus
要使用到 js 中间文件 export const eventBus = new Vue()
两兄弟都导 import { eventBus } from '../bus.js'
兄弟1 $emit
eventBus.$emit('msg', 'run start')
兄弟2 $on
eventBus.$on('msg', (message) => {
console.log(message)
})
SLOT插槽
默认插槽
子组件:任意地方加入 <slot>
标签,可设置默认内容
<slot>default message</slot>
父级使用:组件标签内有内容则会替代子组件的默认内容
<child>parent message</child>
具名插槽
子组件:可以给对应的插槽起名称
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
父组件:在一个 <template>
元素上使用 v-slot
指令,没 name 的将会有隐含名称 default
<div>main info one</div>
<template v-slot:header>
<h1>title info</h1>
</template>
<p>main info two</p>
<template v-slot:footer>
<p>footer info</p>
</template>
结果
title info
main info one
main info two
footer info
作用域插槽
子组件: 为了让 user 在父级的插槽内容中可用,可作为 元素的 attribute
绑定上去
<slot v-bind:user="user">
{{ user.phone }}
</slot
父组件:将对象命名为 scope,也可用任意名字
代码也可写成 v-slot=“scope” ,但是 缩写语法
和 具名插槽
混用会导致 作用域
不明确
<child>
<template v-slot:default="scope">
{{ scope.user.phone }}
</template>
</child>
四、请求操作
转码encodeURI:encodeURI() 函数可把字符串作为 URI 进行编码
'&columnArr=' + encodeURI(JSON.stringify(columnArr))
特殊符号转义码
符号 | url转义结果 | 转义码 |
---|---|---|
+ | URL 中+号表示空格 | %2B |
空格 | URL中的空格可以用+号或者编码 | %20 |
/ | 分隔目录和子目录 | %2F |
? | 分隔实际的URL和参数 | %3F |
% | 指定特殊字符 | %25 |
# | 表示书签 | %23 |
& | URL 中指定的参数间的分隔符 | %26 |
= | URL 中指定参数的值 | %3D |
五,性能优化
路由懒加载
异步组件实现
routes: [
{
path: '/',
name: 'home',
component: resolve=>(require(["@/views/home.vue"],resolve))
}
]
使用 import 懒加载
const Home = ()=>import("@/views/home.vue")
...
routes: [
{
path: '/',
name: 'home',
component: Home
}
]
指定相同的webpackChunkName,合并打包成一个js文件
const Home= () => import(/* webpackChunkName: "group-home" */ '@/views/home.vue')
keep-alive缓存
作用:当 keep-alive
包裹 动态组件
时,会缓存不活动的组件实例,而不销毁它们。切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗
生命周期:引入keep-alive 的时候,页面第一次进入时触发顺序created -> mounted -> activated,退出时触发deactivated,当再次进入只触发activated
使用$route.meta 中的属性缓存部分页面
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
const Home = resolve => require(['@/views/home.vue'], resolve)
...
routes: [
{
path: '/',
name: 'Login',
component: Login,
meta: {
keepAlive: false // 不需要缓存
}
},
{
path: '/home',
name: 'Home',
component: Home,
meta: {
keepAlive: true // 需要被缓存
}
}
]
长列表优化
-
不常变动数据,不需做响应化
this.users = Object.freeze(users)
-
使用插件
vue-virtual-scroller
图片懒加载
安装:npm install vue-lazyload --save
全局注册
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// 配置项
Vue.use(VueLazyload, {
error: 'dist/error.png',
loading: 'dist/loading.gif'
})
可添加图片Loading样式:img[lazy="loading"]{...}
图片使用:<img v-lazy="img.src">
其他优化
- 对于简单的组件来说使用
v-show
代替keep-alive
和v-if
来复用DOM - 定时器组件手动销毁
- UI等三方插件按需引入
- 无状态展示型组件标记为函数式组件
- 子组件分割
- 变量本地化
六,样式修改
/deep/
使用预处理器,sass less都可以用 /deep/
要改变element-ui某个深层元素(eg:.el-input__inner)或其他深层样式时,需要使用/deep/
.class /deep/ .el-inpput__inner {
}
::v-deep
或::v-deep()
VUE3.0下/deep/的使用可能会有报错,如果/deep/报错,可采用::v-deep
.class ::v-deep .el-input__inner {
}
>>>
深度作用选择器 >>>,可用于css原生样式,可以直接使用 >>>
如果sass/less可能无法识别,这时候需要使用 /deep/和::v-deep 选择器
操作一下
可以外层套个DIV,然后 v-deep
深度修改
<div class="dialog-wrapper">
<el-dialog title="计划详情" :show-close="false" :visible.sync="planDetailVisible" width="60%">
</el-dialog>
</div>
.dialog-wrapper {
::v-deep .el-dialog__wrapper {
.el-dialog {
.el-dialog__body {
background-color: #031527d4;
}
.el-dialog__header {
.el-dialog__title {
color: white;
}
background-color: rgb(68, 99, 138);
}
.el-dialog__footer {
background-color: rgb(68, 99, 138);
}
}
}
}
Form 也是如此
.elform-wrapper {
::v-deep .el-form {
.el-form-item {
.el-form-item__label {
color: white;
font-size: 12px;
}
.el-input__inner {
color: white;
}
.el-input.is-disabled .el-input__inner {
background-color: #46628C8C;
border-color: #384869;
}
}
}
}
Table 透明一波
.table-wrapper {
::v-deep .el-table {
background-color: transparent;
tr {
background-color: transparent;
}
.cell {
background-color: transparent;
}
}
::v-deep .el-table__expanded-cell {
background-color: transparent;
}
::v-deep .el-table--enable-row-transition {
.el-table__body {
td {
background-color: transparent;
}
}
}
}