1.递归
const enume = (arr, result = []) => {
arr.forEach(v => {
if (v.prop) result.push(v.prop);
if (v.children && v.children.length) enume(v.children, result);
});
return result;
};
const a = enume(arr);
2.二级table表头竖向展示
//div
table(
border="1"
style="border-collapse:collapse")
template(v-for="col in column")
template(v-if="col.children && col.children.length")
tr(v-for="child in col.children")
th {{child.label}}
tr(v-else)
th {{col.label}}
//- table
//- tr
//- th(colspan="3") js
//- td 11
//- tr
//- th(rowspan="4") zlsd
//- th(rowspan="2") fj
//- th fj1
//- td 22
//- tr
//- th fj2
//- td 33
//- tr
//- th(colspan="2") hj
//- td 34
//- tr
//- th(colspan="2") hx
//- td 44
//- tr
//- th(colspan="3") sj
//- td 55
//- tr
//- th(rowspan="4") jlg
//- th(colspan="2") s1
//- td 66
//- tr
//- th(colspan="2") 2
//- td 77
//- tr
//- th(colspan="2") 3
//- td 88
//- tr
//- th(colspan="2") x4
//- td 99
<script>
import * as _ from 'lodash';
export default {
name: 'tableRow',
props: {
column: {
type: Array,
default: () => [],
},
data: {
type: Array,
default: () => [],
}
},
computed: {
arrayLevel() {
let newLevel = 0;
const emun = (arrs, level = 0) => arrs.forEach(v => {
let level1 = level + 1;
if (v.children && v.children.length) {
emun(v.children, level1);
} else {
if (level1 > newLevel) {
newLevel = level1;
}
}
});
emun(this.column);
return newLevel;
}
},
render(h) {
let depth = 0;
let level = 0;
const emun = (
column
) => {
let row = [];
level++;
depth = level > depth ? level : depth;
let sonLevel = 1;
column.forEach((col, i) => {
let rowspan = 1;
let ths = [{ tag: 'th', text: col.label, rowspan, level, sonLevel }];
if (col.prop) ths[0].td = col.prop;
if (col.children && col.children.length) {
let [e0, ...e] = emun(col.children);
const maxSonLevel = _.maxBy(
[].concat(e0, ...e),
v => v.sonLevel
);
ths[0].rowspan =
e.length +
ths[0].rowspan;
ths[0].sonLevel += maxSonLevel.sonLevel;
ths = [...ths, ...e0];
row.push(ths);
row = row.concat(e);
} else {
if (col.type === 'index') {
ths.push(...this.data.map((v, i) => ({
tag: 'td',
text: i + 1,
})));
} else if (col.prop) {
ths.push(...this.data.map(v => ({
tag: 'td',
text: v[col.prop],
})));
}
row.push(ths);
}
});
level--;
return row;
};
let trs = emun(this.column)
.map(v => h('tr', v.map(j => h(j.tag, {
attrs: j.tag === 'th'
? {
rowspan: j.rowspan,
colspan: j.sonLevel === 1 ? depth - j.level + 1 : 1,
}
: null,
}, j.text))));
return h('table', [
h('tbody', [
trs,
]),
]);
},
};
</script>
<style lang="stylus" scoped>
table
height 100%
border-color 1px solid #dedede
border-collapse collapse
th
background-color #f5f5f5
td, th
border 1px solid #dedede
tr:hover > td
background-color #F5F7FA
td
text-align center
padding 0 5px
min-width 40px
</style>
- 页面轮循
export default {
data() {
return {
timer: '',
};
},
mounted() {
this.timer = setInterval(this.getData, 3000);
},
beforeDestroy() {
clearInterval(this.timer);
},
methods: {
getData() {}
},
};
4.遍历children中的flowNo,使其与父层的flowNo一样
const tableData = res.data.map(v => {
v.children = v.children.map(j => {
return {
...j,
flowNo: v.flowNo,
};
});
return {
...v,
state: '',
};
});
5.component的用法
6.Math用法
Math.ceil 向上取整;
Math.floor 向下取整;
Math.round 四舍五入;
Math.PI 去π值;
Math.abs 取绝对值;
Math.max 取最大值;
Math.min 取最小值;
7.容差用法:
const isClosed = (a, b) => { // 创建一个方法
const aTime = new Date(a).getTime(); // 将要对比的两个参数转换是时间戳
const bTime = new Date(b).getTime();
return Math.abs(aTime - bTime) < 2000; // 在2000毫秒内取绝对值为容差值
};
const findItem = value => this.paramterList.find(k => isClosed(k.createTime, value));
7.localStorage, 图片展示的使用
<template lang="pug">
.sop
ebrain-table(
:column="column"
:data="data"
:highlight-current-row="false")
template(#operate)
el-table-column(
label="操作"
width="120"
align="center")
template(v-slot="{row}")
el-button(
type="primary"
@click="check(row)") 查看
el-dialog(
:visible.sync="dialogVisible"
:close-on-click-modal="false")
.wrap
.img
img(:src="imageUrl")
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'linePosition',
data() {
return {
imageUrl: '',
};
},
computed: {
...mapState('workcenter', {
workcenter: state => state.workcenter,
}),
wc() {
return this.$route.query.wc;
},
},
mounted() {
this.getData();
},
methods: {
getData() {
let data;
try {
data = JSON.parse(localStorage.getItem('mydata_' + this.wc)); //取数据,需将字符串转回对象
} catch (err) {
console.log(err);
} finally {
this.data = data ? [data] : [];
}
},
check(val) {
this.dialogVisible = true;
this.$http.get(val.fileAddress, {
responseType: 'blob',
}).then(res => {
if (res) {
const blob = new Blob([res]);
this.imageUrl = window.URL.createObjectURL(blob);
}
});
},
submitFormTable() {
localStorage.setItem('mydata_' + this.wc, JSON.stringify(this.row)); // 存数据,需转成字符串
this.dialogVisibleTable = false;
this.getData();
},
}
</script>
8.for循环ESLint报错
for (let i in row) {
if (Object.prototype.hasOwnProperty.call(row, i)) {
遍历的内容
}
}
9.类数组结构---set的使用
1.Set实例的属性和方法
size: 返回Set实例的成员总数
add(val): 添加某个值,返回Set结构本身
delete(val): 删除某个值,返回一个布尔值,表示删除是否成功
has(val): 返回一个布尔值,表示参数是否为Set成员
clear(): 清除所有成员,没有返回值
2.遍历操作
let set = new Set(['red','green','blue'])
keys(): 返回一个键名的遍历器 // red green blue
values(): 返回一个键值的遍历器 // red green blue
entries(): 返回一个键值对的遍历器 // ["red", "red"] ["green", "green"] ["blue", "blue"]
forEach(): 使用回调函数遍历每个成员
3.使用方法
由于扩展运算符(...)内部使用for...of循环,所有也可以使用于Set结构
快速去重:
let arr = [3,5,2,2,5,5]
let unique = [...new Set(arr)] // [3,5,2]
map和filter使用
let set = new Set([1,2,3])
set = new Set([...set].map(v=>v*2)) // {2,4,6}
let set = new Set([1,2,3,4,5])
set = new Set([...set].filter(v=>v%2===0)) // {2,4}
并集,交集,差集
let a = new Set([1,2,3])
let b = new Set([4,3,2])
并集 let union = new Set([...a, ...b]) // [1,2,3,4]
交集 let intersect = new Set([...a].filter(v => b.has(v))); // [2,3]
差集 difference = new Set([...a].filter(v => !b.has(v)); // [1, 4]
10.类数组对象去重
原理: 合并两个数组,然后过滤key;
方法1
let arr: any = data.concat(this.form.firstAgencyCompanys);
const res = new Map();
this.form.firstAgencyCompanys = arr.filter(
(v: any) => !res.has(v.agencyId) && res.set(v.agencyId, 1)
);
方法2
let newArr: any = [];
let flag: any = true;
arr.forEach((v: any) => {
newArr.forEach((j: any) => {
if (v.id === j.id) {
flag = false;
}
});
if (flag) {
newArr.push({
...v,
});
}
});
console.log(newArr);
方法3
原理: 2个类数组对象,先将其中一个过滤成关键值的数组
data: 接口数据
const newData = data.map(v => v.type);
newList = arr.filter(j => {
return newData.includes(j.code);
})
11.内循环变量决定外层变量
(如果变量中不存在fileId,则外层要为[], 原理: 创建一个空数组arr,若内部存在fileId,则arr.push,否则arr=[])
this.fileListType = dictList.map((v: any) => {
let arr: any = [];
data
.filter((j: any) => j.type === v.code)
.forEach((h: any) => {
if (h.fileId) {
arr.push({
...h,
name: h.fileName,
});
} else {
arr = [];
}
});
return {
...v,
fileList: arr,
};
});
12.数组对象归类(将数组对象中某个属性相同的值放在一个数组中)
例如: arr = [
{cycleId: '111', cycleName: '开发商1', payNum: 1, payTax: 2},
{cycleId: '222', cycleName: '开发商2', payNum: 3, payTax: 4},
{cycleId: '333', cycleName: '开发商3', payNum: 5, payTax: 6},
{cycleId: '111', cycleName: '开发商1', payNum: 7, payTax: 9},
{cycleId: '222', cycleName: '开发商2', payNum: 9, payTax: 10},
] (接口数据)
期望:
arr = [{
cycleId: '111',
cycleName: '开发商1',
list: [
{cycleId: '111', cycleName: '开发商1', payNum: 1, payTax: 2},
{cycleId: '111', cycleName: '开发商1', payNum: 7, payTax: 9},
],
payNumTotal: 8,
payTaxTotal: 11
},
{
cycleId: '222',
cycleName: '开发商2',
list: [
{cycleId: '222', cycleName: '开发商2', payNum: 3, payTax: 4},
{cycleId: '222', cycleName: '开发商2', payNum: 9, payTax: 10},
],
payNumTotal: 12,
payTaxTotal: 14
},
{
cycleId: '333',
cycleName: '开发商3',
list: [
{cycleId: '333', cycleName: '开发商3', payNum: 5, payTax: 6},
],
payNumTotal: 5,
payTaxTotal: 6
}]
代码:
let map = {};
let newList = [];
arr.forEach((v) => {
if (!map[v.cycleId]) {
map[v.cycleId] = {
cycleId: v.cycleId,
cycleName: v.cycleName,
payNum: v.payNum,
payTax: v.payTax,
dealList: [],
};
} else {
map[v.cycleId].payNumTotal += v.payNum;
map[v.cycleId].payTaxTotal += v.payTax;
}
map[v.cycleId].list.push(v);
});
for (let key in map) {
newList.push(map[key]);
}
console.log(newList, "后");
13.如何处理浏览器断网情况
父组件:
<OfflineHandle
offlineTitle="网络已断开。。。"
desc="断网了,请及时充值"
onlineTitle="连网提醒"
/>
子组件:
<template>
<div
v-if="mask"
class="offline-mask"
>
<h2 class="offline-mask-title">{{ offlineTitle }}</h2>
<p class="offline-mask-desc">{{ desc }}</p>
</div>
</template>
<script>
export default {
name: "offline-handle",
props: {
offlineTitle: {
type: String,
default: "网络已断开,请检查网络连接。",
},
onlineTitle: {
type: String,
default: "网络已连接",
},
desc: {
type: String,
default: "",
},
duration: {
type: Number,
default: 4.5,
},
},
data() {
return {
mask: false,
};
},
mounted() {
window.addEventListener("offline", this.eventHandle);
window.addEventListener("online", this.eventHandle);
},
beforeDestroy() {
window.removeEventListener("offline", this.eventHandle);
window.removeEventListener("online", this.eventHandle);
},
methods: {
eventHandle(event) {
const type = event.type === "offline" ? "error" : "success";
this.$notify({
title: type === "error" ? this.offlineTitle : this.onlineTitle,
message: type === "error" ? this.desc : "",
type,
});
setTimeout(() => {
this.mask = event.type === "offline";
}, 1500);
},
},
};
</script>
<style lang="css" scoped>
.offline-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
z-index: 9999;
transition: position 2s;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.offline-mask-title {
color: rgba(0, 0, 0, 0.8);
}
.offline-mask-desc {
margin-top: 20px;
color: red;
font-weight: bold;
}
</style>
14.slot槽的传参
<template #extend="{ data }">
</template>
<div v-if="$slots.default"> // vue2判断是否有插槽传入
<slot
name="extend"
:data="file"
/>
</div>
vue3判断是否有插槽传入
const { proxy } = getCurrentInstance();
console.log(Object.keys(proxy.$slots)) // 有插槽['extend'],没有['default']
!Object.keys(proxy.$slots).includes("default") ture为有插槽,false为没有插槽
15.JSON.styingify序列化问题
前提: JSON.styingify布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)
或者被转换成 null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined
如:JSON.stringify(function(){}) or JSON.stringify(undefined)
例子:

如上图需要在render输入框中输入函数,并期望拿到最终的结果为:
[{
prop: "date",
label: "日期",
render: (el) => {return ''},
}{
prop: "address",
label: "地址",
render: ,
}{
prop: "name",
label: "名称",
render: ,
}]
处理结果:
let column = '[';
columnData.forEach(v => {
column += `{
prop: "${v.prop}",
label: "${v.label}",
render: ${v.render},
}`
})
column += ']';
console.log(column);
注: 因为输入框内输入的结果为字符串,会拿到"(el) => {return ''}",
单独对该变量进行序列化会出现意想不到结果.
用模板字符串去声明整个column,每个属性均以变量去声明,可以避免上述问题
16.递归多层数据并改造
let drawingItems = [
{
__config__: {
label: "基础容器1",
children: [
{
__config__: {
label: "基础容器2",
children: [
{
__config__: {
label: "基础容器3",
children: [
{
__config__: {
label: "基础容器4",
children: [
{
__config__: {
renderKey: "1021663987894653",
label: "柱状图4-1",
},
},
],
renderKey: "1663987901788",
},
},
{
__config__: {
label: "基础容器5",
children: [
{
__config__: {
renderKey: "1021663987894653",
label: "柱状图5-1",
},
},
],
renderKey: "1663987901708",
},
},
],
renderKey: "1663987901785",
},
},
],
renderKey: "1663987903209",
},
},
],
renderKey: "1663987904683",
},
},
];
let createItem = {
__config__: {
label: "基础容器(新增)",
children: [],
renderKey: "1663987901123",
},
};
let activeRenderKey = "1663987901708";
需求:对选中的层级(activeRenderKey)进行添加一层新的层级(内层/外层)
// 外层递归查找子项目
// 注:deepClone为深拷贝方法
const enums = (arr, position) => {
let newArr = arr?.reduce((pre, cur) => {
let config = cur.__config__;
if (config.renderKey === activeRenderKey) {
if (position === "outer") { // 外层添加
newItem = deepClone(createItem);
newItem.__config__.children = [deepClone(cur)];
newItem.__config__.renderKey = new Date().getTime().toString();
} else { // 内层添加
newItem = deepClone(cur);
let child = deepClone(cur.__config__.children);
createItem.__config__.children = child;
createItem.__config__.renderKey = new Date().getTime().toString();
newItem.__config__.children = deepClone([createItem]);
}
pre.push(newItem);
} else {
let obj = {
...cur,
__config__: {
...cur.__config__,
children:
(config.children?.length &&
enums(config.children, position)) ||
[],
},
};
pre.push(obj);
}
return pre;
}, []);
return newArr;
};
let res = enums(drawingItems, where);
17.自定义ref实现防抖
import { customRef } from 'vue';
<script setup>
const myRef = (val, delay) => {
let timer = null;
return customRef((track, trigger) => {
return {
get() {
track() // 通知vue追踪val的变化(提前和get商量,让他认为val是有用的)
return val;
}
set(newValue) {
clearTimeout(timer)
timer = setTimeout(() => {
val = newValue;
trigger() // 通知vue去重新解析模板
}, delay)
}
}
})
}
let keyWord = myRef('hello', 500)
</script>