Vue常用代码与常见问题汇总,不断更新中


前言

总结一些工作中常用的通用的代码,希望可以帮助到大家


一、对象操作

重置

导致界面刷新的操作

  • 界面刷新: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 // 需要被缓存
    }
  }
]

长列表优化

  1. 不常变动数据,不需做响应化

    this.users = Object.freeze(users)

  2. 使用插件 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">


其他优化

  1. 对于简单的组件来说使用 v-show 代替 keep-alivev-if 来复用DOM
  2. 定时器组件手动销毁
  3. UI等三方插件按需引入
  4. 无状态展示型组件标记为函数式组件
  5. 子组件分割
  6. 变量本地化

六,样式修改

  1. /deep/
    使用预处理器,sass less都可以用 /deep/
    要改变element-ui某个深层元素(eg:.el-input__inner)或其他深层样式时,需要使用/deep/
.class /deep/ .el-inpput__inner {
}
  1. ::v-deep::v-deep()
    VUE3.0下/deep/的使用可能会有报错,如果/deep/报错,可采用::v-deep
.class ::v-deep .el-input__inner {
}
  1. >>>
    深度作用选择器 >>>,可用于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;
      }
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值