文章目录
- 元素滚动到可视化区域
- 检测服务器上是否存在某个文件
- Vue3 项目中,纯前端如何实现跨标签通信:
- 监听localstorage的变化
- 多数组取交集
- 判断hex颜色值是深色还是浅色
- js判断是手机端还是移动端
- fetch直接读文件内容,解决乱码问题
- 前端导出文件
- 移动端和pc端js判断手指的上滑,下滑,左滑,右滑,事件监听 和 判断鼠标滚轮向上滚动滑轮向下滚动
- vue2、vue3全局挂载
- js点击按钮复制文本方法
- vite vue3 遍历图片不显示问题
- @keyup.enter.native不生效问题解决
- js将一维数组转为二维数组
- electron中指定默认下载路径和名称
- TypeScript 中?: 、??、?. 、!. 、&&= 、??= 、||= 含义解析
- input框中输入的值,需要导出pdf或者打印出来为空的问题
- js写货币格式(每三位一个逗号分隔)
- 大数值转换为 K,M,G,T或者KB,MB,GB,TB
- 数组包对象,同时对多个属性进行筛选(搜索查询)
- 字符串中混合数字,按照部分数字排序
- 数组包对象,按照对象的某一属性去重
- 数组包对象,以对象的某一个属性排序
- getCookie、setCookie、removeCookie
- 防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
- 将文件类型转换成字符串数组
- 将对象转化为URL的查询字符串(对象转化为地址栏问号传参)
- vue3中解构地址栏参数 (比下面getUrlParams好用)
- 截取地址栏参数
- dom节点删除 删除子节点 removeChild
- 如何隐藏滚动条 滚动条的样式修改
- 获取系统时间日期, 返回:日期,星期
- 将rangepick 时间选择的数据进行过滤
- 字符串超出长度显示省略号 css方法
- 字符串超出长度显示省略号 js截取方法
- input 取消默认提示框
- 利用@media与@media screen进行响应式布局
- 表格时间格式化
- 日期格式化
- 获取设备信息方法
- 封装公共路径跳转的方法
- 扫码的方法 h5 不兼容
元素滚动到可视化区域
document.getElementById('id')?.scrollIntoView({
behavior: 'smooth',
// 定义动画过渡效果, "auto"或 "smooth" 之一。默认为 "auto"
// 指定滚动行为是否应该平滑地进行。'smooth' 表示平滑滚动,而 'auto' 表示默认行为(通常是瞬间跳转)。
block: 'center',
// 定义垂直方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "start"
// 指定垂直方向上的对齐方式。'start' 表示对齐到顶部,'center' 表示对齐到中间,'end' 表示对齐到底部,'nearest' 表示对齐到最接近的边缘。
inline: 'nearest',
// 定义水平方向的对齐, "start", "center", "end", 或 "nearest"之一。默认为 "nearest"
// 指定水平方向上的对齐方式。与 block 属性类似,但用于水平方向。
});
检测服务器上是否存在某个文件
fetch(
'http://192.168.11.105:8102/outputs/fea4bd3f-9c46-440f-b529-8c83801ba03e/4.tracing/sample_clustermap.png',
).then((res) => {
console.log(res.status);
});
检测当前电脑是否存在某个文件
注意这里用fs的话,只能检测项目部署的那台电脑(即,项目部署到那台电脑,检测那台电脑)
const fs = require('fs');
let path = 'F:\\xi1a.ico';
if (fs.existsSync(path)) {
console.log('存在');
} else {
console.log('不存在');
}
Vue3 项目中,纯前端如何实现跨标签通信:
下面介绍了第三个,其他的自行百度,很简单的
- BroadCast Channel
- Service Worker
- LocalStorage + storage
- open + postMessage
监听localstorage的变化
注意:这里只能监听同源不同窗口的localStorage变化或者iframe与父级的localStorage 变化
可以通过监听storage事件来监控localStorage的变化
请注意,storage事件只会在其他页面(相同域下的不同页面)修改localStorage时触发,如果是在当前页面进行修改,监听函数不会被触发,因为当前页面本身就是修改的一部分。
window.addEventListener('storage', function (e) {
console.log('Key:', e.key);
console.log('Old Value:', e.oldValue);
console.log('New Value:', e.newValue);
console.log('URL:', e.url);
console.log('Storage area:', e.storageArea);
});
多数组取交集
const intersection = (arr: Array<any>, ...arr2: Array<any>) =>
[...new Set(arr)].filter((v) => arr2.every((b) => b.includes(v)));
let result = intersection([1, 2, 3, 4], [2, 3, 4, 7, 8], [1, 3, 4, 9]);
console.log(result); //[3,4]
判断两个数组是否有相同元素 返回相同元素(数组)
//判断两个数组是否有相同元素
export const ishasSameElement = (arr1: string[], arr2: string[]) => {
// 使用Set数据结构来存储数组的唯一元素
let set1 = new Set(arr1);
let set2 = new Set(arr2);
// 使用Intersection方法找出两个集合的交集,如果交集不为空,那么就存在共享的元素
let commonElements = new Set([...set1].filter((x) => set2.has(x)));
return Array.from(commonElements);
};
如果上面看不懂话的就用for循环遍历吧
判断hex颜色值是深色还是浅色
注意这里一定要是128,不要写0.5,仔细看看下面的公式,就不会相信0.5了, 1*0.5=0.5了,哈哈哈
export const hexIsDark = (hex: string) => {
// 将Hex颜色转换为RGB颜色
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
let rgb = result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: null;
let brightness: number = 0;
if (rgb) brightness = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;
return brightness < 128;
};
随机生成深浅样色
const randomColor = () => {
let deepColor = [];
let lightColor = [];
for (let i = 0; i < 100; i++) {
let color = '#' + parseInt(Math.random() * 0xffffff).toString(16);
if (hexIsDark(color)) {
deepColor.push(color);
} else {
lightColor.push(color);
}
}
console.log('deepColor', deepColor);
console.log('lightColor', lightColor);
};
js判断是手机端还是移动端
推荐使用UA去判断
使用UA判断
UA(UserAgent)是指HTTP请求头中的一部分,用于标识客户端的一些信息,比如用户的设备类型、浏览器型号等等。因此,我们可以通过判断UA中的关键字来确定页面访问者的设备类型。下面是实现的代码:
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if (isMobile) {
console.log('当前在手机端');
} else {
console.log('当前在PC端');
}
//判断是否在微信浏览器
var ua = navigator.userAgent.toLowerCase();
var isWeixin = ua.indexOf("micromessenger") != -1;
if (isWeixin) {
// 微信浏览器
}else{
//普通浏览器
if (isMobile) {
console.log('当前在手机端');
} else {
console.log('当前在PC端');
}
}
使用媒体查询判断
获取当前浏览器的屏幕宽度
if (window.innerWidth <= 1023) {
console.log('当前在手机端');
} else {
console.log('当前在PC端');
}
fetch直接读文件内容,解决乱码问题
fetch(‘文件路径’).then(async (r) => {
const text = await r.text();
console.log(text);
});
前端导出文件
将表格导出xlsx文件
import xlsx from 'node-xlsx';
import { saveAs } from 'file-saver';
/**
* 下载xlsx文件
* @param data 表格数据 [{},{}]
* @param name 文件名
*/
export const downloadXlsx = (data: any, fileName: string) => {
let headerArr: string[] = [];
let data2 = data.map((item: any, index: number) => {
let arr2 = [];
for (let key in item) {
if (index == 0) headerArr.push(key);
arr2.push(item[key]);
}
return arr2;
});
data2.unshift(headerArr);
//如果你已经将需要下载数据处理成二维数据的话,上面的操作可以不要,上面我是为了把table中的data处理成二维数组
let result = xlsx.build([{ name: 'sheet1', data: data2 }]);
const ab = Buffer.from(result, 'binary');
const blob = new Blob([ab]);
//可以 file-saver 直接下载,也可以用下面注释掉的创建a链接去下载
saveAs(blob, fileName);
// const blobUrl = URL.createObjectURL(blob);
// const a = document.createElement('a');
// a.href = blobUrl;
// a.download = fileName;
// a.click();
// window.URL.revokeObjectURL(blobUrl);
};
将表格导出 txt fasta fa csv tsv等文本文件
注意
TSV是用制表符(Tab,’\t’)作为字段值的分隔符,以此转换的格式生成的文件;
CSV是用半角逗号(’,’)作为字段值的分隔符,以此转换的格式生成的文件;
import Papa from 'papaparse';
import { saveAs } from 'file-saver';
/**
* 下载csv文件
* @param origin 列表数据对象 [{},{}]
* @param fileName 文件名
*/
export const downloadCSV = (origin: any, fileName: string) => {
let result = '';
if (fileName.includes('.tsv')) {
result = Papa.unparse(origin).replace(/,/g, '\t');
} else {
result = Papa.unparse(origin);
}
const blob = new Blob(['\uFEFF' + result], { type: 'text/plain;charset=utf-8' });
saveAs(blob, fileName);
};
js将二维数组转为 txt tsv csv fasta fa 等文本文件
//数组导出CSV文件
const exportCSV = (jsonData: Array<string[]>, fileName: string) => {
if (!jsonData || jsonData.length == 0) {
console.log('暂无数据');
return;
}
if (!fileName) {
fileName = 'exportCSV.csv';
}
let csvText = '';
//增加\t为了不让表格显示科学计数法或者其他格式
for (let i = 0; i < jsonData.length; i++) {
let row = '';
for (let item in jsonData[i]) {
row += `${jsonData[i][item]},`;
}
csvText += trim(row, ',') + '\n';
}
//encodeURIComponent解决中文乱码
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(csvText);
//通过创建a标签实现
let link = document.createElement('a');
link.href = uri;
//对下载的文件命名
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
//js实现类似php trim函数
const trim = (str: string, char: string) => {
if (char) {
str = str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '');
}
return str.replace(/^\s+|\s+$/g, '');
};
const data = [
['士大夫', 'dfg', 'fgh'],
['要让他', '取完', '和'],
['士大夫', 'dfg', 'fgh'],
['要让他', '取完', '和'],
];
exportCSV(data, 'test.tsv');
将字符串下载保存为 txt fasta fa csv tsv等文本文件
/**
* 下载txt fasta fa等文本文件
* @param text 文本内容
* @param fileName 文件名
*/
export const saveTextAsFile = (text: any, filename: string) => {
const blob = new Blob([text], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
//或者
/**
* 下载文件
* @param url 文件路径
* @param fileName 文件名称
*/
import { saveAs } from 'file-saver';
//安装一下 file-saver包
export const downloadTxt = (url: string, fileName: string) => {
const fileBlob = fetch(url).then((r) => r.blob())
const blob = new Blob(['\uFEFF'+fileBlob ], { type: 'text/plain;charset=utf-8' });
saveAs(blob, fileName);
};
下载文件
/**
* 下载文件
* @param content 文件内容
* @param fileName 文件名称
*/
export const download = (content: string, fileName: string) => {
const link = document.createElement('a');
link.href = encodeURI(content);
link.download = fileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
文件链接转文件流下载–主要针对pdf 解决谷歌浏览器a标签下载pdf直接打开的问题 还有excel下载
import { saveAs } from 'file-saver';
/**
* 文件链接转文件流下载--主要针对pdf 解决谷歌浏览器a标签下载pdf直接打开的问题 还有excel下载
* @param url :文件链接
* @param fileName :文件名;
* @param type :文件类型;
* @param fn :进度回调方法;
*/
export const saveFileToLink = (url: string, fileName: string) => {
let xhr = new XMLHttpRequest();
url = url.includes('https:') ? url.replace('https:', '') : url.replace('http:', ''); //资源路径动态获取请求的方式HTTPS或HTTP
xhr.open('get', url, true);
xhr.setRequestHeader('Content-Type', 'application/');
xhr.setRequestHeader('If-Modified-Since', '0'); //解决缓存问题,每次请求都去请求服务器获取最新数据
xhr.responseType = 'blob';
xhr.onprogress = function (e) {
//文件下载进度
// if (fn && typeof fn == 'function') {
// fn(e); //监听文件下载进度;
// }
};
xhr.onload = function () {
if (this.status == 200) {
//接受二进制文件流
let blob = this.response;
saveAs(blob, fileName);
}
};
xhr.send();
};
移动端和pc端js判断手指的上滑,下滑,左滑,右滑,事件监听 和 判断鼠标滚轮向上滚动滑轮向下滚动
const scrollFunc = (e) => {
e = e || window.event;
let wheelDelta = e.wheelDelta ? e.wheelDelta : -e.detail * 50;
if (wheelDelta > 0) {
console.log(wheelDelta + '滑轮向上滚动');
let dom = document.querySelector('.header-contanier');
dom.style.display = 'flex';
let dom2 = document.querySelector('.navNull');
dom2.style.display = 'block';
}
if (wheelDelta < 0) {
console.log(wheelDelta + '滑轮向下滚动');
let dom = document.querySelector('.header-contanier');
let dom2 = document.querySelector('.navNull');
dom.style.display = 'none';
dom2.style.display = 'none';
}
};
if (document.addEventListener) {
//火狐使用DOMMouseScroll绑定
document.addEventListener('DOMMouseScroll', scrollFunc, false);
}
//其他浏览器直接绑定滚动事件
window.onmousewheel = document.onmousewheel = scrollFunc; //IE/Opera/Chrome
// touchstart: //手指放到屏幕上时触发
// touchmove: //手指在屏幕上滑动式触发
// touchend: //手指离开屏幕时触发
// touchcancel: //系统取消touch事件的时候触发,这个好像比较少用
let startX: number = 0;
let startY: number = 0;
document.addEventListener(
'touchstart',
(e) => {
e.preventDefault();
// console.log(e);
startX = e.changedTouches[0].pageX;
startY = e.changedTouches[0].pageY;
},
false,
);
// document.addEventListener(
// 'touchend',
// (e) => {
// e.preventDefault();
// console.log(e);
// },
// false,
// );
document.addEventListener(
'touchmove',
(e) => {
// e.preventDefault();
let moveEndX = e.changedTouches[0].pageX;
let moveEndY = e.changedTouches[0].pageY;
let X = moveEndX - startX;
let Y = moveEndY - startY;
if (Math.abs(X) > Math.abs(Y) && X > 0) {
console.log('right');
} else if (Math.abs(X) > Math.abs(Y) && X < 0) {
console.log('left');
} else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
console.log('bottom');
} else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
console.log('top');
} else {
alert('just touch');
}
},
false,
);
vue2、vue3全局挂载
vue3全局挂载
推荐使用(provide/inject),不推荐使用globalProperties:最新版本的已经弃用了
main.ts中
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { store } from './store';
import ant from 'ant-design-vue';
import { ObjAscend, ObjDescend } from './utils/utils';
const app = createApp(App);
//在这里挂载 这里挂载的是两个函数
app.provide('ObjAscend', ObjAscend);
app.provide('ObjDescend', ObjDescend);
//不推荐这种挂载方式了,最新版本已经弃用了
app.config.globalProperties.window = window;
app.use(router).use(store).use(ant).mount('#app');
组件中
import { defineComponent, inject } from 'vue';
let ObjAscend:(parm:string)=>any = inject('ObjAscend')
let ObjDescend:any = inject('ObjDescend')
vue2全局挂载
main.ts中
import Vue from 'vue'
import App from './App'
import wLoading from "@/component/w-loading.vue";
import store from './store'
import {
showToastOrNavTo,
scanCode
} from '@/utils/util'
Vue.prototype.$store = store;
Vue.prototype.showToastOrNavTo = showToastOrNavTo;
页面中 :直接this就好了
mounted() {
this.showToastOrNavTo()
this.scanCode()
}
js点击按钮复制文本方法
//方法一:
clickCopy(text) {
const save = function (evn) {
evn.clipboardData.setData("text/plain", text);
evn.preventDefault(); // 阻止默认行为
};
document.addEventListener("copy", save); // 添加一个copy事件
document.execCommand("copy"); // 执行copy方法
this.$message({ message: "复制成功", type: "success" });
}
//方法二:
clickCopy(code) {
let oInput = document.createElement('input');
oInput.value = code;
document.body.appendChild(oInput);
oInput.select(); // 选择对象;
document.execCommand("Copy"); // 执行浏览器复制命令
this.$message({ message: '复制成功', type: 'success' });
oInput.remove()
}
vite vue3 遍历图片不显示问题
官网:vite官网参考
<div
class="header-menu-list flex ac"
v-for="(item, i) in header"
:key="item.title"
>
<div class="header-img">
<img :src="getimg(i)" alt="" />
</div>
</div>
<script>
methods: {
// 图片
getimg(e) {
let path1 = [
"/src/assets/img/guangfu1.png",
"/src/assets/img/day.png",
"/src/assets/img/sum.png",
"/src/assets/img/yongshuiliang.png",
"/src/assets/img/leijiyongshui.png",
];
//属性是href,正好是函数的返回值
//(我测试的,打包后就不能用了,绝对路径可以:(E:/img/sum.png))
// 是在不行也可以用 import url1 from '/@/assets/img/shamen.jpg'; 最后吧rul1放到数组里面再去遍历
return new URL(path1[e],import.meta.url).href //import.meta 对象包含关于当前模块的信息。
},
}
<script/>
@keyup.enter.native不生效问题解决
el-form表单中的el-input回车刷新页面,@keyup.enter.native不生效问题解决
表单中只有一个input,键盘回车会刷新页面,@keyup.enter就会失效
解决方案:
1:在表单里加一个不显示的input(不推荐此写法)
2:在el-form上添加@submit.native.prevent(推荐)
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" @submit.native.prevent>
<el-form-item label="客户id" prop="customerId">
<el-input v-model="queryParams.customerId" placeholder="请输入客户id" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
js将一维数组转为二维数组
如果多维数组转以为数组用 flat() arr.flat()
//推荐使用 convertTo2DArray
const convertTo2DArray = (arr: Array<any>, chunkSize: number) => {
var result = [];
//slice:截取,返回新数组,不改变原数组
for (var i = 0; i < arr.length; i += chunkSize) {
result.push(arr.slice(i, i + chunkSize));
}
return result;
}
const arrToMatrix = (arr: Array<any>, num: number) => {
var matrix = [], i, k;
for (i = 0, k = -1; i < arr.length; i++) {
if (i % num === 0) {
k++;
matrix[k] = [];
}
matrix[k].push(arr[i]);
}
return matrix;
}
electron中指定默认下载路径和名称
const { BrowserWindow} = require('electron');
// 触发下载
let win = BrowserWindow.getFocusedWindow();
win.webContents.downloadURL(args.download)
//监听下载动作
win.webContents.session.on('will-download', (event, item, webContents) => {
/*
args.localPath:下载的资源连接 url
args.saveName:下载名字
*/
var zipFile = path.join(args.localPath, args.saveName)
// console.log(zipFile)
item.setSavePath(zipFile)
//监听下载过程
item.on('updated', (event, state) => {
//下载意外中断,可以恢复
if (state === 'interrupted') {
console.log('Download is interrupted but can be resumed')
} else if (state === 'progressing') {
//下载正在进行中
if (item.isPaused()) {
//下载暂停中
console.log('Download is paused')
} else {
//下载进行中 下载进度
console.log(`complete:${(item.getReceivedBytes() / item.getTotalBytes() * 100).toFixed(2)}%`)
//任务栏进度条 -1不展示
win.setProgressBar(item.getReceivedBytes() / item.getTotalBytes())
}
}
})
//监听完成
item.once('done', (event, state) => {
console.log('下载完成下载完成')
//读取一个Buffer
var buffer = fs.readFileSync(zipFile);
var fsHash = crypto.createHash('sha1');
fsHash.update(buffer);
var sha1 = fsHash.digest('hex');
console.log("文件的MD5是:%s", args.hash + ',' + sha1);
if (sha1 == args.hash) {
shell.openPath(zipFile)
}
// console.log(getFileSha1(zipFile))
// win.webContents.send('onFileSHA1', zipFile)
// shell.openPath(zipFile)
})
})
TypeScript 中?: 、??、?. 、!. 、&&= 、??= 、||= 含义解析
- ?: 是指可选参数,可以理解为参数自动加上undefined
- ?? ?? 和 || 的意思有点相似,但是又有点区别,??相较||比较严谨, 当值等于0的时候||就把他给排除了,但是?? 不会.
- ?. ?.的意思基本和 && 是一样的
- !. !.的意思是断言,告诉ts你这个对象里一定有某个值
- &&= 如果第一个表达式的值为 true,则执行第二个表达式,并将结果赋值给第一个表达式;如果第一个表达式的值为 false,则不执行第二个表达式,第一个表达式的值不变。
- ||= 如果左侧的操作数(表达式)为真(即非零、非空或非undefined),则返回左侧的操作数(表达式);否则,返回右侧的操作数(表达式)。
- ??= 如果左侧的操作数(表达式)是 null 或 undefined,那么返回右侧的操作数(表达式);否则,将右侧的操作数(表达式)赋值给左侧的操作数(表达式)。
看下面的例子
a = a && b
a = a || b
a = a ?? b
//等效于下面的方法
a &&= b;
a ||= b;
a ??= b;
input框中输入的值,需要导出pdf或者打印出来为空的问题
原理:利用 setAttribute()方法添加value属性,并为其赋值
let allInput = document.querySelectorAll('input') //先获取所有的input 的dom对象
allInput.forEach((item, index) => {
if (index != 0) {
//利用 setAttribute()方法天骄value属性,并为其赋值 allInput[index].value:对应input中输入的值
allInput[index].setAttribute('value', allInput[index].value)
}
})
js写货币格式(每三位一个逗号分隔)
注意:每个组件库中都有:Statistic 统计数值,可以参考一下,直接应用
const convertNum = (val: number) => {
return val.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
};
大数值转换为 K,M,G,T或者KB,MB,GB,TB
// 转换文件大小格式
export const convertSizeFormat = (size: number): string => {
if (!size) return '0 Bytes' // 处理size为0的特殊情况
const unit = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
let index = Math.floor(Math.log(size) / Math.log(1024))
let newSize = size / Math.pow(1024, index)
// 保留的小数位数
return newSize.toFixed(2) + ' ' + unit[index]
}
export default function convertNumber(number: any) {
if (number < 10 ** 3) {
return number;
}
if (10 ** 3 <= number && number < 10 ** 6) {
return `${(number / 10 ** 3).toFixed(1)} K`;
}
if (10 ** 6 <= number && number < 10 ** 9) {
return `${(number / 10 ** 6).toFixed(1)} M`;
}
if (10 ** 9 <= number && number < 10 ** 12) {
return `${(number / 10 ** 9).toFixed(1)} G`;
}
return `${(number / 10 ** 12).toFixed(1)} T`;
}
export function convertBase(number: any) {
if (number < 10 ** 3) {
return number;
}
if (10 ** 3 <= number && number < 10 ** 6) {
return `${(number / 10 ** 3).toFixed(1)} Kb`;
}
if (10 ** 6 <= number && number < 10 ** 9) {
return `${(number / 10 ** 6).toFixed(1)} Mb`;
}
if (10 ** 9 <= number && number < 10 ** 12) {
return `${(number / 10 ** 9).toFixed(1)} Gb`;
}
return `${(number / 10 ** 12).toFixed(1)} Tb`;
}
数组包对象,同时对多个属性进行筛选(搜索查询)
html页面的input
<div class="search">
<!-- orderName geneName similar length evalue score-->
<a-space>
<a-input v-model:value="tableConfig.orderName" placeholder="请输入序列名称" @keyup.enter.native="search" allowClear />
<a-input v-model:value="tableConfig.geneName" placeholder="请输入参考基因组名称" @keyup.enter.native="search" allowClear />
<a-input v-model:value="tableConfig.similar" placeholder="请输入相似性" @keyup.enter.native="search" allowClear />
<a-button type="primary" @click="search">查询</a-button>
<a-button type="default" @click="reset">重置</a-button>
</a-space>
</div>
这里是需要筛选的数据 方法在下面写
let tableConfig.SearchtotalData = [
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.489",
"id": "1",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.857",
"id": "2",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"id": "3",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.386",
"id": "4",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "97.522",
"id": "5",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.889",
"id": "6",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "99.048",
"id": "7",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.706",
"id": "8",
},
{
"序列名称": "contig_1",
"参考基因组名称": "AJ938182",
"相似性(%)": "98.085",
"id": "9",
}
]
筛选的方法
const search = () => {
if (!tableConfig.orderName && !tableConfig.geneName && !tableConfig.similar && !tableConfig.length && !tableConfig.evalue && !tableConfig.score) {
message.info('请输入筛选条件!')
} else {
let tempArray = [];
tableConfig.SearchtotalData.forEach(item => {
let flag = false;
let flag2 = false;
let flag3 = false;
if (tableConfig.orderName) {
if (item.序列名称.includes(tableConfig.orderName)) {
flag = true;
} else {
flag = false;
}
} else {
flag = true;
}
if (tableConfig.geneName) {
if (flag && item.参考基因组名称.includes(tableConfig.geneName)) {
flag2 = true;
} else {
flag2 = false;
}
} else {
flag2 = true;
}
let isSimilar = parseFloat(item['相似性(%)']) > parseFloat(tableConfig.similar)
if (tableConfig.similar) {
if (flag && flag2 && isSimilar) {
flag3 = true;
} else {
flag3 = false;
}
} else {
flag3 = true;
}
if (flag && flag2 && flag3 ) {
tempArray.push(item);
}
tableConfig.totalData = tempArray;
tableConfig.totalNumber = tableConfig.totalData.length
})
}
}
字符串中混合数字,按照部分数字排序
/**
* string和number混合,的字符串,按照部分数字排序 如:
* var arr = ['sample1', 'sample10', 'sample2', 'sample12', 'sample5'];
* 输出: ['sample1', 'sample2', 'sample5', 'sample10', 'sample12']
* @param val1
* @param val2
* @returns
*/
export const stringNumberMixSort = (a: string | number, b: string | number) =>
a - b || a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
export const compareSort = (a: string | number, b: string | number) => {
if (typeof a === 'number') {
return a - b;
} else {
return a?.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
}
};
数组包对象,按照对象的某一属性去重
推荐方法一
/**
* 根据唯一值对数组进行去重
* @param list 要去去重的数组
* @param key 按照对象某一属性(key)去重
*/
const deWeightThree = (list: Array<any>, key: string) => [
...list.reduce((prev, cur) => prev.set(cur[key], cur), new Map()).values(),
];
console.log(deWeightThree(tempArr, 'name'));
方法二:
//arr: 要去重的数组, attribute:按照对象的属性去重
let deWeightThree = (arr: Array<any>, attribute: string) => {
let map = new Map();
for (let item of arr) {
if (!map.has(item[attribute])) {
map.set(item[attribute], item);
}
}
return [...map.values()];
}
//得到的新数组
tempArray2 = deWeightThree(tempArray, 'sample');
数组包对象,以对象的某一个属性排序
首相要了解数组的sort方法
对象的属性是 number类型
let arr = [{name: "zlw", age: 24}, {name: "wlz", age: 25}];
//降序
let ObjDescend= function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}
//如果想以 age,进行排序:arr.sort(ObjDescend('age'))
//或者直接用sort方法:
arr.sort(function(a, b) {
return a.age - b.age;//升序
//return b.age - a.age;//降序
});
如果 age 的值为字符串 (age:“24”),还用上面的方法则会按照ASCII排序(按照字符串排序)
对象的属性是字符串的类型
let arr = [{name: "zlw", age: 24}, {name: "wlz", age: 25}];
//升序
let ObjAscend= function (prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
val1 = Number(val1);
val2 = Number(val2);
}
if (val1 > val2) {
return -1;
} else if (val1 < val2) {
return 1;
} else {
return 0;
}
}
}
如果想以 age,进行排序:arr.sort(ObjAscend('age'))
getCookie、setCookie、removeCookie
function getCookie(key){
var arr1 = document.cookie.split('; ');//这里是分号+空格分隔
for( var i = 0 , len = arr1.length ; i < len ; i++ ){
var arr2 = arr1[i].split('=');
if( arr2[0] == key ){
return decodeURI(arr2[1]);
}
}
}
getCookie('age');//21
function setCookie(key,value,time){
var oDate = new Date();
oDate.setDate( oDate.getDate() + time );
document.cookie = key +'=' + value + ';expires=' + oDate.toGMTString();
}
setCookie('sex','男',10);//sex='男'存cookie十天
//封装一个删除cookie的方法,就是将cookie的有效时间更改为昨天而已。
function removeCookie(key){
setCookie(key,'',-1);//调用上面的setCookie方法
}
removeCookie('sex');
防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
// 防抖:n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
function _debounce(func,delay) {
let timeout;
var delay = delay || 200;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, delay)
if (callNow) func.apply(context, args)
}
}
//防抖
let timer_debounce: any;
export const debounce = (func: Function, wait?: number) => {
wait = wait || 500;
clearTimeout(timer_debounce);
timer_debounce = setTimeout(() => {
func.apply(this);
}, wait);
};
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
// 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
function _throttle(fn, interval) {
var last;
var timer;
var interval = interval || 200;
return function () {
var th = this;
var args = arguments;
var now = +new Date();
if (last && now - last < interval) {
clearTimeout(timer);
timer = setTimeout(function () {
last = now;
fn.apply(th, args);
}, interval);
} else {
last = now;
fn.apply(th, args);
}
}
}
let timer_throttle: any;
export const throttle = (func: Function, wait?: number) => {
wait = wait || 500;
if (!timer_throttle) {
timer_throttle = setTimeout(() => {
func.apply(this);
timer_throttle = null;
}, wait);
}
};
不想自己写,也可以用 lodash 库去实现
_.throttle(func, [wait=0], [options=])//节流
//说明:
//func (Function): 要节流的函数。
//[wait=0] (number): 需要节流的毫秒。
//[options=] (Object): 选项对象。
//[options.leading=true] (boolean): 指定调用在节流开始前。
//[options.trailing=true] (boolean): 指定调用在节流结束后。
_.debounce(func, [wait=0], [options=])//防抖
//说明:
//func (Function): 要防抖动的函数。
//[wait=0] (number): 需要延迟的毫秒数。
//[options=] (Object): 选项对象。
//[options.leading=false] (boolean): 指定在延迟开始前调用。
//[options.maxWait] (number): 设置 func 允许被延迟的最大值。
//[options.trailing=true] (boolean): 指定在延迟结束后调用。
//记得安装
//引入
import _ from "lodash";
//使用
_.debounce(() => {
console.log("防抖");
}, 500);
_.throttle(() => {
console.log("节流");
}, 500);
将文件类型转换成字符串数组
// 将文件类型转换成字符串数组
export const filesToStringArrary = function (list: any) {
if (typeof list === 'string') return list;
if (list === null) return [];
const _list: { fileName: any; fileType: any; fileId: any }[] = [];
const _ids_list: any[] = [];
list.length > 0 &&
list.map(function (
item: { response: { data: any[] }; name: any; type: any; contentType: any; uid: any },
) {
if (item.response) {
_list.push({
fileName: item.name,
fileType: item.type,
fileId: item.response.data[0],
});
_ids_list.push(item.response.data[0]);
} else {
_list.push({
fileName: item.name,
fileType: item.contentType,
fileId: item.uid,
});
_ids_list.push(item.uid);
}
});
return { _list, _ids_list };
};
将对象转化为URL的查询字符串(对象转化为地址栏问号传参)
常用语get请求传参,将对象格式转换为?+&的情况
/**
* 将对象转化为URL的查询字符串
* @param q 查询对象
* @returns URL的查询字符串
*/
export const formatQuery = (q: any) => {
let query = '';
Object.keys(q).forEach((key) => {
if (q[key] !== '' && q[key] !== undefined) {
query += `${key}=${q[key]}&`;
}
});
return query.substring(0, query.length - 1);
};
vue3中解构地址栏参数 (比下面getUrlParams好用)
import { useRouter } from 'vue-router';
const router = useRouter();
const query = JSON.parse(JSON.stringify(router.currentRoute.value.query));
const { taskId, barcodeId, sampleId, generation, barcodeName } = query; //{}里面直接结构参数
截取地址栏参数
// 获取数组的params字段默认用来获取rbacToken;
export const getUrlParams = function (name: string) {
const url2 = window.location.href;
const temp2 = url2.split('?')[1];
const pram2 = new URLSearchParams(`?${temp2}`);
let data = pram2.get(name);
if (!data) return '';
if (data.indexOf('#/') >= 0) {
data = data.split('#/')[0];
}
return data;
};
如果需要传值过多,推荐使用下列方法,类似于vue3中的vue-router
//将地址栏参数返回一个对象直接结构出来就好了,类似于上面的vue3获取地址栏参数
export const getUrlParamsObj = function () {
var s = location.href.indexOf("?");
var t = location.href.substring(s + 1);
let arr = t.split('\&')
let paramsObj: any = {}
arr.forEach((item: string, index: number) => paramsObj[item.split('=')[0]] = item.split('=')[1])
return paramsObj;
};
//使用方法
//let { taskId ,barcodeId } = getUrlParamsObj()
//console.log(taskId ,barcodeId);
dom节点删除 删除子节点 removeChild
在同一个div中话echart是,需要清除画布,重回绘制,否则会重叠,这里我用了删除dom在添加一个div进去
/**
* 要删除的父div id
* 要删除的div id
*/
resetDom('mapParent', 'map')
const resetDom = (parentId: string, childId: string) => {
let parentsDom = document.getElementById(parentId);
// clear
let childDom = document.getElementById(childId);
if (childDom) {
parentsDom.removeChild(childDom)
}
// create
var littleBox = document.createElement('div')
littleBox.style.width = "100%";
littleBox.style.height = "100%";
littleBox.setAttribute("id", childId)
parentsDom.appendChild(littleBox)
}
如何隐藏滚动条 滚动条的样式修改
overflow: auto;
overflow-x: hidden;
overflow-y: scroll;
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
/* 设置滚动条的样式 */
&::-webkit-scrollbar {
display: none;
//width: 12px;
//height:12px;
}
/* 滚动槽 */
&::-webkit-scrollbar-track {
background-color: #fdffeb;
border-radius: 10px;
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(173, 247, 89, 0.6);
}
&::-webkit-scrollbar-thumb:window-inactive {
background: rgba(255, 0, 0, 0.4);
}
获取系统时间日期, 返回:日期,星期
/** 获取系统时间日期, 返回:
* @returns dateNum: 日期, dayStr: 星期
*/
const getNowDateStr = () => {
const nowDate = new Date();
const dayStrs = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六",];
const dateNum = nowDate.getDate();
const dayStr = dayStrs[nowDate.getDay()];
return {
dateNum,
dayStr
}
}
将rangepick 时间选择的数据进行过滤
//将rangepick 时间选择的数据进行过滤
export const filterKeys = function (data) {
const filterData = {};
for (let key in data) {
if (key.indexOf('-') >= 0) {
key.split('-').map(function (item, idx) {
if (!data[key]) {
filterData[item] = undefined;
} else {
if (typeof data[key][idx] === 'object') {
//目前只针对时间做了优化 未出现有其他是对象的值
filterData[item] = data[key][idx].format('YYYY-MM-DD 00:00:00');
} else {
filterData[item] = data[key][idx];
}
}
});
} else {
filterData[key] = data[key];
}
}
return filterData;
};
字符串超出长度显示省略号 css方法
word-break: break-all; 只对英文起作用,以字母作为换行依据。
word-wrap: break-word; 只对英文起作用,以单词作为换行依据。
white-space: pre-wrap; 只对中文起作用,强制换行。
一行显示
// 这样只能显示一行,多出的省略号显示
white-space: nowrap;/* 强制在一行显示 */
text-overflow: ellipsis; /* 超过最小宽度后,超过部分用省略号显示 */
overflow: hidden; /* 超过最小宽度后,自动隐藏 */
多行显示
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2; //这里控制行数
-webkit-box-orient: vertical;
字符串超出长度显示省略号 js截取方法
// 字符串超出长度显示省略号
const lineOmit = function (str, breakLength) {
if (!breakLength) breakLength = 3;
if (str.length <= breakLength) return str;
return str.slice(0, breakLength) + '...';
};
input 取消默认提示框
autocomplete="off" // 添加这个属性
<input autocomplete="off" /> //这样获取焦点的时候就没有提示框了
利用@media与@media screen进行响应式布局
<style>
//一种是直接在link中判断设备的尺寸,然后引用不同的css文件:
<link rel="stylesheet" type="text/css" href="styleA.css" media="screen and (min-width: 400px)">
//另一种方式,即是直接写在 style 标签里:
@media screen and (max-width: 1919px) {
@import './styles/small.less';
}
@media screen and (min-width: 1920px) {
@import './styles/big.less';
}
// 参考下面的例子:
//我们用min-width时,小的放上面大的在下面,同理如果是用max-width那么就是大的在上面,小的在下面
@media (min-width: 1200){ //>=1200的设备 }
@media (min-width: 992px){ //>=992的设备 }
@media (min-width: 768px){ //>=768的设备 }
//注意下顺序,如果你把@media (min-width: 768px)写在了上面那么就是错误的!!!
@media (max-width: 1199){ //<=1199的设备 }
@media (max-width: 991px){ //<=991的设备 }
@media (max-width: 767px){ //<=768的设备 }
//混合使用
@media screen and (min-width:1200px){}
@media screen and (min-width: 960px) and (max-width: 1199px) { }
@media screen and (min-width: 768px) and (max-width: 959px) { }
@media only screen and (min-width: 480px) and (max-width: 767px){ }
@media only screen and (max-width: 479px) { }
</style>
表格时间格式化
/**
* 表格时间格式化
*/
export function formatDate(cellValue) {
if (cellValue == null || cellValue == "") return "";
var date = new Date(cellValue)
var year = date.getFullYear()
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
日期格式化
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
获取设备信息方法
//获取设备信息方法
const getClientInfo = () => {
var cid, getClientInfo;
return new Promise(function (resolve) {
try {
if (window && window.plus) {
} else {
if (plus) {
//#ifdef APP-PLUS
getClientInfo = plus.push.getClientInfo();
cid = getClientInfo.clientid;
console.log(cid);
console.log(getClientInfo);
resolve({
cid,
getClientInfo
})
//#endif
} else {
plus.globalEvent.addEventListener('plusready', function () {
if (cid && cid != 'undefind' && cid != '' && cid != 'null') {
return;
}
//#ifdef APP-PLUS
getClientInfo = plus.push.getClientInfo();
//#endif
cid = getClientInfo.clientid;
console.log(cid);
console.log(getClientInfo);
resolve({
cid,
getClientInfo
})
});
}
}
} catch (e) {
//#ifdef H5
resolve({})
//#endif
//TODO handle the exception
}
})
}
封装公共路径跳转的方法
//封装公共路径跳转的方法
const navTo = function (url, params) {
if (!isNaN(parseInt(url))) {
uni.navigateBack({
delta: Number(url)
})
return;
}
let _params = "";
params ?
Object.keys(params).map(function (key, idx) {
_params = _params + `${idx == 0 ? '?' : '&'}${key}=${params[key]}`;
}) : null;
uni.navigateTo({
url: url + _params,
})
}
//提示文字+路径跳转方法
//如果没有传navTo对象 则不进行跳转 只进行提示
const showToastOrNavTo = function (conf) {
const { title, duration, icon, image, navTo: _navTo } = conf;
uni.showToast({
//icon 类型 success error loading none
//none 不显示图标,此时 title 文本在小程序最多可显示两行,App仅支持单行显示。
icon: icon ? icon : 'success',
//自定义图标路径
image: image ? image : null,
mask: true,
title: title || "操作成功",
duration: Number(duration) || 1500,
complete: function () {
_navTo ?
setTimeout(function () {
navTo(_navTo.url, _navTo.params)
}, duration || 1500) : null
}
});
}
扫码的方法 h5 不兼容
//扫码的方法 h5 不兼容
const scanCode = (conf) => {
const { onlyFromCamera, scanType } = conf || {};
return new Promise(function (resolve) {
uni.scanCode({
//是否只能从相机扫码,不允许从相册选择图片
onlyFromCamera: onlyFromCamera || true,
//扫码类型,参数类型是数组,二维码是'qrCode',一维码是'barCode',DataMatrix是‘datamatrix’,pdf417是‘pdf417’。
scanType: scanType || ['qrCode'],
success: function (...data) {
resolve(...data)
},
fail: function (err) {
if (err.errMsg.includes("cancel")) {
return;
} else {
showToastOrNavTo({
icon: "error",
title: "扫码失败",
})
}
},
complete: function () {
}
})
})
}