目录

前端实现文件下载功能

前端实现图片上传功能

element ui 表单验证不通过

this.$nextTick(() => {})的作用

JavaScript 判断对象中是否有某属性的常用方法

JS根据身份证号码算年龄

element ui的表格鼠标定义右键菜单

vue 操作数组的变异方法和非变异方法

vue使用lodash

javascript页面刷新的几种方法

vue watch对象内的属性

通过window.sessionStorage.getItem获取的值,一定要 通过JSON.parse()转成对象

vue项目中,定义并使用 全局变量,全局函数

重构项目可能出现的问题


前端实现文件下载功能

原文文章:前端实现文件下载功能

1.最简单的,有文件的地址,直接使用a标签实现下载:

<a href="/user/test/xxxx.txt" download="文件名.txt">点击下载</a>

但是有个情况,比如txt,png,jpg等这些浏览器支持直接打开的文件是不会执行下载任务的,而是会直接打开文件,这个时候就需要给a标签添加一个属性“download”;

2. window.open()方法,后端提供下载接口:

html:

<button type="button" id="btn1">window.open()方法下载</button>

js:

var $eleBtn1 = $("#btn1");
//已知一个下载文件的后端接口:
https://codeload.github.com/douban/douban-client/legacy.zip/master
//方法一:window.open()
$eleBtn1.click(function(){var url = "https://codeload.github.com/douban/douban-client/legacy.zip/master";window.open(url);
});

3.通过form表单提交的方式:

html:

<button type="button" id="btn2">form方法下载</button>

js:

var $eleBtn2 = $("#btn2");
//已知一个下载文件的后端接口:
https://codeload.github.com/douban/douban-client/legacy.zip/master
$eleBtn2.click(function(){var $eleForm = $("<form method='get'></form>");$eleForm.attr("action","https://codeload.github.com/douban/douban-client/legacy.zip/master");$(document.body).append($eleForm);//提交表单,实现下载$eleForm.submit();
});

还有几个参考文章:

  • vue实现点击下载图片到本地
  • vue+axios实现文件下载
  • vuejs怎么根据url下载文件
  • window.open
  • JS兼容IE怎么实现下载图片在本地

我在项目中使用的是第一种方法,顺便把代码贴出来(表格的点击事件):

 handleDownload (index,row) {   // row为当前行的数据let cV = row.cV;let applyUrl = this.$sourcePrefix + cV; //this.$sourcePrefix为资源前缀if(cV!='' && cV !=undefined) {let url = applyUrl;let link = document.createElement('a');link.style.display = 'none';link.href = url;link.setAttribute('download', cV);link.setAttribute('target', "_blank");document.body.appendChild(link);link.click();} else {}
}

前端实现图片上传功能

直接上代码:最好是把组件的props、data、computed、watch、mounted、methods来看参数、函数的作用,这样更容易明白

  • 头像上传:
<template><div class="upload-avatar-component"><divclass="preview"style="height:100%"><div><img :src="fileSrc" alt="UploadImg"></div></div><div class="button-upload"><el-uploadclass="upload-img":action="theUrl":before-upload="BeforeUpload"ref="upload":show-file-list="false">编辑</el-upload></div></div>
</template><script>
import * as connector from '@api/interfaceList'
import { post } from '@api/api.request'
export default {name: "uploadImg",model: {prop: "uploadedFile",event: "updateFile"},data() {return {imgFile: null,fileSrc: "",errorNotify: {ImgFormatError: null,ImgExceededSize: null,ImgDimensionError: null,ImgDimensionRangeError: null},iconPrefix: ""};},props: {/*validateEvent: {type: Boolean,default: true},*//*  showPreview:{type:Boolean,default:true}, */uploadedFile: {},disabled: {type: Boolean,default: false},defaultImg: {//自定义默认未上传时显示图片default: require("@images/home/default_avatar.png")},itemName: {//上传图片对应表单项名称type: String,required: true},/*itemProp:{//接收父组件传来的表单prop值,用于在父组件中应用该组件多次时,进行各子实例的区分},*/imgDisplayWidth: {//图片上传后的预览宽度type: Number,default: 74},/*defaultImgUrl:{type:String,required: true},*/imgDisplayHeight: {//图片上传后的预览高度type: Number,default: 75},itemMessage: {//表单项文字信息type: Object,default: function() {return {};}/*default:function () {return {instruction:'请提交有效期内的教师资格证照片,需确保头像和文字清晰',//String/html标记语言(换行用<br/>) ;showLimitRules为false时,不受影响,显示extraDescribe:['亦可提交高等学历证,专业证书等其他资格证明']//Array 上传要求的额外描述,【showLimitRules为false时不显示】}}*/},itemRule: {/*限制条件*/type: Object,/*required: true,*/validator: function(value) {// 宽度范围与高度范围中的最大最小的数值需符合逻辑if (value.widthRange &&value.widthRange.minWidth &&value.widthRange.maxWidth) {return value.widthRange.minWidth < value.widthRange.maxWidth;} else if (value.heightRange &&value.heightRange.minHeight &&value.heightRange.maxHeight) {return value.heightRange.minHeight < value.heightRange.maxHeight;} else {return true;}},default: function() {return {format: ["jpg", "jpeg", "png"], //Array 文件格式maxSize: 1024, //Number[kb] 文件大小width: undefined, //Number[px] 图片宽度height: undefined, //Number[px] 图片高度widthRange: {minWidth: undefined, //Number[px] 图片最小宽度maxWidth: undefined //Number[px] 图片最大宽度},heightRange: {minHeight: undefined, //Number[px] 图片最小高度maxHeight: undefined //Number[px] 图片最大高度}};}},showLimitRules: {//是否展示根据限制条件自动生成的规则提示语qualificationtype: Boolean,default: true},uploadUrl: {type: String}},watch: {/* 监听上传之后返回的值 */uploadedFile: function(newVal) {if (!newVal) {this.fileSrc = this.defaultImg;this.dispatch("ElFormItem", "el.form.change", [""]);return false;}if (newVal.indexOf(this.iconPrefix) > 0) {this.fileSrc = newVal;} else {this.fileSrc = this.iconPrefix + "/" + newVal;}},// 监听iconPrefix变化iconPrefix_C (val) {if(val) {/* 判断上传之后返回的值是否带有前缀 */let urlPattern = /[a-zA-z]+:\/\/[^\s]*/;let uploadedFile = String(this.uploadedFile || "");if (!uploadedFile) {this.fileSrc = this.defaultImg;} else if (urlPattern.test(uploadedFile)) {this.fileSrc = this.uploadedFile;} else {this.fileSrc = this.iconPrefix +"/" + this.uploadedFile;}} else {this.getsourcePrefix();}}},mounted: function() {/*this.$notify.config({top: 130,duration: 0});*//* 获取资源前缀 */this.getsourcePrefix();},computed: {/*validateState() {return this.elFormItem ? this.elFormItem.validateState : '';},*/iconPrefix_C () {return this.iconPrefix;},/* 设置上传图片的地址 */theUrl: function() {if (!this.uploadUrl || this.uploadUrl === "") {return this.$uploadUrl; //todo:默认的上传地址(注册于Vue.prototype)} else {return this.uploadUrl;}},/* 规则提示语的 */qualification: function() {let qualification = [];if (this.itemRule) {if (this.itemRule.maxSize) {let maxSize =this.itemRule.maxSize < 1024? this.itemRule.maxSize + "Kb": this.itemRule.maxSize / 1024 + "Mb";let sizeLimit = "图片大小不超过" + maxSize;qualification.push(sizeLimit);}if (this.itemRule.format) {let formatLimit = "支持";for (let i = 0; i < this.itemRule.format.length; i++) {if (i !== this.itemRule.format.length - 1) {formatLimit = formatLimit + this.itemRule.format[i] + "/";} else {formatLimit = formatLimit + this.itemRule.format[i];}}formatLimit = formatLimit + "格式的图片";qualification.push(formatLimit);}if (this.itemRule.width || this.itemRule.height) {let widthLimit = this.itemRule.width? this.itemRule.width + "px(像素)": "不限";let heightLimit = this.itemRule.height? this.itemRule.height + "px(像素)": "不限";let dimensionLimit ="图片尺寸为" + "宽:" + widthLimit + ";高:" + heightLimit;qualification.push(dimensionLimit);}/*if(!this.itemRule.width && !this.itemRule.height){//只有穿参中没有宽或高固定限制,才进行宽度或高度范围的条件校验//此处为自动生成的宽度、高度范围校验的描述文字【现在不想写】}*/}if (this.itemMessage.extraDescribe) {qualification = qualification.concat(this.itemMessage.extraDescribe);}return qualification;}/*    // 设置请求头headers() {return {// 设置Content-Type类型为multipart/form-data'ContentType': 'multipart/form-data'}} */},methods: {/* 获取配置的地址 */getsourcePrefix() {this.$http.hosCommon.fetchConfig().then(data => {this.iconPrefix = "http://" + data.qiniu;});},/* 警告 */notifyWarning(title, message, duration) {let that = this;setTimeout(() => {that.$notify.warning({/*this.errorNotify['ImgFormatError'] = */title: title,message: message,duration: duration});}, 20); //elementUI组件bug(that.$notify的触发时间接近的提示窗叠在一起bug),需要添加20ms的延时触发(0,1的延时触发均不能解决)},/* 上传之前的验证操作 */BeforeUpload(file) {/*this.closeError();*/if (!this.itemRule) {this.customUpload(file);return false;}let validateResult = this.validate(file);/*alert(validateResult);*//* 在客户端读取文件 */let reader = new FileReader();let that = this;//这是一个回调函数,需要设置reader.readAsDataURL(file),并在该函数执行结束后才会触发这个回调reader.onload = function(e) {let data = e.target.result;/*that.fileSrc = data;//本地加载展示图片*///加载图片获取图片真实宽度和高度用于校验let image = new Image();/* 这是个回调,在图像加载完毕后调用 */image.onload = function() {/*宽高范围校验*/if (!that.itemRule.width && !that.itemRule.height) {let widthRangeInconform = false;let heightRangeInconform = false;if (that.itemRule.widthRange) {widthRangeInconform = that.itemRule.widthRange.maxWidth? image.width > that.itemRule.widthRange.maxWidth: false;if (!widthRangeInconform) {widthRangeInconform = that.itemRule.widthRange.minWidth? image.width < that.itemRule.widthRange.minWidth: false;}} else if (that.itemRule.heightRange) {heightRangeInconform = that.itemRule.heightRange.maxHeight? image.height > that.itemRule.heightRange.maxHeight: false;if (!heightRangeInconform) {heightRangeInconform = that.itemRule.heightRange.minHeight? image.height < that.itemRule.heightRange.minHeight: false;}} else {}if (widthRangeInconform || heightRangeInconform) {that.notifyWarning(that.itemName + "图片长宽尺寸不符合要求!","请重新上传符合宽、高规定的图片",5000);file = null;that.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;} else if (validateResult) {//所有校验均通过that.imgFile = file;that.customUpload(file);/*console.log('进入了手动上传')*/} else {//宽高校验通过,但格式或大小校验不通过file = null;this.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;}} else {/*固定宽/高校验(校验通过为false)*/let widthInconform = that.itemRule.width? image.width !== that.itemRule.width: false;let heightInconform = that.itemRule.height? image.height !== that.itemRule.height: false;if (widthInconform || heightInconform) {//宽高校验未通过let widthLimit = that.itemRule.width? that.itemRule.width + "px": "不限";let heightLimit = that.itemRule.height? that.itemRule.height + "px": "不限";that.notifyWarning(that.itemName + "图片长宽尺寸不符合要求!","请重新上传:宽度为 " +widthLimit +"*" +heightLimit +"的图片",5000);file = null;that.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;} else if (validateResult) {//所有校验均通过that.imgFile = file;/*that.$refs['upload'].post(file);//采用手动上传*/that.customUpload(file);console.log("进入了手动上传");} else {//宽高校验通过,但格式或大小校验不通过file = null;this.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;}}};image.src = data;};// 以DataURL的形式读取文件:reader.readAsDataURL(file);return false; //采用手动上传},/*   校验格式与文件大小 */validate(file) {let result = true; //校验通过旗标if (this.itemRule) {if (this.itemRule.format.length) {const _file_format = file.name.split(".").pop().toLocaleLowerCase();const checked = this.itemRule.format.some(item => item.toLocaleLowerCase() === _file_format);if (!checked) {this.handleFormatError();result = false;}}// check maxSizeif (this.itemRule.maxSize) {if (file.size > this.itemRule.maxSize * 1024) {this.handleExceedSize();result = false;}}}return result;},/* 上传格式报错的函数处理 */handleFormatError() {this.notifyWarning(this.itemName + "图片格式错误!","请重新上传" + this.itemRule.format + "格式的图片",5000);},/* 上传图片大小报错的函数处理 */handleExceedSize() {let maxSize =this.itemRule.maxSize < 1024? this.itemRule.maxSize + "Kb": this.itemRule.maxSize / 1024 + "Mb";this.notifyWarning(this.itemName + "图片体积过大!","请重新上传不超过" + maxSize + "的图片",5000);},/* 手动上传的函数处理 */customUpload(file) {this.progressObj = {status: "text",progressPercentage: 0};let that = this;let onUploadProgress = function(progressEvent) {let progress = Number(((progressEvent.loaded / progressEvent.total) * 100).toFixed(2));that.progressObj.progressPercentage =progress >= 99.99 ? 99.99 : progress;};let reqConfig = {headers: {fileType: "file","Content-Type": "multipart/form-data"},onUploadProgress: onUploadProgress};let rawFile = new FormData();rawFile.append("a", file);this.$http.hosCommon.putFile(this.theUrl, rawFile, reqConfig.headers).then(data => {this.noticeParent(data[0]);this.fileSrc = "http://w.y7edu.com/" + data[0];/*  console.log(this.fileSrc); */setTimeout(() => {that.progressObj = {status: "success",progressPercentage: 100};}, 150);}).catch(error => {that.progressObj.status = "exception";});},/* 同步父、子组件上传文件状态【null/Object[file]】 */noticeParent(msg) {/*let notice = {itemProp:this.itemProp,uploadedImg:msg};*/this.$emit("updateFile", msg);// this.dispatch("ElFormItem", "el.form.change", [msg]);},/* 使用了elFormItem组件作为父组件,该图片上传组件的v-model绑定的数据更新时,通知elFormItem组件 */dispatch(componentName, eventName, params) {let parent = this.$parent || this.$root;let name = parent.$options.componentName;while (parent && (!name || name !== componentName)) {parent = parent.$parent;if (parent) {name = parent.$options.componentName;}}if (parent) {parent.$emit.apply(parent, [eventName].concat(params));}}}
};
</script>
<style lang="less">
.upload-avatar-component {height: 110px;position: relative;display: inline-block;.el-upload {width: 100%;}.button-upload {position: absolute;top: 0;left: 0;height: 110px;line-height: 110px;width: 100%;.upload-img {display: none;border-radius: 50%;overflow: hidden;.el-upload--text { height: 40px;line-height: 40px;border-radius: 5px;text-align: center;font-size: 18px;color:  #00b8c4;background-size: 100% 100%;background-position: center;&:hover{opacity: 0.85;}}}&:hover {.upload-img {display: block;overflow: hidden;background-color: #333;opacity: 0.85;border-radius: 50%;}}}
}
.preview {height: 110px;width: 100%;line-height: 110px;text-align: center;img {height: 110px;width: 110px;border-radius: 50%}
}
</style>

使用:

<avatar:showPreview="false":imgDisplayWidth="uploadConfig.previewWidth":imgDisplayHeight="uploadConfig.previewHeight":itemRule="uploadConfig.imgRequirement"v-model="userInfo.avatarUrl":itemName="uploadConfig.label"@updateFile="updateFile"
></avatar>

配置(data中定义):

uploadConfig: {previewWidth: 110,previewHeight: 110,label: "",itemMessage: {instruction: "请提交你的头像", //String/html标记语言(换行用<br/>) 表单上传提示语/提示语+上传文件规则extraDescribe: []},imgRequirement: {format: ["jpg", "jpeg", "png"]/*  width:1920,//Number[px] 图片宽度height:768,//Number[px] 图片高度maxSize:4096,//Number[kb] 文件大小 */}}

方法:

// 上传头像的事件updateFile (msg) {window.sessionStorage.setItem("avatar", msg);let params = {'icon': msg};this.$http.hosCommon.editUserInfo(params).then(data => {this.$message({message: '编辑用户头像成功',type: 'success'});this.$store.commit("SET_AVATAR", msg);})}

注意:this.$http.hosCommon.editUserInfo是我封装的方法

  • 图片上传:
<template><div class="upload-img-component"><!-- <divclass="preview":style="{width:imgDisplayWidth+'px',height:imgDisplayHeight + 'px'}"style="height:100%"><div><img :src="fileSrc" alt="UploadImg"></div></div> --><div class="button-upload"><el-uploadclass="upload-img"v-if="fileSrc === defaultImg":action="theUrl":before-upload="BeforeUpload"ref="upload":show-file-list="false">点击上传</el-upload><el-uploadclass="uploaded-img"v-if="fileSrc != defaultImg":action="theUrl":before-upload="BeforeUpload"ref="upload":show-file-list="false">重新上传</el-upload></div></div>
</template><script>
import * as connector from '@api/interfaceList'
import { post } from '@api/api.request'
export default {name: "uploadImg",model: {prop: "uploadedFile",event: "updateFile"},data() {return {imgFile: null,fileSrc: "",errorNotify: {ImgFormatError: null,ImgExceededSize: null,ImgDimensionError: null,ImgDimensionRangeError: null},iconPrefix: ""};},props: {/*validateEvent: {type: Boolean,default: true},*//*  showPreview:{type:Boolean,default:true}, */uploadedFile: {},disabled: {type: Boolean,default: false},defaultImg: {//自定义默认未上传时显示图片default: require("@images/login/bg_zyzs.png")},itemName: {//上传图片对应表单项名称type: String,required: true},/*itemProp:{//接收父组件传来的表单prop值,用于在父组件中应用该组件多次时,进行各子实例的区分},*/imgDisplayWidth: {//图片上传后的预览宽度type: Number,default: 74},/*defaultImgUrl:{type:String,required: true},*/imgDisplayHeight: {//图片上传后的预览高度type: Number,default: 75},itemMessage: {//表单项文字信息type: Object,default: function() {return {};}/*default:function () {return {instruction:'请提交有效期内的教师资格证照片,需确保头像和文字清晰',//String/html标记语言(换行用<br/>) ;showLimitRules为false时,不受影响,显示extraDescribe:['亦可提交高等学历证,专业证书等其他资格证明']//Array 上传要求的额外描述,【showLimitRules为false时不显示】}}*/},itemRule: {/*限制条件*/type: Object,/*required: true,*/validator: function(value) {// 宽度范围与高度范围中的最大最小的数值需符合逻辑if (value.widthRange &&value.widthRange.minWidth &&value.widthRange.maxWidth) {return value.widthRange.minWidth < value.widthRange.maxWidth;} else if (value.heightRange &&value.heightRange.minHeight &&value.heightRange.maxHeight) {return value.heightRange.minHeight < value.heightRange.maxHeight;} else {return true;}},default: function() {return {format: ["jpg", "jpeg", "png"], //Array 文件格式maxSize: 1024, //Number[kb] 文件大小width: undefined, //Number[px] 图片宽度height: undefined, //Number[px] 图片高度widthRange: {minWidth: undefined, //Number[px] 图片最小宽度maxWidth: undefined //Number[px] 图片最大宽度},heightRange: {minHeight: undefined, //Number[px] 图片最小高度maxHeight: undefined //Number[px] 图片最大高度}};}},showLimitRules: {//是否展示根据限制条件自动生成的规则提示语qualificationtype: Boolean,default: true},uploadUrl: {type: String}},watch: {/* 监听上传之后返回的值 */uploadedFile: function(newVal) {console.log(newVal)if (!newVal) {this.fileSrc = this.defaultImg;this.dispatch("ElFormItem", "el.form.change", [""]);return false;}if (newVal.indexOf(this.iconPrefix) > 0) {this.fileSrc = newVal;} else {this.fileSrc = this.iconPrefix + "/" + newVal;}}},mounted: function() {/*this.$notify.config({top: 130,duration: 0});*//* 获取资源前缀 */this.getsourcePrefix();/* 判断上传之后返回的值是否带有前缀 */let urlPattern = /[a-zA-z]+:\/\/[^\s]*/;let uploadedFile = String(this.uploadedFile || "");if (!uploadedFile) {this.fileSrc = this.defaultImg;} else if (urlPattern.test(uploadedFile)) {this.fileSrc = this.uploadedFile;} else {this.fileSrc = this.iconPrefix + this.uploadedFile;}},computed: {/*validateState() {return this.elFormItem ? this.elFormItem.validateState : '';},*//* 设置上传图片的地址 */theUrl: function() {if (!this.uploadUrl || this.uploadUrl === "") {return this.$uploadUrl; //todo:默认的上传地址(注册于Vue.prototype)} else {return this.uploadUrl;}},/* 规则提示语的 */qualification: function() {let qualification = [];if (this.itemRule) {if (this.itemRule.maxSize) {let maxSize =this.itemRule.maxSize < 1024? this.itemRule.maxSize + "Kb": this.itemRule.maxSize / 1024 + "Mb";let sizeLimit = "图片大小不超过" + maxSize;qualification.push(sizeLimit);}if (this.itemRule.format) {let formatLimit = "支持";for (let i = 0; i < this.itemRule.format.length; i++) {if (i !== this.itemRule.format.length - 1) {formatLimit = formatLimit + this.itemRule.format[i] + "/";} else {formatLimit = formatLimit + this.itemRule.format[i];}}formatLimit = formatLimit + "格式的图片";qualification.push(formatLimit);}if (this.itemRule.width || this.itemRule.height) {let widthLimit = this.itemRule.width? this.itemRule.width + "px(像素)": "不限";let heightLimit = this.itemRule.height? this.itemRule.height + "px(像素)": "不限";let dimensionLimit ="图片尺寸为" + "宽:" + widthLimit + ";高:" + heightLimit;qualification.push(dimensionLimit);}/*if(!this.itemRule.width && !this.itemRule.height){//只有穿参中没有宽或高固定限制,才进行宽度或高度范围的条件校验//此处为自动生成的宽度、高度范围校验的描述文字【现在不想写】}*/}if (this.itemMessage.extraDescribe) {qualification = qualification.concat(this.itemMessage.extraDescribe);}return qualification;}/*    // 设置请求头headers() {return {// 设置Content-Type类型为multipart/form-data'ContentType': 'multipart/form-data'}} */},methods: {/* 获取配置的地址 */getsourcePrefix() {this.$http.hosCommon.fetchConfig().then(data => {this.iconPrefix = "http://" + data.qiniu;});},/* 警告 */notifyWarning(title, message, duration) {let that = this;setTimeout(() => {that.$notify.warning({/*this.errorNotify['ImgFormatError'] = */title: title,message: message,duration: duration});}, 20); //elementUI组件bug(that.$notify的触发时间接近的提示窗叠在一起bug),需要添加20ms的延时触发(0,1的延时触发均不能解决)},/* 上传之前的验证操作 */BeforeUpload(file) {/*this.closeError();*/if (!this.itemRule) {this.customUpload(file);return false;}let validateResult = this.validate(file);/*alert(validateResult);*//* 在客户端读取文件 */let reader = new FileReader();let that = this;//这是一个回调函数,需要设置reader.readAsDataURL(file),并在该函数执行结束后才会触发这个回调reader.onload = function(e) {let data = e.target.result;/*that.fileSrc = data;//本地加载展示图片*///加载图片获取图片真实宽度和高度用于校验let image = new Image();/* 这是个回调,在图像加载完毕后调用 */image.onload = function() {/*宽高范围校验*/if (!that.itemRule.width && !that.itemRule.height) {let widthRangeInconform = false;let heightRangeInconform = false;if (that.itemRule.widthRange) {widthRangeInconform = that.itemRule.widthRange.maxWidth? image.width > that.itemRule.widthRange.maxWidth: false;if (!widthRangeInconform) {widthRangeInconform = that.itemRule.widthRange.minWidth? image.width < that.itemRule.widthRange.minWidth: false;}} else if (that.itemRule.heightRange) {heightRangeInconform = that.itemRule.heightRange.maxHeight? image.height > that.itemRule.heightRange.maxHeight: false;if (!heightRangeInconform) {heightRangeInconform = that.itemRule.heightRange.minHeight? image.height < that.itemRule.heightRange.minHeight: false;}} else {}if (widthRangeInconform || heightRangeInconform) {that.notifyWarning(that.itemName + "图片长宽尺寸不符合要求!","请重新上传符合宽、高规定的图片",5000);file = null;that.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;} else if (validateResult) {//所有校验均通过that.imgFile = file;that.customUpload(file);/*console.log('进入了手动上传')*/} else {//宽高校验通过,但格式或大小校验不通过file = null;this.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;}} else {/*固定宽/高校验(校验通过为false)*/let widthInconform = that.itemRule.width? image.width !== that.itemRule.width: false;let heightInconform = that.itemRule.height? image.height !== that.itemRule.height: false;if (widthInconform || heightInconform) {//宽高校验未通过let widthLimit = that.itemRule.width? that.itemRule.width + "px": "不限";let heightLimit = that.itemRule.height? that.itemRule.height + "px": "不限";that.notifyWarning(that.itemName + "图片长宽尺寸不符合要求!","请重新上传:宽度为 " +widthLimit +"*" +heightLimit +"的图片",5000);file = null;that.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;} else if (validateResult) {//所有校验均通过that.imgFile = file;/*that.$refs['upload'].post(file);//采用手动上传*/that.customUpload(file);console.log("进入了手动上传");} else {//宽高校验通过,但格式或大小校验不通过file = null;this.imgFile = null;that.noticeParent(undefined);//清除展示that.fileSrc = that.defaultImg;}}};image.src = data;};// 以DataURL的形式读取文件:reader.readAsDataURL(file);return false; //采用手动上传},/*   校验格式与文件大小 */validate(file) {let result = true; //校验通过旗标if (this.itemRule) {if (this.itemRule.format.length) {const _file_format = file.name.split(".").pop().toLocaleLowerCase();const checked = this.itemRule.format.some(item => item.toLocaleLowerCase() === _file_format);if (!checked) {this.handleFormatError();result = false;}}// check maxSizeif (this.itemRule.maxSize) {if (file.size > this.itemRule.maxSize * 1024) {this.handleExceedSize();result = false;}}}return result;},/* 上传格式报错的函数处理 */handleFormatError() {this.notifyWarning(this.itemName + "图片格式错误!","请重新上传" + this.itemRule.format + "格式的图片",5000);},/* 上传图片大小报错的函数处理 */handleExceedSize() {let maxSize =this.itemRule.maxSize < 1024? this.itemRule.maxSize + "Kb": this.itemRule.maxSize / 1024 + "Mb";this.notifyWarning(this.itemName + "图片体积过大!","请重新上传不超过" + maxSize + "的图片",5000);},/* 手动上传的函数处理 */customUpload(file) {this.progressObj = {status: "text",progressPercentage: 0};let that = this;let onUploadProgress = function(progressEvent) {let progress = Number(((progressEvent.loaded / progressEvent.total) * 100).toFixed(2));that.progressObj.progressPercentage =progress >= 99.99 ? 99.99 : progress;};let reqConfig = {headers: {fileType: "file","Content-Type": "multipart/form-data"},onUploadProgress: onUploadProgress};let rawFile = new FormData();rawFile.append("a", file);this.$http.hosCommon.putFile(this.theUrl, rawFile, reqConfig.headers).then(data => {this.noticeParent(data[0]);this.fileSrc = "http://w.y7edu.com/" + data[0];/*  console.log(this.fileSrc); */setTimeout(() => {that.progressObj = {status: "success",progressPercentage: 100};}, 150);}).catch(error => {that.progressObj.status = "exception";});},/* 同步父、子组件上传文件状态【null/Object[file]】 */noticeParent(msg) {/*let notice = {itemProp:this.itemProp,uploadedImg:msg};*/this.$emit("updateFile", msg);this.dispatch("ElFormItem", "el.form.change", [msg]);},/* 使用了elFormItem组件作为父组件,该图片上传组件的v-model绑定的数据更新时,通知elFormItem组件 */dispatch(componentName, eventName, params) {let parent = this.$parent || this.$root;let name = parent.$options.componentName;while (parent && (!name || name !== componentName)) {parent = parent.$parent;if (parent) {name = parent.$options.componentName;}}if (parent) {parent.$emit.apply(parent, [eventName].concat(params));}}}
};
</script>
<style lang="less">
.upload-img-component {height: 40px;position: relative;display: inline-block;.el-upload {width: 100%;}.button-upload {position: absolute;height: 40px;padding: 0 20px;min-width: 160px;top: 0;left: 0;.upload-img {.el-upload--text { height: 40px;line-height: 40px;border-radius: 5px;text-align: center;font-size: 18px;color:  #FFF;background-color: #00b8c4;background-size: 100% 100%;background-position: center;&:hover{opacity: 0.85;}}}.uploaded-img {height: 40px;line-height: 40px;border-radius: 5px;text-align: center;font-size: 18px;color: rgba(255, 255, 255, 1);background-color: #909399;background-size: 100% 100%;background-position: center;&:hover{opacity: 0.85;}}}// .preview {//   & > div {//     width: 100%;//     height: 100%;//     border-radius: 6px;//   }//   img {//     height: 100%;//     width: 100%;//     background: #dddddd;//     border-radius: 6px;//   }// }
}
</style>

使用:

<upload-img:showPreview="false":imgDisplayWidth="uploadConfig.previewWidth":imgDisplayHeight="uploadConfig.previewHeight":itemRule="uploadConfig.imgRequirement"v-model="imgUrl":itemName="uploadConfig.label"
></upload-img>

这里的图片上传就不做赘述了,请看上面的头像上传的详细说明

参考文章:

  • Element :upload组件实例
  • input和formdata文件上传,formdata在append上传的文件file之后,formdata还是空的?
  • HTML5的 input:file上传类型控制

element ui 表单验证不通过

参考问题:element ui 表单验证 this.$refs[formName].validate()里面的内容死活不执行

this.$nextTick(() => {})的作用

参考问题:vue中mounted函数中添加setTimeout有什么作用

JavaScript 判断对象中是否有某属性的常用方法

原文文章:JavaScript 判断对象中是否有某属性的常用方法

  • 第一种:点( . )或者方括号( [ ] )

通过点或者方括号可以获取对象的属性值,如果对象上不存在该属性,则会返回undefined。当然,这里的“不存在”指的是对象自身和原型链上都不存在,如果原型链有该属性,则会返回原型链上的属性值。

// 创建对象
let test = {name : 'lei'}
// 获取对象的自身的属性
test.name   //"lei"
test["name"]   //"lei"// 获取不存在的属性
test.age    //undefined// 获取原型上的属性
test["toString"]  //toString() { [native code] }// 新增一个值为undefined的属性
test.un = undefinedtest.un    //undefined 不能用在属性值存在,但可能为 undefined的场景

所以,我们可以根据 Obj.x !== undefined 的返回值 来判断Obj是否有x属性。

这种方式很简单方便,局限性就是:不能用在x的属性值存在,但可能为 undefined的场景。 in运算符可以解决这个问题

  • 第二种:in 运算符

MDN 上对in运算符的介绍:如果指定的属性在指定的对象或其原型链中,则in 运算符返回true。

'name' in test  //true
'un' in test    //true
'toString' in test //true
'age' in test   //false

示例中可以看出,值为undefined的属性也可正常判断。

这种方式的局限性就是无法区分自身和原型链上的属性,在只需要判断自身属性是否存在时,这种方式就不适用了。这时需要hasOwnProperty()

  • 第三种:hasOwnProperty()
test.hasOwnProperty('name')  //true 自身属性
test.hasOwnProperty('age')   //false 不存在
test.hasOwnProperty('toString') //false 原型链上属性

可以看到,只有自身存在该属性时,才会返回true。适用于只判断自身属性的场景。

参考的文章:

  • js检测对象中是否存在某个属性
  • 判断一个对象是否有某一个属性

JS根据身份证号码算年龄

原文文章:JS根据身份证号码算年龄

element ui的表格鼠标定义右键菜单

上代码:


<template><!--
@property { tableData :  {Array} 表格数据 }
@property { columData :  {Array} 表头数据 }
@property { menuList :  {Array} 右键菜单 }
@property { myKey :  {String} 唯一标识。}
@property { isRadio :  {Boolean} 是否单选,默认false。}
@property { emptyText :  {String} 空数据时显示的文本内容,默认暂无数据。}
@method  { selectItem :  {Function(selection, row)} 当用户手动勾选数据行的 Checkbox 时触发的事  }
@method  { selectAll :  {Function(selection)} 当用户手动勾选全选 Checkbox 时触发的事件  }
@method  { selectionChange :  {Function(selection)} 当选择项发生变化时会触发该事件  }
@method  { rowClick :  {Function(row, column, event)} 当某一行被点击时会触发该事件  }
@method  { rowContextmenu :  {Function(row, column, event)} 当某一行被鼠标右键点击时会触发该事件 }
@method  { rowDblclick :  {Function(row, column, event)} 当某一行被双击时会触发该事件  }--><div class="air-table-wrapper"><el-tableref="table"id="table":data="tableData":height="height":highlight-current-row="true"tooltip-effect="dark"style="width: 100%;":row-class-name="rowClassName":header-row-class-name="headerClassName"@empty-text="emptyText"@select="selectItem"@select-all="selectAll"@selection-change="selectionChange"@row-click="rowClick"@row-contextmenu="rowContextmenu"@row-dblclick="rowDblclick"><!-- checkbox --><el-table-column type="selection" v-if="showSelection" width="56" align="center"></el-table-column><!-- index 序号 --><el-table-column v-if="showIndex" label="序号" type="index" width="50"></el-table-column><!--列表的表头循环--><el-table-columnv-for="(column, index) in columData":key="index":prop="column.prop":label="column.label":width="column.width":align="column.align||'left'"show-overflow-tooltip><template slot-scope="scope"><imgv-if="column.isImg":src="scope.row[column.prop]?$sourcePrefix+scope.row[column.prop]:'javascript:;'"style="max-width: 100%;height:auto"><spanv-if="!column.isImg&&!column.codeMap&&column.type !== 'select'&&column.type !== 'text'&&column.type !== 'op-icon' &&column.type !== 'cj-icon'&& column.type !== 'datetime' && column.type !== 'select_input'"v-html="scope.row[column.prop]":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]"></span><!-- type为op-icon时,为门诊工作站的患者列表的带转入标注 --><spanclass="icon"v-if="column.type === 'op-icon'":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]"><span v-if="scope.row[column.prop] === '待转出'"><img src="~@images/work/icon_zhuanru.png" alt></span><span v-if="scope.row[column.prop] === '外院转入'"><img src="~@images/work/icon_zhuanchu.png" alt></span><span v-if="scope.row[column.prop] === '跟台手术患者'"><img src="~@images/work/icon_gentai.png" alt></span><span v-if="scope.row[column.prop] === '跟台手术患者(审核)'"><img src="~@images/work/icon_gentai_weishenhe.png" alt></span></span><!-- type为cj-icon时,为采集工作站的标本类型 --><spanclass="icon"v-if="column.type === 'cj-icon'":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]"><span v-if="scope.row[column.prop] === '血沉'"><img src="~@images/work/icon_shiguan_hei.png" alt></span><span v-if="scope.row[column.prop] === '生化检验'"><img src="~@images/work/icon_shiguan_hong.png" alt></span><span v-if="scope.row[column.prop] === '凝血常规'"><img src="~@images/work/icon_shiguan_lan.png" alt></span><span v-if="scope.row[column.prop] === '血流变学'"><img src="~@images/work/icon_shiguan_lv.png" alt></span><span v-if="scope.row[column.prop] === '血常规'"><img src="~@images/work/icon_shiguan_zi.png" alt></span></span><!-- type为text时,为门诊工作站的医嘱列表的带转入标注 --><spanclass="text"v-if="column.type === 'text' && scope.row[column.prop] === item.status"v-for="(item,index) of column.option":key="index"v-html="item.title":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]":style="{'color': (scope.row[column.prop]==column.option[0].title?column.option[0].color:(scope.row[column.prop] === column.option[1].title?column.option[1].color:(scope.row[column.prop]==column.option[2].title?column.option[2].color:column.option[3].color)))}"></span><!-- type为select时,为下拉选择框 --><spanv-if="column.type === 'select'":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]"><el-selectv-model="scope.row[column.prop]":class="scope.row[column.prop] === 2 ? column.textCalss :''"placeholder="请选择"><el-optionv-for="item in column.options":key="item.value":label="item.label":value="item.value"></el-option></el-select></span><!-- type为select时,为input在下拉选择框中 --><spanv-if="column.type === 'select_input'"><div v-if="column.tableCommands.type==='buttons'"><el-buttonv-for="(btn,index) in column.tableCommands.commandList"v-if="btn.hasAuth && btn.commandAvailable(scope.$index,scope.row)":style="{'color':btn.label === '删除'? '#FB7B7B':''}":key="index"type="text"size="small"@click="btn.command(scope.$index,scope.row)">{{btn.label}}</el-button></div><!--下拉类型操作--><el-dropdownv-if="column.tableCommands.type==='dropDown'"@command="handleDropDownMenuCommand"style="cursor:pointer":trigger="column.tableCommands.trigger||'hover'"><span class="el-dropdown-link">操作<i class="el-icon-caret-bottom el-icon--right"></i></span><el-dropdown-menu slot="dropdown"><el-dropdown-itemv-for="(option,index) in column.tableCommands.commandList"v-if="option.hasAuth && option.commandAvailable(scope.$index,scope.row)":key="index":command="{callback:option.command,row:scope.row,index:scope.$index}">{{option.label}}</el-dropdown-item></el-dropdown-menu></el-dropdown><!-- <el-selectv-model="scope.row[column.prop]":class="scope.row[column.prop] === 2 ? column.textCalss :''"placeholder="请选择"><el-option :label="column.options[0].label" :value="column.options[0].value"></el-option><el-option :label="column.options[1].label" :value="column.options[1].value"></el-option><el-optionv-for="item in column.options":key="item.value":label="item.label":value="item.value"><el-input v-if="item.value===1" v-model="scope.row[column.prop]" placeholder="请输入内容"></el-input></el-option></el-select> --></span><!-- 时间选择器 --><spanv-if="column.type === 'datetime'"><el-date-pickerv-model="scope.row[column.prop]"type="datetime"format="yyyy-MM-dd HH:mm:ss"value-format="yyyy-MM-dd HH:mm:ss"placeholder="选择停止时间"></el-date-picker></span><!--不含codeMap,服务器返回内容即显示内容--><!--:class="column.diffStyle?column.diffStyle(scope.row[column.prop]):[]"--><spanv-if="!column.isImg&&column.codeMap&&column.type != 'select'"v-html="column.codeMap[scope.row[column.prop]]":class="column.diffClassList?column.diffClassList(scope.row[column.prop]):[]"></span><!--含有codeMap(数字码与内容的映射),服务器返回的是code,根据code映射显示实际内容--><!-- 右键菜单 --></template></el-table-column><!-- 表格内的按钮 --><el-table-columnv-if="tableCommands"label="操作":width="tableCommands":align="tableCommands.align||'left'"><template slot-scope="scope"><!--按钮组类型操作--><div v-if="tableCommands.type==='buttons'"><el-buttonv-for="(btn,index) in tableCommands.commandList"v-if="btn.hasAuth && btn.commandAvailable(scope.$index,scope.row)":style="{'color':btn.label === '删除'? '#FB7B7B':''}":key="index"type="text"size="small"@click="btn.command(scope.$index,scope.row)">{{btn.label}}</el-button></div><!--下拉类型操作--><el-dropdownv-if="tableCommands.type==='dropDown'"@command="handleDropDownMenuCommand"style="cursor:pointer":trigger="tableCommands.trigger||'hover'"><span class="el-dropdown-link">操作<i class="el-icon-caret-bottom el-icon--right"></i></span><el-dropdown-menu slot="dropdown"><el-dropdown-itemv-for="(option,index) in tableCommands.commandList"v-if="option.hasAuth && option.commandAvailable(scope.$index,scope.row)":key="index":command="{callback:option.command,row:scope.row,index:scope.$index}">{{option.label}}</el-dropdown-item></el-dropdown-menu></el-dropdown></template><!--v-if="commandAvailable(option.disabledRows,option.disabledEffectInPage,scope.$index)"--></el-table-column><!-- 添加按钮 --><template slot="append" v-if="showAdd"><Button buttonType="colorButtonroundOrange" @click="addClick"></Button></template></el-table><div class="remark" v-if="tableData.length >100">查询数据多余100条最大限制,请调整查询条件后重试!</div><div v-if="dialogVisible" @click="dialogVisible = false" class="modal"><divclass="air-contex-menu"v-if="dialogVisible"v-on:click="hidePanel":style="{top: positionD.top + 'px',left: positionD.left+'px'}"><!--  <el-button class="return" type="text"  icon="el-icon-close" @click="dialogVisible = false"></el-button> --><ul><liv-for="(btn,btnIndex) of menuList":key="btnIndex"v-if="btn.hasAuth && btn.commandAvailable(listData.index,listData.row)"><divclass="menu_item"@click="btn.command(listData.index,listData.row);dialogVisible=false">{{btn.label}}</div></li></ul></div></div></div>
</template>
<script>
export default {name: "airtable",// 框选的指令directives: {drag: {// 指令的定义inserted: function(el, binding, vnode) {var oDiv = el;vnode.context.tableTop = getY(oDiv);vnode.context.tableLeft = getX(oDiv);//方法是确定列表到屏幕的位置function getX(obj) {var parObj = obj;var left = obj.offsetLeft;while ((parObj = parObj.offsetParent)) {left += parObj.offsetLeft;}return left;}//方法是确定列表到屏幕的位置function getY(obj) {var parObj = obj;var top = obj.offsetTop;while ((parObj = parObj.offsetParent)) {top += parObj.offsetTop;}return top;}// 禁止右键默认菜单oDiv.oncontextmenu = function() {return false;};oDiv.onmousedown = function(ev) {// 防止奇葩操作if ([2, 3, 4, 5].indexOf(ev.buttons) > -1) {if (selDiv) {oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);}return;}// 获取当前scrollTopvar scrollingTop = vnode.context.targetScroll;if (vnode.context.isRadio) return;vnode.context.$selectState(true);//初始化不显示vnode.context.toggleShow = false;//确保用户在移动鼠标的时候只初始化一次选中var flag = true;// 获取表格的宽高let tableWidth = vnode.context.$el.clientWidth;let tableHeight = vnode.context.$el.clientHeight;//用来存储列表var selList = [];//获得指令下的dom对应的表格var fileNodes = oDiv.getElementsByTagName("tr");//获得鼠标var evt = window.event || arguments[0];var startX = evt.x || evt.clientX;var startY = evt.y || evt.clientY;var top, left;//时时获得top = getY(oDiv);left = getX(oDiv);var selDiv = document.createElement("div");selDiv.style.cssText ="position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px solid rgba(255,165,22,0.38);background-color:rgba(0,0,0,0.38);z-index:1000;filter:alpha(opacity:60);opacity:0.6;display:none;";selDiv.id = "selectDiv";oDiv.getElementsByClassName("el-table__body")[0].appendChild(selDiv);selDiv.style.left = startX + "px";selDiv.style.top = startY + "px";var _x = null;var _y = null;vnode.context.clearEventBubble(evt);// 打开开关vnode.context.mouseflag = true;// 鼠标拖动时画框document.onmousemove = function(ev) {evt = window.event || arguments[0];_x = evt.x || evt.clientX;_y = evt.y || evt.clientY;// 为了确定是点击事件还是移动事件if (Math.abs(_x - startX) < 5 && Math.abs(_y - startY) < 5) {return;}vnode.context.selectItemFlag = false;// 为了确保只有一次的渲染每次框选都把默认选中为空(针对当前页)if (flag) {// 重置选中cssfor (var i = 0; i < fileNodes.length; i++) {if (fileNodes[i].className.indexOf("el-table__row") != -1) {fileNodes[i].className = "el-table__row";selList.push(fileNodes[i]);}}// 判断翻页是否保存选中数据// if (vnode.context.pageDataFlag) {// 判断当前页是否有选中的vnode.context.tableData.forEach(item => {vnode.context.$refs.table.toggleRowSelection(item, false);vnode.context.multipleSelection.forEach((ele, i) => {if (item[vnode.context.myKey] === ele[vnode.context.myKey]) {vnode.context.multipleSelection.splice(i, 1);i = i - 1;}});});// } else {//     vnode.context.multipleSelection = []// }flag = false;}// 判断鼠标移动是否超出在当前表格区域if (_x <= left ||_x >= left + tableWidth ||_y <= top ||_y >= top + tableHeight) {document.onmousemove = null;if (selDiv) {oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);}(selList = null),(_x = null),(_y = null),(selDiv = null),(startX = null),(startY = null),(evt = null);vnode.context.mouseflag = false;vnode.context.$handleSelect();}if (vnode.context.mouseflag) {if (selDiv.style.display === "none") {selDiv.style.display = "";}var scrolling = oDiv.getElementsByClassName("el-table__body-wrapper");// 两个表格的时候需增加滚屏的高度// var main_scrolling=document.getElementsByClassName("common_table_height");// selDiv.style.left = Math.min(_x, startX)-left+scrolling[0].scrollLeft +main_scrolling[0].scrollLeft+ "px";// console.log(scrolling)selDiv.style.left =Math.min(_x, startX) - left + scrolling[0].scrollLeft + "px";//48是表头的高度// selDiv.style.top = Math.min(_y, startY)-top - 48 + scrolling[0].scrollTop+main_scrolling[0].scrollTop+ "px";selDiv.style.top =Math.min(_y, startY) -top -oDiv.getElementsByClassName("is-leaf")[0].offsetHeight +scrollingTop +"px";selDiv.style.width = Math.abs(_x - startX) + "px";if (scrolling[0].scrollTop > scrollingTop) {selDiv.style.height =Math.abs(_y - startY) + scrolling[0].scrollTop + "px";} else {selDiv.style.height = Math.abs(_y - startY) + "px";}// ---------------- 关键算法确定列表的选中靠的是index---------------------var _l = selDiv.offsetLeft,_t = selDiv.offsetTop;var _w = selDiv.offsetWidth,_h = selDiv.offsetHeight;for (var i = 0; i < selList.length; i++) {var sl = selList[i].offsetWidth + selList[i].offsetLeft;var st = selList[i].offsetHeight + selList[i].offsetTop;if (sl > _l &&st > _t &&selList[i].offsetLeft < _l + _w &&selList[i].offsetTop < _t + _h) {if (selList[i].className.indexOf("seled") === -1 &&!vnode.context.tableData[i][vnode.context.rowDisabled]) {selList[i].className = selList[i].className + " seled";vnode.context.$refs.table.toggleRowSelection(vnode.context.tableData[i],true);vnode.context.multipleSelection.push(vnode.context.tableData[i]);}} else {if (selList[i].className.indexOf("seled") != -1) {selList[i].className = "el-table__row";vnode.context.$refs.table.toggleRowSelection(vnode.context.tableData[i],false);let index = vnode.context.multipleSelection.indexOf(vnode.context.tableData[i]);vnode.context.multipleSelection.splice(index, 1);}}}// ---------------- 关键算法结束---------------------}if (document.onmousemove) {vnode.context.clearEventBubble(evt);}};//在鼠标抬起后做的重置oDiv.onmouseup = function() {//把鼠标移动事初始化document.onmousemove = null;if (selDiv) {oDiv.getElementsByClassName("el-table__body")[0].removeChild(selDiv);}(selList = null),(_x = null),(_y = null),(selDiv = null),(startX = null),(startY = null),(evt = null);vnode.context.mouseflag = false;vnode.context.$selectState(false);// 防止重复$handleSelect()事件if (!vnode.context.selectItemFlag) {vnode.context.$handleSelect();vnode.context.selectItemFlag = false;}};};}}},props: {// 对于列表中唯一的字段myKey默认为idmyKey: {type: String,default: "id"},//有没有checkboxshowSelection: {type: Boolean,default: false},// 是否显示表头showIndex: {type: Boolean,default: false},//列表的数据tableData: {type: Array,default: () => []},//传过来的表头信息columData: {type: Array,default: () => []},/* 表格类的按钮 */tableCommands: {type: Object,default: () => {}},//右键菜单menuList: {type: Array,default: () => []},/* 是否设置右键菜单 */iscontextmenu: {type: Boolean,default: true},/* 设置是否有双击事件 */isDblclick: {type: Boolean,default: true},// 当表格需要单选的时候isRadio: {type: Boolean,default: false},// 是否显示添加按钮showAdd: {type: Boolean,default: false},// 表格高度height: {type: [Number, String],default: 500},// 空数据时显示的文本内容emptyText: {type: String,default: "暂无数据"}},data() {return {// 当前行的数据listData: {index: "",row: ""},//指令中确定的时候是鼠标按下事件mouseflag: false,//选中的数组multipleSelection: [],//控制右键菜单弹出显示dialogVisible: false,//右键鼠标的位置position: {left: 0,top: 0},//当前右键点击的列currentRow: [],//当前滚动的距离,targetScroll: 0,// 是否点击单选按钮selectItemFlag: false};},computed: {// 通过滚动距计算阴影 classheaderClassName() {if (this.targetScroll === 0) {return "air-table-header__class";} else if (this.targetScroll > 0 && this.targetScroll <= 100) {return "air-table-header__class air-table-header__scroll1";} else if (this.targetScroll > 100 && this.targetScroll <= 200) {return "air-table-header__class air-table-header__scroll2";} else {return "air-table-header__class air-table-header__scroll3";}},menuH() {return 25 + this.menuList.length * 34;},positionD() {return this.position;},size() {return this.getViewportSize();}},mounted() {this.$refs.table.$refs.bodyWrapper.addEventListener("scroll",this.handleScroll);},beforeDestroy() {this.$refs.table.$refs.bodyWrapper.removeEventListener("scroll",this.handleScroll);clearTimeout(this.timer);},methods: {//清除默认事件clearEventBubble(evt) {if (evt.stopPropagation) evt.stopPropagation();else evt.cancelBubble = true;if (evt.preventDefault) evt.preventDefault();else evt.returnValue = false;},hidePanel(event) {event.stopPropagation();},//当单选时触发的事件selectItem(selection, row) {this.$emit("clickSelect", selection);},//当表头全选是触发的事件selectAll(selection) {this.$emit("clickSelect", selection);},// 选项发生改变事件selectionChange(selection) {this.$emit("clickSelect", selection);},//列表单击选中事件rowClick(row, column, event) {this.$emit("rowClick", row, column, event);},//列表右键点击事件rowContextmenu(row,column, event) {if (this.iscontextmenu && this.menuList.length > 0) {this.dialogVisible = false;this.dialogVisible = true;let defaultIndex = 0;this.tableData.forEach((el, index) => {if ((el === row)) {defaultIndex = index;}});let toRightX = this.size.width - event.clientX;let toBottomY = this.size.height - event.clientY;if (toRightX < 250) {this.position.left = event.clientX - 250;} else {this.position.left = event.clientX;}if (toBottomY < this.menuH) {this.position.top = event.clientY - this.menuH;} else {this.position.top = event.clientY;}//阻止默认事件event.preventDefault();event.returnValue = false;/*  event.stopPropagation(); */this.listData.index = defaultIndex;this.listData.row = row;//显示弹出窗this.$emit("contextmenu", row, event);}},//双击事件rowDblclick(row, column, event) {if (this.isDblclick === true) {this.$emit("rowDblclick", row, column, event);}},//监听表格的滚动handleScroll(e) {this.targetScroll = e.target.scrollTop;},// 添加按钮点击事件addClick() {this.$emit("addClick");},handleClose(e) {this.dialogVisible = false;},rowClassName() {return "rowClassName";},handleDropDownMenuCommand(commandObj) {let { callback, row, index } = commandObj;callback(index, row);}}
};
</script>
<style lang="less">
.air-table-wrapper {position: relative;.air-table-header__class {background-color: #e9e9e9;th {background-color: #e9e9e9;& > .cell {font-size: 12px;font-weight: 400;color: #666666;}}}.el-table__body-wrapper {background: #f9f9f9;}.remark {position: absolute;box-sizing: border-box;z-index: 100;bottom: 0;left: 0;width: 100%;line-height: 30px;padding: 0 10px;background: #e9e9e9;color: #00b8c4;text-align: center;font-size: 14px;}
}
.el-table td {background: #f9f9f9;border-bottom: 1px solid #dddddd;
}
.el-table {.el-table__row {.cell.el-tooltip {position: relative;font-size: 12px;font-weight: 400;color: #666666;.icon {position: absolute;top: 0;left: 0;text-align: center;width: 100%;height: 100%;line-height: 0;z-index: 1;}}}
}
.rowClassName:hover,
.current-row {td {background-color: #f1f7f9;}.cell.el-tooltip {color: #00b8c4;}
}#table {
}
.red_style {.el-input__inner {color: #fb7b7b;}
}
</style><style lang="less" scoped>
@import "./index";
</style>

使用:

 <CommonTable:tableData="WtableList":columData="tableObj.tableColumns":menuList="tableObj.commandList" //tableObj.commandList为菜单配置:height="tableHeight"@rowDblclick="rowDblclick"@rowClick="rowClick"
></CommonTable>
 commandList: [{label: "编辑患者信息",hasAuth: true,command: this.handleEdit,commandAvailable: function() {return true;}},{label: "下达医嘱",hasAuth: true,command: this.handleRDAdvice,commandAvailable: function() {return true;}},{label: "预约住院",hasAuth: true,command: this.handleAhospitalization,commandAvailable: function() {return true;}},{label: "打印预约入院证明",hasAuth: true,command: this.handlePrint,commandAvailable: function() {return true;}},{label: "完成看诊",hasAuth: true,command: this.handleCVisit,commandAvailable: function() {return true;}},{label: "撤回",hasAuth: true,command: this.handleRetract,commandAvailable: function() {return true;}}
]

这些方法就可以在methods中使用了

参考的文章:

  • JS简单实现自定义右键菜单
  • Vue2.5 结合 Element UI 之 Table 和 Pagination 组件实现分页
  • 基于vue和elementUI封装框选表格组件

vue 操作数组的变异方法和非变异方法

文章地址: vue 操作数组的变异方法和非变异方法

vue文档:变异方法 (mutation method)

变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组:

  • push( )
  • pop( )
  • shift( )
  • unshift( )
  • splice( )
  • sort( )
  • reverse( )

也有非变异 (non-mutating method) 方法,例如:

  • filter( )
  • concat( )
  • slice( )

这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组

vue使用lodash

原文文章:vue使用lodash

使用lodash可以做什么:

  • JS中深拷贝数组、对象、对象数组方法
  • js判断对象是否为空对象的几种方法
  • 在JavaScript中,如何判断数组是数组?
  • javaScript遍历对象、数组总结
  • JS 对象的深拷贝和浅拷贝
  • 数据类型的转换

javascript页面刷新的几种方法

原文文章:javascript页面刷新的几种方法

vue watch对象内的属性

原文文章:vue watch对象内的属性

通过window.sessionStorage.getItem获取的值,一定要 通过JSON.parse()转成对象

原文文章:通过window.sessionStorage.getItem获取的值,一定要 通过JSON.parse()转成对象

vue项目中,定义并使用 全局变量,全局函数

原文文章:vue项目中,定义并使用 全局变量,全局函数

重构项目可能出现的问题

  • nodejs 升级后, vue+webpack 项目 node-sass 报错的解决方法
  • 升级vue-cli3报错(You are using the runtime-only build of Vue where the template compiler is not available. Either pre)
  • webpack与ts版本不兼容
  • babel 7.x 和 webpack 4.x 配置vue项目
  • webpack踩坑--webpack 2.x升级至4.x

前端工作过程遇到的问题总结(八)相关推荐

  1. 前端工作过程遇到的问题总结(九)

    目录 JS中every()和some()的用法 置换元素和非置换元素 ES6的map数据类型转换 关于原生方法增加参数的问题(element增加参数) element-ui中的表格el-table滚动 ...

  2. 【回顾九月份第一周】 为什么你的前端工作经验不值钱

    原链接:http://bluezhan.me/weekly/#/9-1 1.web前端 JavaScript 函数式编程术语大全 SegmentFault 社区访谈 | Linxz:只会写 CSS 不 ...

  3. [置顶] 谈谈找工作过程中的那些环节、注意点和经验

    作者:寒小阳 时间:2013年9月. 出处:http://blog.csdn.net/han_xiaoyang/. 声明:版权所有,转载请注明出处,谢谢. 前面写了两篇面试相关的总结性文章,一篇是找工 ...

  4. 前端工作面试问题(下)

    续 "前端工作面试问题(上)" JS相关问题: 解释下事件代理. 在传统的事件处理中,你按照需要为每一个元素添加或者是删除事件处理器.然而,事件处理器将有可能导致内存泄露或者是性能 ...

  5. 19岁中专学历是怎么在广州找到前端工作的?

    大家好,我是若川.持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  6. 计算机工作过程中 电压应稳定在,计算机组装与维修前三章测评卷.doc

    计算机组装与维修前三章测评卷 计算机组装与维修第一.二.三章测评卷 2011年10月17日 一.选择题(第小题1分,共40分) 1.USB2.0接口数据传输速率的理论值是 A.8Mbps B.480M ...

  7. 主动模式下FTP的详细工作过程

    文中有不对或者有不清楚的地方,请大家告诉我,谢谢!   主动模式下FTP的详细工作过程   PORT FTP是常用的FTP工作方式,当客户端的连接请求到来时,FTP服务器会利用默认的21端口与客户端建 ...

  8. 前端工作面试问题(上)---转

    前端工作面试问题(上) 前段时间专心整理一下关于前端的面试问题.感谢耐心尽责的楷豪和闻东师兄最近给我们的指导和建议.大家可以通过这些问题,大家可以顺便看以下自己的水平. https://github. ...

  9. 执行引擎的工作过程、Java代码编译和执行的过程、解释器、JIT编译器

    执行引擎概述 执行引擎是Java虛拟机核心的组成部分之一. "虚拟机"是-一个相对于"物理机"的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接 ...

最新文章

  1. BPSK,QPSK,2FSK,16QAM,64QAM信号在高斯信道与瑞利信道下的误码率性能仿真
  2. 用python画常密度轮廓线,如何使用Matplotlib在极坐标中绘制具有等高线密度线的散点图?...
  3. zendguard php5.4,ZendGuardLoader6.0.0支持PHP5.4.x系列
  4. Linux图片马PHP,php 根据请求生成缩略图片保存到Linux图片服务器的代码
  5. /etc/security/limits.conf的相关说明
  6. js实现网页跳转脚本
  7. 使用python实现栈和队列
  8. java取负数_[Java] 告别“CV 工程师”码出高效!(基础篇)
  9. 基于京东家电商品知识图谱的自动问答系统(二) -- IDEA搭建开发环境
  10. mongodb driver c#语法
  11. 解决Chrome浏览器无法加载flash插件的问题
  12. 微信小程序-tab标签栏实现教程
  13. 多进程统计策略盈亏分布——从零到实盘12
  14. 一行 Python 代码能实现什么丧心病狂的功能?
  15. FleaPHP 开发指南 - 3. 应用程序入口
  16. Linux 基金会成立小组支持边缘网络开发;浙江绍兴用 AI 监控厨房
  17. 关于AQS中enq( )方法CAS操作的疑惑
  18. 图像处理--角点检测
  19. RGBA、ARGB和HEX颜色格式转换javascript实现
  20. 【转载】在个股回测中,如何才能避开新股的一字涨停?

热门文章

  1. 安卓毕业设计app项目基于Uniapp+SSM实现的移动端的酒店餐饮住宿订餐点餐管理系统
  2. 计算机ps计划,PS学习计划 - 作业部落 Cmd Markdown 编辑阅读器
  3. 企业想要搭建CRM平台该如何操作?
  4. SAP 项目总结【一】
  5. 搭建邮件服务器,该怎么选择邮件服务器软件呢?
  6. vue 中点击切换图标,切换选中状态
  7. 怀旧与超越 | RO 仙境传说:新世代的诞生的年度故事
  8. 硬币之谜:如何用最少的步骤拿完所有硬币?
  9. ✯GLSL-2-着色器概述
  10. java 用itext-asian解决itext pdf中文不显示问题