前端笔记

247 阅读4分钟

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>

  1. 页面轮循
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)
例子:
![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1f4ba5afbd3243e08ca9718a93decffd~tplv-k3u1fbpfcp-watermark.image "代码说明")

如上图需要在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>