3、JavaScript
3-1 判断对象是否为空
js
if (Object.keys(obj).length === 0) {
console.log('空对象');
} else {
console.log('非空对象');
}if (Object.keys(obj).length === 0) {
console.log('空对象');
} else {
console.log('非空对象');
}3-2 金额,三位就以逗号分割的形式方法,小数两位
javascript
// 第一种方法
toThousands (num) {
const result = [];
let counter = 0;
const str = (num || 0).toString().split('.')[0];
// 存在小数
const str1 = (num || 0).toString().split('.')[1];
let flag = false;
if ((num || 0).toString().includes('.')) {
// 存在小数
flag = true;
}
num = str.split('');
for (var i = num.length - 1; i >= 0; i--) {
counter++;
result.unshift(num[i]);
if (!(counter % 3) && i !== 0) { result.unshift(','); }
}
if (flag) {
// 存在小数
return result.join('') + '.' + str1;
} else {
return result.join('');
}
}
// 第二种方法
export const formMoney = (n) => {
const money = n.toString();
return money.replace(new RegExp(`(?!^)(?=(\\d{3})+${money.includes('.') ? '\\.' : '$'})`, 'g'), ',');
};
// 第三种方法
export default formatNumber(value) {
value += '';
const list = value.split('.');
const prefix = list[0].charAt(0) === '-' ? '-' : '';
let num = prefix ? list[0].slice(1) : list[0];
let result = '';
while (num.length > 3) {
result = `,${num.slice(-3)}${result}`;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return `${prefix}${result}${list[1] ? `.${list[1]}` : ''}`;
}// 第一种方法
toThousands (num) {
const result = [];
let counter = 0;
const str = (num || 0).toString().split('.')[0];
// 存在小数
const str1 = (num || 0).toString().split('.')[1];
let flag = false;
if ((num || 0).toString().includes('.')) {
// 存在小数
flag = true;
}
num = str.split('');
for (var i = num.length - 1; i >= 0; i--) {
counter++;
result.unshift(num[i]);
if (!(counter % 3) && i !== 0) { result.unshift(','); }
}
if (flag) {
// 存在小数
return result.join('') + '.' + str1;
} else {
return result.join('');
}
}
// 第二种方法
export const formMoney = (n) => {
const money = n.toString();
return money.replace(new RegExp(`(?!^)(?=(\\d{3})+${money.includes('.') ? '\\.' : '$'})`, 'g'), ',');
};
// 第三种方法
export default formatNumber(value) {
value += '';
const list = value.split('.');
const prefix = list[0].charAt(0) === '-' ? '-' : '';
let num = prefix ? list[0].slice(1) : list[0];
let result = '';
while (num.length > 3) {
result = `,${num.slice(-3)}${result}`;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return `${prefix}${result}${list[1] ? `.${list[1]}` : ''}`;
}3-3 数组对象去重
js
export function uniqueArray (arr, key) {
const obj = {};
arr = arr.reduce(function (item, next) {
// eslint-disable-next-line no-unused-expressions
obj[next[key]] ? '' : obj[next[key]] = item.push(next);
return item;
}, []);
return arr;
}export function uniqueArray (arr, key) {
const obj = {};
arr = arr.reduce(function (item, next) {
// eslint-disable-next-line no-unused-expressions
obj[next[key]] ? '' : obj[next[key]] = item.push(next);
return item;
}, []);
return arr;
}3-4 动态配置WebSocket
js
// 初始化连接
function initWebSocket () {
if (typeof (WebSocket) === 'undefined') {
this.$message.error('您的浏览器不支持WebSocket!');
} else {
const userId = '';
const url = process.env. VUE_APP_SOCKET_URL;
const socketUrl = generateEndpoint(url);
// 实例化socket
this.socket = new WebSocket(`${socketUrl}/xx`);
// 监听socket连接
this.socket.onopen = () => {
console.log('websocket连接成功');
};
// 监听socket错误信息
this.socket.onerror = () => {
console.log('websocket连接错误');
};
// 监听socket断开
this.socket.onclose = () => {
console.log('websocket连接断开');
initWebSocket();
};
// 监听socket消息
this.socket.onmessage = ({ data }) => {
try {
// 这里写逻辑
} catch (e) {
console.log(e);
}
};
}
}
export function generateEndpoint (socketURI) {
if (socketURI.includes('ws')) {
return socketURI;
} else {
return `${location.protocol === 'https' ? 'wss' : 'ws'}://${location.host}${socketURI}`;
}
}// 初始化连接
function initWebSocket () {
if (typeof (WebSocket) === 'undefined') {
this.$message.error('您的浏览器不支持WebSocket!');
} else {
const userId = '';
const url = process.env. VUE_APP_SOCKET_URL;
const socketUrl = generateEndpoint(url);
// 实例化socket
this.socket = new WebSocket(`${socketUrl}/xx`);
// 监听socket连接
this.socket.onopen = () => {
console.log('websocket连接成功');
};
// 监听socket错误信息
this.socket.onerror = () => {
console.log('websocket连接错误');
};
// 监听socket断开
this.socket.onclose = () => {
console.log('websocket连接断开');
initWebSocket();
};
// 监听socket消息
this.socket.onmessage = ({ data }) => {
try {
// 这里写逻辑
} catch (e) {
console.log(e);
}
};
}
}
export function generateEndpoint (socketURI) {
if (socketURI.includes('ws')) {
return socketURI;
} else {
return `${location.protocol === 'https' ? 'wss' : 'ws'}://${location.host}${socketURI}`;
}
}3-5 脱敏处理
vue
computed: {
encryFn () {
return (value, startLen, endLen) => {
if (value && value.length) {
if (value.length > 2) {
const prefix = value.substr(0, startLen);
const suffix = value.substr(-endLen, endLen);
const len = value.length - startLen- endLen;
let str= '';
for (let i = 0; i < len; i++) {
str+= '*';
}
return `${prefix}${str}${suffix}`;
} else {
const prefix = value.substr(0, 1);
return `${prefix}*`;
}
} else {
return value;
}
};
},
}computed: {
encryFn () {
return (value, startLen, endLen) => {
if (value && value.length) {
if (value.length > 2) {
const prefix = value.substr(0, startLen);
const suffix = value.substr(-endLen, endLen);
const len = value.length - startLen- endLen;
let str= '';
for (let i = 0; i < len; i++) {
str+= '*';
}
return `${prefix}${str}${suffix}`;
} else {
const prefix = value.substr(0, 1);
return `${prefix}*`;
}
} else {
return value;
}
};
},
}3-6 拷贝
js
JSON.parse(JSON.stringify(Value))JSON.parse(JSON.stringify(Value))3-7 判断对象是否为空
js
if (Object.keys(obj).length === 0) {
console.log('空对象');
} else {
console.log('非空对象');
}if (Object.keys(obj).length === 0) {
console.log('空对象');
} else {
console.log('非空对象');
}3-8 判断浏览器类型
js
export function browserType () {
var userAgent = navigator.userAgent; // 取得浏览器的userAgent字符串
// 判断是否Opera浏览器
if (userAgent.indexOf('Opera') > -1) {
return 'isOpera';
}
// 判断是否Firefox浏览器
if (userAgent.indexOf('Firefox') > -1) {
return 'Firefox';
}
// 判断是否Chrome浏览器
if (userAgent.indexOf('Chrome') > -1) {
return 'Chrome';
}
// 判断是否Safari浏览器
if (userAgent.indexOf('Safari') > -1) {
return 'Safari';
}
// 判断是否IE浏览器
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
return 'isIE';
}
}export function browserType () {
var userAgent = navigator.userAgent; // 取得浏览器的userAgent字符串
// 判断是否Opera浏览器
if (userAgent.indexOf('Opera') > -1) {
return 'isOpera';
}
// 判断是否Firefox浏览器
if (userAgent.indexOf('Firefox') > -1) {
return 'Firefox';
}
// 判断是否Chrome浏览器
if (userAgent.indexOf('Chrome') > -1) {
return 'Chrome';
}
// 判断是否Safari浏览器
if (userAgent.indexOf('Safari') > -1) {
return 'Safari';
}
// 判断是否IE浏览器
if (!!window.ActiveXObject || 'ActiveXObject' in window) {
return 'isIE';
}
}3-9 对象深度合并
js
// 参考:http://www.seozhijia.net/javascript/238.html
/**
*判断对象是否是一个纯粹的对象
*/
function isPlainObject (obj) {
return typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Object]';
}
/**
*深度合并多个对象的方法
*/
export function deepAssign () {
const len = arguments.length;
let target = arguments[0];
if (!isPlainObject(target)) {
target = {};
}
for (let i = 1; i < len; i++) {
const source = arguments[i];
if (isPlainObject(source)) {
for (const s in source) {
if (s === '__proto__' || target === source[s]) {
continue;
}
if (isPlainObject(source[s])) {
target[s] = deepAssign(target[s], source[s]);
} else {
target[s] = source[s];
}
}
}
}
return target;
}
// 自定义方法: const setting = deepAssign(this.defaultSetting, this.setting)
// 使用Jquery方法
// const setting = $.extend(true, this.defaultSetting, this.setting);// 参考:http://www.seozhijia.net/javascript/238.html
/**
*判断对象是否是一个纯粹的对象
*/
function isPlainObject (obj) {
return typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Object]';
}
/**
*深度合并多个对象的方法
*/
export function deepAssign () {
const len = arguments.length;
let target = arguments[0];
if (!isPlainObject(target)) {
target = {};
}
for (let i = 1; i < len; i++) {
const source = arguments[i];
if (isPlainObject(source)) {
for (const s in source) {
if (s === '__proto__' || target === source[s]) {
continue;
}
if (isPlainObject(source[s])) {
target[s] = deepAssign(target[s], source[s]);
} else {
target[s] = source[s];
}
}
}
}
return target;
}
// 自定义方法: const setting = deepAssign(this.defaultSetting, this.setting)
// 使用Jquery方法
// const setting = $.extend(true, this.defaultSetting, this.setting);3-10 两个数组查找相同项
js
const columns = [
{
"prop": "name",
"label": "姓名",
"minWidth": "150px"
},
{
"prop": "region",
"label": "区域",
"minWidth": "250px",
"slot": true,
"slotHeader": "region"
},
{
"prop": "province",
"label": "省份",
"slot": true,
"slotColumn": "province",
"minWidth": "250px"
},
{
"prop": "city",
"label": "城市",
"minWidth": "350px"
},
{
"prop": "county",
"label": "市县",
"minWidth": "250px"
},
{
"prop": "zip",
"label": "邮政编码",
"minWidth": "150px"
},
{
"prop": "creatDate",
"label": "创建日期",
"minWidth": "150px"
}
];
const list =[
"name",
"region",
"province",
"city",
"county",
"zip"
]
function getSame(columns, filterCheckList) {
const list = JSON.parse(JSON.stringify(columns));
return list.filter(item => {
return filterCheckList.some(val => item.prop === val);
});
}
console.log(getSame(columns,list))
/* 结果如下
[
{
"prop": "name",
"label": "姓名",
"minWidth": "150px"
},
{
"prop": "region",
"label": "区域",
"minWidth": "250px",
"slot": true,
"slotHeader": "region"
},
{
"prop": "province",
"label": "省份",
"slot": true,
"slotColumn": "province",
"minWidth": "250px"
},
{
"prop": "city",
"label": "城市",
"minWidth": "350px"
},
{
"prop": "county",
"label": "市县",
"minWidth": "250px"
},
{
"prop": "zip",
"label": "邮政编码",
"minWidth": "150px"
}
]
*/const columns = [
{
"prop": "name",
"label": "姓名",
"minWidth": "150px"
},
{
"prop": "region",
"label": "区域",
"minWidth": "250px",
"slot": true,
"slotHeader": "region"
},
{
"prop": "province",
"label": "省份",
"slot": true,
"slotColumn": "province",
"minWidth": "250px"
},
{
"prop": "city",
"label": "城市",
"minWidth": "350px"
},
{
"prop": "county",
"label": "市县",
"minWidth": "250px"
},
{
"prop": "zip",
"label": "邮政编码",
"minWidth": "150px"
},
{
"prop": "creatDate",
"label": "创建日期",
"minWidth": "150px"
}
];
const list =[
"name",
"region",
"province",
"city",
"county",
"zip"
]
function getSame(columns, filterCheckList) {
const list = JSON.parse(JSON.stringify(columns));
return list.filter(item => {
return filterCheckList.some(val => item.prop === val);
});
}
console.log(getSame(columns,list))
/* 结果如下
[
{
"prop": "name",
"label": "姓名",
"minWidth": "150px"
},
{
"prop": "region",
"label": "区域",
"minWidth": "250px",
"slot": true,
"slotHeader": "region"
},
{
"prop": "province",
"label": "省份",
"slot": true,
"slotColumn": "province",
"minWidth": "250px"
},
{
"prop": "city",
"label": "城市",
"minWidth": "350px"
},
{
"prop": "county",
"label": "市县",
"minWidth": "250px"
},
{
"prop": "zip",
"label": "邮政编码",
"minWidth": "150px"
}
]
*/3-11 echarts 地图名称位置更改
添加cp数组字段,值为经纬度坐标
json
"properties": {
"adcode": 620000,
"name": "甘肃省",
"center": [
103.823557,
36.058039
],
"cp": [
103.830175,
36.063365
],
"childrenNum": 14,
"level": "province",
"parent": {
"adcode": 100000
},
"subFeatureIndex": 27,
"acroutes": [
100000
]
},"properties": {
"adcode": 620000,
"name": "甘肃省",
"center": [
103.823557,
36.058039
],
"cp": [
103.830175,
36.063365
],
"childrenNum": 14,
"level": "province",
"parent": {
"adcode": 100000
},
"subFeatureIndex": 27,
"acroutes": [
100000
]
},更改前

更改后

3-12 复制
js
function handleCopyResult () {
// const m3uOutput = document.getElementById('m3uOutput');
// m3uOutput.select();
// document.execCommand('copy');
// alert('内容已复制到剪贴板!');
// 下面为新语法
navigator.clipboard.writeText(this.vaule).then(() => {
this.$message.success('复制成功');
});
}
// 复制高阶函数
import { Message } from 'element-ui';
export const copyText = (function () {
if (navigator.clipboard) {
return (text) => navigator.clipboard.writeText(text).then(() => {
Message({
message: '复制成功',
type: 'success',
duration: 3000
});
});
} else {
return (text) => {
const input = document.createElement('input');
input.setAttribute('value', text);
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
Message({
message: '复制成功',
type: 'success',
duration: 3000
});
};
}
})();function handleCopyResult () {
// const m3uOutput = document.getElementById('m3uOutput');
// m3uOutput.select();
// document.execCommand('copy');
// alert('内容已复制到剪贴板!');
// 下面为新语法
navigator.clipboard.writeText(this.vaule).then(() => {
this.$message.success('复制成功');
});
}
// 复制高阶函数
import { Message } from 'element-ui';
export const copyText = (function () {
if (navigator.clipboard) {
return (text) => navigator.clipboard.writeText(text).then(() => {
Message({
message: '复制成功',
type: 'success',
duration: 3000
});
});
} else {
return (text) => {
const input = document.createElement('input');
input.setAttribute('value', text);
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
Message({
message: '复制成功',
type: 'success',
duration: 3000
});
};
}
})();3-13 字符串分割
js
/**
* @Description
* @author qianyinggenian
* @date 2024/4/19
* @str str 字符串
* @separatorChar separatorChar 分割字符
* @isIncludes isIncludes 是否包含分割字符
* @isLastIndex isLastIndex 是否从最后出现的分割字符
*/
export function getStr (str, separatorChar, isIncludes = false, isLastIndex = false) {
let index = str.indexOf(separatorChar);
if (isLastIndex) {
index = str.lastIndexOf(separatorChar);
} else {
index = str.indexOf(separatorChar);
}
if (index !== -1) {
const endStr = isIncludes ? str.slice(index) : str.slice(index + 1);
const startStr = isIncludes ? str.slice(0, index + 1) : str.slice(0, index);
return {
endStr,
startStr
};
} else {
return '';
}
}/**
* @Description
* @author qianyinggenian
* @date 2024/4/19
* @str str 字符串
* @separatorChar separatorChar 分割字符
* @isIncludes isIncludes 是否包含分割字符
* @isLastIndex isLastIndex 是否从最后出现的分割字符
*/
export function getStr (str, separatorChar, isIncludes = false, isLastIndex = false) {
let index = str.indexOf(separatorChar);
if (isLastIndex) {
index = str.lastIndexOf(separatorChar);
} else {
index = str.indexOf(separatorChar);
}
if (index !== -1) {
const endStr = isIncludes ? str.slice(index) : str.slice(index + 1);
const startStr = isIncludes ? str.slice(0, index + 1) : str.slice(0, index);
return {
endStr,
startStr
};
} else {
return '';
}
}3-14 数组求和
js
/**
* @Description 数组求和
* @author qianyinggenian
* @date 2024/4/26
*/
export function getSum (list, field) {
if (list?.length > 0) {
if (field) {
return list.reduce((acc, item) => {
return getValue(acc, item[field]);
}, 0);
} else {
return list.reduce((acc, val) => {
return getValue(acc, val);
}, 0);
}
} else {
return 0;
}
function getValue (acc, value) {
const fieldType = typeof value;
if (['number', 'string'].includes(fieldType) && Number(value)) {
return acc + Number(value);
} else {
return acc;
}
}
}/**
* @Description 数组求和
* @author qianyinggenian
* @date 2024/4/26
*/
export function getSum (list, field) {
if (list?.length > 0) {
if (field) {
return list.reduce((acc, item) => {
return getValue(acc, item[field]);
}, 0);
} else {
return list.reduce((acc, val) => {
return getValue(acc, val);
}, 0);
}
} else {
return 0;
}
function getValue (acc, value) {
const fieldType = typeof value;
if (['number', 'string'].includes(fieldType) && Number(value)) {
return acc + Number(value);
} else {
return acc;
}
}
}3-15 标签页通信
js
/**
* @Description 跨标签页通信
* @author qianyinggenian
* @date 2024/4/29
*/
const channel = new BroadcastChannel('my-channel');
/**
* @Description 发送信息
* @author qianyinggenian
* @date 2024/4/29
*/
export function sendMsg (type, msg) {
channel.postMessage({ type, msg });
}
/**
* @Description 监听通信
* @author qianyinggenian
* @date 2024/4/29
*/
export function listenMsg (callback) {
const handler = (evt) => {
callback && callback(evt.data);
};
channel.addEventListener('message', handler);
return () => {
channel.removeEventListener('message', handler);
};
}/**
* @Description 跨标签页通信
* @author qianyinggenian
* @date 2024/4/29
*/
const channel = new BroadcastChannel('my-channel');
/**
* @Description 发送信息
* @author qianyinggenian
* @date 2024/4/29
*/
export function sendMsg (type, msg) {
channel.postMessage({ type, msg });
}
/**
* @Description 监听通信
* @author qianyinggenian
* @date 2024/4/29
*/
export function listenMsg (callback) {
const handler = (evt) => {
callback && callback(evt.data);
};
channel.addEventListener('message', handler);
return () => {
channel.removeEventListener('message', handler);
};
}3-15-1 发送页
vue
<template>
<div>
<el-button @click="handleSubmit">发送</el-button>
</div>
</template>
<script>
import { sendMsg } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
handleSubmit () {
this.num += 1;
sendMsg('add', this.num);
}
}
};
</script>
<style scoped lang="scss">
</style><template>
<div>
<el-button @click="handleSubmit">发送</el-button>
</div>
</template>
<script>
import { sendMsg } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
handleSubmit () {
this.num += 1;
sendMsg('add', this.num);
}
}
};
</script>
<style scoped lang="scss">
</style>3-15-2 监听页
vue
<template>
<div></div>
</template>
<script>
import { listenMsg } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
computed: {},
watch: {},
created () {},
mounted () {
this.removeListen = listenMsg((info) => {
console.log('info', info);
if (info.msg) {
this.count = info.msg;
}
});
},
destroyed () {
this.removeListen();
},
methods: {}
};
</script>
<style scoped lang="scss">
</style><template>
<div></div>
</template>
<script>
import { listenMsg } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
computed: {},
watch: {},
created () {},
mounted () {
this.removeListen = listenMsg((info) => {
console.log('info', info);
if (info.msg) {
this.count = info.msg;
}
});
},
destroyed () {
this.removeListen();
},
methods: {}
};
</script>
<style scoped lang="scss">
</style>3-16 防抖函数
js
/**
* @Description 防抖函数
* @author qianyinggenian
* @params method 函数
* @params delay 延时时间-毫秒
* @date 2024/12/30
*/
export function debounce (method, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
method(context, args);
}, delay);
};
}/**
* @Description 防抖函数
* @author qianyinggenian
* @params method 函数
* @params delay 延时时间-毫秒
* @date 2024/12/30
*/
export function debounce (method, delay) {
let timer = null;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
method(context, args);
}, delay);
};
}vue
<script>
import { debounce } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
props: {},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
handleClick: debounce((vm, args) => {
const [params, params2, params3] = args;
console.log('params', params);
console.log('params2', params2);
console.log('params3', params3);
console.log('vm', vm);
vm.fn();
}, 2000),
fn () {
console.log('防抖输出');
}
}
};
</script>
<template>
<div><button class="btn type-1" @click="handleClick('参数1','参数2',false)">按钮</button></div>
</template>
<style scoped lang="scss">
</style><script>
import { debounce } from '@/utils/util';
export default {
components: {},
data () {
return {};
},
props: {},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
handleClick: debounce((vm, args) => {
const [params, params2, params3] = args;
console.log('params', params);
console.log('params2', params2);
console.log('params3', params3);
console.log('vm', vm);
vm.fn();
}, 2000),
fn () {
console.log('防抖输出');
}
}
};
</script>
<template>
<div><button class="btn type-1" @click="handleClick('参数1','参数2',false)">按钮</button></div>
</template>
<style scoped lang="scss">
</style>3-17 截图
js
import html2canvas from 'html2canvas';
setTimeout(() => {
// container截图范围节点id
html2canvas(document.getElementById('container'), {
useCORS: true, // 允许跨域资源加载
logging: true, // 开启控制台日志(调试用)
scale: 1 // 提高清晰度(可调整)
}).then(canvas => {
const link = document.createElement('a');
link.download = 'map.jpg';
link.href = canvas.toDataURL();
link.click();
});
}, 500);import html2canvas from 'html2canvas';
setTimeout(() => {
// container截图范围节点id
html2canvas(document.getElementById('container'), {
useCORS: true, // 允许跨域资源加载
logging: true, // 开启控制台日志(调试用)
scale: 1 // 提高清晰度(可调整)
}).then(canvas => {
const link = document.createElement('a');
link.download = 'map.jpg';
link.href = canvas.toDataURL();
link.click();
});
}, 500);3-18 获取文件媒体类型
js
const mimeTypeMap = {
// --- 常用办公文档 (Office & PDF) ---
pdf: 'application/pdf',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
csv: 'text/csv',
rtf: 'application/rtf', // 富文本格式
// --- 图片格式 (Images) ---
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
gif: 'image/gif',
bmp: 'image/bmp',
svg: 'image/svg+xml',
webp: 'image/webp',
ico: 'image/x-icon',
tiff: 'image/tiff',
tif: 'image/tiff',
// --- 音视频格式 (Audio & Video) ---
mp3: 'audio/mpeg',
wav: 'audio/wav',
ogg: 'audio/ogg',
mp4: 'video/mp4',
avi: 'video/x-msvideo',
mov: 'video/quicktime',
wmv: 'video/x-ms-wmv',
flv: 'video/x-flv',
webm: 'video/webm',
m4a: 'audio/mp4',
// --- 压缩包 (Archives) ---
zip: 'application/zip',
rar: 'application/x-rar-compressed',
'7z': 'application/x-7z-compressed',
tar: 'application/x-tar',
gz: 'application/gzip',
// --- 文本与代码 (Text & Code) ---
txt: 'text/plain',
html: 'text/html',
htm: 'text/html',
css: 'text/css',
js: 'application/javascript', // 或 text/javascript
json: 'application/json',
xml: 'application/xml', // 或 text/xml
md: 'text/markdown',
java: 'text/x-java-source',
py: 'text/x-python',
c: 'text/x-c',
cpp: 'text/x-c++src',
h: 'text/x-c',
yaml: 'application/x-yaml',
yml: 'application/x-yaml',
// --- 字体 (Fonts) ---
ttf: 'font/ttf',
otf: 'font/otf',
woff: 'font/woff',
woff2: 'font/woff2',
eot: 'application/vnd.ms-fontobject',
// --- 其他/特殊格式 ---
apk: 'application/vnd.android.package-archive',
exe: 'application/x-msdownload',
msi: 'application/x-msdownload',
dwg: 'application/acad', // CAD文件,有时也用 application/x-autocad
psd: 'image/vnd.adobe.photoshop',
ai: 'application/postscript',
eps: 'application/postscript',
jsonld: 'application/ld+json',
mjs: 'text/javascript',
// --- 默认兜底 ---
default: 'application/octet-stream'
};
// 辅助函数:根据后缀获取类型
export function getMimeType (suffix) {
const key = suffix.toLowerCase();
return mimeTypeMap[key] || mimeTypeMap.default;
}const mimeTypeMap = {
// --- 常用办公文档 (Office & PDF) ---
pdf: 'application/pdf',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
csv: 'text/csv',
rtf: 'application/rtf', // 富文本格式
// --- 图片格式 (Images) ---
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
png: 'image/png',
gif: 'image/gif',
bmp: 'image/bmp',
svg: 'image/svg+xml',
webp: 'image/webp',
ico: 'image/x-icon',
tiff: 'image/tiff',
tif: 'image/tiff',
// --- 音视频格式 (Audio & Video) ---
mp3: 'audio/mpeg',
wav: 'audio/wav',
ogg: 'audio/ogg',
mp4: 'video/mp4',
avi: 'video/x-msvideo',
mov: 'video/quicktime',
wmv: 'video/x-ms-wmv',
flv: 'video/x-flv',
webm: 'video/webm',
m4a: 'audio/mp4',
// --- 压缩包 (Archives) ---
zip: 'application/zip',
rar: 'application/x-rar-compressed',
'7z': 'application/x-7z-compressed',
tar: 'application/x-tar',
gz: 'application/gzip',
// --- 文本与代码 (Text & Code) ---
txt: 'text/plain',
html: 'text/html',
htm: 'text/html',
css: 'text/css',
js: 'application/javascript', // 或 text/javascript
json: 'application/json',
xml: 'application/xml', // 或 text/xml
md: 'text/markdown',
java: 'text/x-java-source',
py: 'text/x-python',
c: 'text/x-c',
cpp: 'text/x-c++src',
h: 'text/x-c',
yaml: 'application/x-yaml',
yml: 'application/x-yaml',
// --- 字体 (Fonts) ---
ttf: 'font/ttf',
otf: 'font/otf',
woff: 'font/woff',
woff2: 'font/woff2',
eot: 'application/vnd.ms-fontobject',
// --- 其他/特殊格式 ---
apk: 'application/vnd.android.package-archive',
exe: 'application/x-msdownload',
msi: 'application/x-msdownload',
dwg: 'application/acad', // CAD文件,有时也用 application/x-autocad
psd: 'image/vnd.adobe.photoshop',
ai: 'application/postscript',
eps: 'application/postscript',
jsonld: 'application/ld+json',
mjs: 'text/javascript',
// --- 默认兜底 ---
default: 'application/octet-stream'
};
// 辅助函数:根据后缀获取类型
export function getMimeType (suffix) {
const key = suffix.toLowerCase();
return mimeTypeMap[key] || mimeTypeMap.default;
}3-19 下载文件
js
export function downloadFile (resultValue, filename = '新建文本文档', filetype = 'txt') {
if (resultValue) {
const blob = new Blob([resultValue], { type: getMimeType(filetype) });
const downloadElement = document.createElement('a');
const href = window.URL.createObjectURL(blob); // 创建下载的链接
const fileName = `${filename}.${filetype}`;
downloadElement.href = href;
downloadElement.download = fileName; // 下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); // 点击下载
document.body.removeChild(downloadElement); // 下载完成移除元素
window.URL.revokeObjectURL(href); // 释放掉blob对象
} else {
this.$message.error('内容为空,不可保存');
}
}export function downloadFile (resultValue, filename = '新建文本文档', filetype = 'txt') {
if (resultValue) {
const blob = new Blob([resultValue], { type: getMimeType(filetype) });
const downloadElement = document.createElement('a');
const href = window.URL.createObjectURL(blob); // 创建下载的链接
const fileName = `${filename}.${filetype}`;
downloadElement.href = href;
downloadElement.download = fileName; // 下载后文件名
document.body.appendChild(downloadElement);
downloadElement.click(); // 点击下载
document.body.removeChild(downloadElement); // 下载完成移除元素
window.URL.revokeObjectURL(href); // 释放掉blob对象
} else {
this.$message.error('内容为空,不可保存');
}
}3-20 获取文件后缀
js
export function getFileExtension (filename) {
if (!filename) return '';
// 找到最后一个点的位置
const lastDotIndex = filename.lastIndexOf('.');
// 如果没有点,或者点在第一个字符之前(如 .gitignore),返回空字符串
if (lastDotIndex === -1 || lastDotIndex === 0) {
return '';
}
// 截取点之后的部分并转为小写(可选,方便比较)
return filename.slice(lastDotIndex + 1).toLowerCase();
}export function getFileExtension (filename) {
if (!filename) return '';
// 找到最后一个点的位置
const lastDotIndex = filename.lastIndexOf('.');
// 如果没有点,或者点在第一个字符之前(如 .gitignore),返回空字符串
if (lastDotIndex === -1 || lastDotIndex === 0) {
return '';
}
// 截取点之后的部分并转为小写(可选,方便比较)
return filename.slice(lastDotIndex + 1).toLowerCase();
}3-21 生成随机字符串
js
export function generateRandomNumbers () {
let d = new Date().getTime();
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}export function generateRandomNumbers () {
let d = new Date().getTime();
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}3-22 将扁平列表转换为树形结构
js
/**
* 将扁平列表转换为树形结构
* @param {Array} list - 原始扁平数组
* @param {String} rootId - 根节点的 parentId 标识,默认为 'root'
* @returns {Array} - 树形结构数组
*/
function listToTree (list, rootId = 'root') {
// 1. 创建映射表:key 为 id,value 为节点对象
// 使用 Map 或者普通对象都可以,这里用普通对象
const map = {};
const tree = [];
// 2. 初始化:将所有节点放入 map,并初始化 children 数组
// 注意:这里需要深拷贝或者直接引用,通常直接引用即可,但为了安全可以浅拷贝 children
list.forEach(item => {
// 确保 children 存在且为数组,防止后端传 null 导致 push 报错
item.children = item.children || [];
map[item.id] = item;
});
// 3. 构建树:再次遍历,将节点挂载到父节点下
list.forEach(item => {
const parent = map[item.parentId];
if (parent) {
// 如果找到了父节点,将当前节点加入父节点的 children
parent.children.push(item);
} else {
// 如果没找到父节点(即 parentId 为 root 或 找不到对应 id),视为根节点
// 这里做一个额外判断,确保只有真正的根节点才进入 tree 数组
if (item.parentId === rootId || !item.parentId) {
tree.push(item);
} else {
// 这种情况通常是数据脏数据(父节点不存在),可以选择忽略或单独处理
console.warn(`发现孤立节点,ID: ${item.id}, 缺失的父ID: ${item.parentId}`);
// 也可以选择将其强行放入根节点,视业务需求而定
// tree.push(item);
}
}
});
return tree;
}/**
* 将扁平列表转换为树形结构
* @param {Array} list - 原始扁平数组
* @param {String} rootId - 根节点的 parentId 标识,默认为 'root'
* @returns {Array} - 树形结构数组
*/
function listToTree (list, rootId = 'root') {
// 1. 创建映射表:key 为 id,value 为节点对象
// 使用 Map 或者普通对象都可以,这里用普通对象
const map = {};
const tree = [];
// 2. 初始化:将所有节点放入 map,并初始化 children 数组
// 注意:这里需要深拷贝或者直接引用,通常直接引用即可,但为了安全可以浅拷贝 children
list.forEach(item => {
// 确保 children 存在且为数组,防止后端传 null 导致 push 报错
item.children = item.children || [];
map[item.id] = item;
});
// 3. 构建树:再次遍历,将节点挂载到父节点下
list.forEach(item => {
const parent = map[item.parentId];
if (parent) {
// 如果找到了父节点,将当前节点加入父节点的 children
parent.children.push(item);
} else {
// 如果没找到父节点(即 parentId 为 root 或 找不到对应 id),视为根节点
// 这里做一个额外判断,确保只有真正的根节点才进入 tree 数组
if (item.parentId === rootId || !item.parentId) {
tree.push(item);
} else {
// 这种情况通常是数据脏数据(父节点不存在),可以选择忽略或单独处理
console.warn(`发现孤立节点,ID: ${item.id}, 缺失的父ID: ${item.parentId}`);
// 也可以选择将其强行放入根节点,视业务需求而定
// tree.push(item);
}
}
});
return tree;
}