【kk-utils】Excel工具——excel-js

前言

kk-utils 是一款我自己基于这几年开发封装出来的前端工具库

excel-js

excel-jskk-utils里的工具之一(1.2.0版本开始支持),其作用是有多个针对导出导出的方法函数,是我在写项目时积累下来的,几乎可以覆盖日常所需

这个工具是基于GitHub上开源的exceljs的代码,基于此工具库的基础上进行二次封装适合我业务的功能

使用方法

安装

js 复制代码
npm install kk-utils-library -S
pnpm add kk-utils-library -S

可用方法

importExcel

导入Excel

js 复制代码
importExcel(File, [options])
  • File:要导入的Excel文件
  • options:配置项,可选,对象类型
    • allWorksheets:boolean,是否导入所有工作表,无论true还是false,返回的结果都是二维数组,默认为false
    • getValue:(cell) => string,获取单元格的文本值,默认为(cell) => cell.text
    • headerStartLine:number,表头开始行数,默认1开始
    • headerTotalLine:number,表头总行数,默认1
    • toJsonArray:boolean,是否转换成JSON格式,默认true
      • false:则返回的数据是[[key, key, key], [value, value, value], [value,value,value]]这种格式
      • true:则返回的数据是[{key, value}, {key, value}, {key, value}]这种格式
html 复制代码
<input type="file" id="file" accept=".xlsx" />
<button id="import">导入所选文件</button>

这是我要导入的Excel文件,第一行就是表头,总共一行表头,所以使用默认的headerStartLine和headerTotalLine就可以了,如果是多行表头或者开始不是第一行则自行调整或者传入对应参数

js 复制代码
import { importExcel } from 'kk-utils-library/excel-js';

const fileInput = document.getElementById('file');
const importButton = document.getElementById('import');
importButton.addEventListener('click', () => {
  const file = fileInput.files[0];
  if (!file) {
    alert('请选择文件');
    return;
  }
  importExcel(file, {
    headerStartLine: 1,
    headerTotalLine: 1
  }).then((data) => {
    console.log('data', data);
    // [
    //   [
    //     {
    //       操作类型: '新增',
    //       客户名称: '测试1',
    //       客户编码: 'TEST001',
    //       客户类型: '供应商',
    //       省: '辽宁省',
    //       市: '沈阳市',
    //       区: '辽中县'
    //     },
    //     {
    //       操作类型: '修改',
    //       客户名称: '测试2',
    //       客户编码: 'TEST002',
    //       客户类型: '客户',
    //       省: '山西省',
    //       市: '太原市',
    //       区: '晋源区'
    //     },
    //     {
    //       操作类型: '删除',
    //       客户名称: '测试3',
    //       客户编码: 'TEST003',
    //       客户类型: '客户与供应商',
    //       省: '吉林省',
    //       市: '长春市',
    //       区: '宽城区'
    //     },
    //     {
    //       操作类型: '不变',
    //       客户名称: '测试4',
    //       客户编码: 'TEST004',
    //       客户类型: '供应商',
    //       省: '湖南省',
    //       市: '长沙市',
    //       区: '雨花区'
    //     }
    //   ]
    // ];
  });
});

exportExcel

导出Excel

js 复制代码
exportExcel([options])
  • filename:导出的文件名,默认为excel
  • sheets:object[],要导出的工作表
    • sheetName:string,表名,默认为SheetJS[index + 1]
    • withDefaultStyle:boolean,携带默认样式,默认true,全局默认样式可通过setGlobalDefaultStyle()配置
    • adaptiveWidth:boolean,自适应列宽,默认true
    • adaptiveWidthOptions:object,自适应列宽配置项
      • minWidth:number,最小列宽,默认5
      • maxWidth:number,最大列宽,默认50
      • interstice:number,列宽额外空隙,默认5
      • ignoreLines:number[],计算列宽忽略的行,因为有些行会有合并单元格的操作,这样会导致合并行的列度最大并使用合并行的列宽作为整列的宽,所以可以传入合并行的行数来进行列宽计算忽略
    • processing:(worksheet) => void,对工作表对象做操作处理,这个是在自动列宽和默认样式之前执行的
    • extraProcessing:(worksheet) => void,对工作表对象做操作额外处理,这个是在自动列宽和默认样式之后执行的
  • processing:(workbook) => void,对Excel对象做操作处理
html 复制代码
<button id="export">导出测试文件</button>
js 复制代码
import { exportExcel } from 'kk-utils-library/excel-js';

const exportButton = document.getElementById('export');
exportButton.addEventListener('click', () => {
  const data = [
    ['姓名', '年龄', '性别'],
    ['张三', 18, '男'],
    ['李四', 19, '女'],
    ['王五', 20, '男']
  ];
  exportExcel({
    filename: 'test',
    sheets: [
      {
        processing: (worksheet) => {
          worksheet.addRows(data);
        },
        extraProcessing: (worksheet) => {
          _merge(worksheet.getRow(1), {
            fill: {
              type: 'pattern',
              pattern: 'solid',
              fgColor: {
                argb: 'FF99CCFF'
              }
            }
          });
          _merge(worksheet.getRow(2).getCell(2), {
            fill: {
              type: 'pattern',
              pattern: 'solid',
              fgColor: {
                argb: 'FFFF4949'
              }
            }
          });
        }
      }
    ]
  });
});

然后就可以看到下载了一份名为test.xlsx的文件,打开就是我们要的数据和效果了

coordinatesFromRange

从一个区间范围获取所有的坐标矩阵

js 复制代码
coordinatesFromRange(range)
  • range:[number, number, number, number]坐标点,四个参数分别代表开始行 开始列 结束行 结束列
js 复制代码
import { coordinatesFromRange } from 'kk-utils-library/excel-js';

const coordinatesResult = coordinatesFromRange([2, 3, 3, 4]);
console.log('coordinatesResult', coordinatesResult);
// [
//   [2, 3],
//   [2, 4],
//   [3, 3],
//   [3, 4]
// ];

isCoordinateInCoordinates

判断一个坐标点是否在坐标矩阵内

js 复制代码
isCoordinateInCoordinates(coordinate, coordinates)
  • coordinate:[number, number]坐标点
  • coordinates:坐标矩阵
js 复制代码
import { isCoordinateInCoordinates } from 'kk-utils-library/excel-js';

const isCoordinateInCoordinatesResult = isCoordinateInCoordinates(
  [2, 3],
  coordinatesResult
);
const isCoordinateInCoordinatesResult2 = isCoordinateInCoordinates(
  [12, 13],
  coordinatesResult
);
console.log('isCoordinateInCoordinatesResult', isCoordinateInCoordinatesResult);
// true
console.log('isCoordinateInCoordinatesResult2', isCoordinateInCoordinatesResult2);
// false

isCoordinateInRange

判断一个坐标点是否在坐标范围内

js 复制代码
isCoordinateInRange(coordinate, range)
  • coordinate:[number, number]坐标点
  • range:[number, number, number, number]坐标点,四个参数分别代表开始行 开始列 结束行 结束列
js 复制代码
import { isCoordinateInRange } from 'kk-utils-library/excel-js';

const isCoordinateInRangeResult = isCoordinateInRange(
  [2, 3],
  [2, 3, 5, 8]
);
const isCoordinateInRangeResult2 = isCoordinateInRange(
  [12, 13],
  [2, 3, 5, 8]
);
console.log('isCoordinateInRangeResult', isCoordinateInRangeResult);
// true
console.log('isCoordinateInRangeResult2', isCoordinateInRangeResult2);
// false

getHorizontalMerges

获取横向合并数据,此数据是专门给exceljs用的

js 复制代码
getHorizontalMerges(excelData)
  • excelData:二维数组
js 复制代码
import { 
    getHorizontalMerges,
    freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
    horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
    verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';

const horizontalMergeAndVerticalMergeTestData = [
  [11, 12, hm, hm, 15, 16, 17, 18, 19],
  [21, 22, 23, 24, 25, fm, fm, 28, 29],
  [31, 32, vm, 34, 35, fm, fm, 38, 39],
  [41, 42, vm, 44, vm, 46, hm, hm, hm],
  [51, 52, 53, 54, vm, 56, 57, 58, 59],
  [61, 62, vm, 64, vm, 66, 67, 68, 69],
  [71, 72, vm, 74, 75, 76, 77, 78, 79],
  [81, 82, vm, 84, 85, 86, 87, 88, 89],
  [91, 92, 93, 94, 95, 96, 97, 98, 99]
];

const horizontalMergesResult = getHorizontalMerges(
  horizontalMergeAndVerticalMergeTestData
);
console.log('horizontalMergesResult', horizontalMergesResult);
// [
//   [1, 2, 1, 4],
//   [4, 6, 4, 9]
// ];

getVerticalMerges

获取纵向合并数据,此数据是专门给exceljs用的

js 复制代码
getVerticalMerges(excelData)
  • excelData:二维数组
js 复制代码
import { 
    getVerticalMerges,
    freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
    horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
    verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';

const horizontalMergeAndVerticalMergeTestData = [
  [11, 12, hm, hm, 15, 16, 17, 18, 19],
  [21, 22, 23, 24, 25, fm, fm, 28, 29],
  [31, 32, vm, 34, 35, fm, fm, 38, 39],
  [41, 42, vm, 44, vm, 46, hm, hm, hm],
  [51, 52, 53, 54, vm, 56, 57, 58, 59],
  [61, 62, vm, 64, vm, 66, 67, 68, 69],
  [71, 72, vm, 74, 75, 76, 77, 78, 79],
  [81, 82, vm, 84, 85, 86, 87, 88, 89],
  [91, 92, 93, 94, 95, 96, 97, 98, 99]
];

const verticalMergesResult = getVerticalMerges(
  horizontalMergeAndVerticalMergeTestData
);
console.log('verticalMergesResult', verticalMergesResult);
// [
//   [2, 3, 4, 3],
//   [3, 5, 6, 5],
//   [5, 3, 8, 3]
// ];

getMatrixMerges

获取纵向和横向的合并数据,此数据是专门给exceljs用的

js 复制代码
getMatrixMerges(excelData)
  • excelData:二维数组
js 复制代码
import { 
    getMatrixMerges,
    freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
    horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
    verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';

const freeMergeTestData = [
  [11, 21, fm, fm, fm, 61, fm, fm, 91],
  [21, 22, fm, fm, fm, 26, 27, 28, 29],
  [31, 32, fm, fm, fm, 36, fm, fm, 39],
  [41, 42, 43, 44, 45, 46, fm, fm, 49],
  [51, 52, fm, fm, 55, 56, fm, fm, 59],
  [fm, 62, fm, fm, 65, 66, 67, 68, 69],
  [fm, 72, fm, fm, 75, 76, 77, 78, 79],
  [81, 82, fm, fm, 85, 86, 87, 88, 89],
  [91, 92, 93, 94, 95, 96, 97, 98, 99]
];

const matrixMergesResult = getMatrixMerges(freeMergeTestData);
console.log('matrixMergesResult', matrixMergesResult);
// [
//   [1, 2, 3, 5],
//   [1, 6, 1, 8],
//   [2, 6, 5, 8],
//   [4, 2, 8, 4],
//   [5, 1, 7, 1]
// ];

getMerges

获取合并数据,此数据是专门给exceljs用的 此方法涵盖了前面三种getMerge方法,会自动识别数据里的hm, vm, fm

js 复制代码
getMerges(excelData)
  • excelData:二维数组
js 复制代码
import { 
    getMerges,
    freeMerge as fm, // 代表自由合并 上下都合并,必须是正方形/长方形 起点为fm左上角单元格
    horizontalMerge as hm, // 代表横向合并 起点为hm前一个单元格
    verticalMerge as vm // 代表纵向合并 起点为vm上一个单元格
} from 'kk-utils-library/excel-js';

const horizontalMergeAndVerticalMergeTestData = [
  [11, 12, hm, hm, 15, 16, 17, 18, 19],
  [21, 22, 23, 24, 25, fm, fm, 28, 29],
  [31, 32, vm, 34, 35, fm, fm, 38, 39],
  [41, 42, vm, 44, vm, 46, hm, hm, hm],
  [51, 52, 53, 54, vm, 56, 57, 58, 59],
  [61, 62, vm, 64, vm, 66, 67, 68, 69],
  [71, 72, vm, 74, 75, 76, 77, 78, 79],
  [81, 82, vm, 84, 85, 86, 87, 88, 89],
  [91, 92, 93, 94, 95, 96, 97, 98, 99]
];

const mergesResult = getMerges(horizontalMergeAndVerticalMergeTestData);
console.log('mergesResult', mergesResult);
// [
//   [1, 2, 1, 4],
//   [4, 6, 4, 9],
//   [2, 3, 4, 3],
//   [3, 5, 6, 5],
//   [5, 3, 8, 3],
//   [1, 5, 3, 7]
// ];

getDefaultStyle

获取全局默认样式

js 复制代码
getDefaultStyle()
js 复制代码
import { getDefaultStyle } from 'kk-utils-library/excel-js';

const beforeStyle = getDefaultStyle();
console.log('beforeStyle', beforeStyle);
// {
//   font: {
//     size: 14
//   },
//   alignment: {
//     vertical: 'top',
//     wrapText: true
//   },
//   border: {
//     top: {
//       style: 'thin'
//     },
//     left: {
//       style: 'thin'
//     },
//     bottom: {
//       style: 'thin'
//     },
//     right: {
//       style: 'thin'
//     }
//   },
//   fill: {
//     type: 'pattern',
//     pattern: 'solid',
//     fgColor: {
//       argb: 'FF99CCFF'
//     }
//   }
// }

getDefaultStyle

获取全局默认样式

js 复制代码
getDefaultStyle()
js 复制代码
import { setGlobalDefaultStyle } from 'kk-utils-library/excel-js';

const afterStyle = setGlobalDefaultStyle({
  font: {
    size: 14
  },
  fill: {
    type: 'pattern',
    pattern: 'solid',
    fgColor: {
      argb: 'FF99CCFF'
    }
  }
});
const afterStyle = getDefaultStyle();
console.log('afterStyle', afterStyle);
// {
//   font: {
//     size: 14
//   },
//   alignment: {
//     vertical: 'top',
//     wrapText: true
//   },
//   border: {
//     top: {
//       style: 'thin'
//     },
//     left: {
//       style: 'thin'
//     },
//     bottom: {
//       style: 'thin'
//     },
//     right: {
//       style: 'thin'
//     }
//   },
//   fill: {
//     type: 'pattern',
//     pattern: 'solid',
//     fgColor: {
//       argb: 'FF99CCFF'
//     }
//   }
// }

setAdaptiveWidth

设置Excel的单元格自适应宽度,如果你自己使用exceljs则需要自己使用setAdaptiveWidth去处理,kk-utils里的导出默认是true了,可以自己传入调整参数,ExcelJs的参数需自己看文档

js 复制代码
setAdaptiveWidth(Worksheet, [options])
js 复制代码
import { setAdaptiveWidth } from 'kk-utils-library/excel-js';
import ExcelJS from 'exceljs';

const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('SheetJS');
worksheet.addRows([
  ['姓名', '简称', '年龄', '性别'],
  ['小明', '无', 18, '男'],
  ['古力那扎尔·拜合提亚尔', '古力娜扎', 16, '女'],
  [
    '巴勃罗·迭戈·荷瑟·山迪亚哥·弗朗西斯科·德·保拉·居安·尼波莫切诺·克瑞斯皮尼亚诺·德·罗斯·瑞米迪欧斯·西波瑞亚诺·德·拉·山迪西玛·特立尼达·玛利亚·帕里西奥·克里托·瑞兹·布拉斯科·毕加索',
    '毕加索',
    92,
    '男'
  ]
]);
console.log('before worksheet widths', _map(worksheet.columns, 'width'));
// [null, null, null, null];
setAdaptiveWidth(worksheet, {
  minWidth: 15,
  maxWidth: 50
});
console.log('after worksheet widths', _map(worksheet.columns, 'width'));
// [50, 17, 15, 15];

getDataHeader

获取最后渲染数据用的表头,因为表头我们可能需要合并,所以塞数据的时候原始表头不适用,需要使用列一一对应的表头才能更方便加入表体数据

js 复制代码
getDataHeader(excelData)
  • excelData:二维数组
js 复制代码
import { getDataHeader } from 'kk-utils-library/excel-js';

const dataHeader = getDataHeader([
  ['编码', '时间', '已批准', '已核销', '未核销', hm, '已支付', '待支付'],
  [vm, vm, vm, vm, '申请中', '未申请', vm, vm]
]);
console.log('dataHeader', dataHeader);
// [
//   '编码',
//   '时间',
//   '已批准',
//   '已核销',
//   '申请中',
//   '未申请',
//   '已支付',
//   '待支付'
// ];

getColumnLetterByNumber

根据列下标1开始获取对应的Excel字母列

js 复制代码
getColumnLetterByNumber(number)
js 复制代码
import { getColumnLetterByNumber } from 'kk-utils-library/excel-js';

const letter = getColumnLetterByNumber(5);
console.log('letter', letter);
// E

getDepthAndLength

获取树结构的深度和最长子级长度

js 复制代码
getDepthAndLength(tree, [options])
  • tree:树形数组
  • options:配置项,可选,对象类型,支持基础配置项
    • itemKey:指定节点key名,默认值为id
    • childrenKey:自定义子节点key名,默认值为children
js 复制代码
import { getDepthAndLength } from 'kk-utils-library/excel-js';

const getDepthAndLengthTree = [
  {
    key: 1,
    children: [
      {
      {
        key: 12,
        children: [
          {
            key: 122,
            children: [
              {
                key: 1221
              },
              {
                key: 1222,
                children: [
                  {
                    key: 12221
                  },
                  {
                    key: 12222
                  },
                  {
                    key: 12223
                  },
                  {
                    key: 12224
                  },
                  {
                    key: 12225
                  },
                  {
                    key: 12226
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
];
const getDepthAndLengthResult = getDepthAndLength(getDepthAndLengthTree);
console.log('getDepthAndLengthResult', getDepthAndLengthResult);
// { depth: 5, length: 6 }

getFillHorizontalMergeKeyMap

获取表头横向合并列所对应的合并长度

js 复制代码
getFillHorizontalMergeKeyMap(Tree, [options])
  • tree:树形数组
  • options:配置项,可选,对象类型,支持基础配置项
    • itemKey:指定节点key名,默认值为id
    • childrenKey:自定义子节点key名,默认值为children
js 复制代码
import { getFillHorizontalMergeKeyMap } from 'kk-utils-library/excel-js';

const treeHeader = [
  {
    prop: 'index',
    label: '序号'
  },
  {
    prop: 'budgetCycleItemName',
    label: '预算周期项名称'
  },
  {
    prop: 'expectedShipmentAmount',
    label: '预发货金额',
    children: [
      {
        prop: 'originalExpectedShipmentAmount',
        label: '调整前金额'
      },
      {
        prop: 'adjustedExpectedShipmentAmount',
        label: '调整的金额'
      },
      {
        prop: 'finalExpectedShipmentAmount',
        label: '调整后金额'
      }
    ]
  },
  {
    prop: 'budgetAmount',
    label: '预算金额',
    children: [
      {
        prop: 'originalBudgetAmount',
        label: '调整前金额'
      },
      {
        prop: 'adjustedBudgetAmount',
        label: '调整的金额'
      },
      {
        prop: 'finalBudgetAmount',
        label: '调整后金额'
      }
    ]
  }
];
const getFillHorizontalMergeKeyMapResult =
  getFillHorizontalMergeKeyMap(treeHeader);
console.log(
  'getFillHorizontalMergeKeyMapResult',
  getFillHorizontalMergeKeyMapResult
);
// {
//   index: 0,
//   budgetCycleItemName: 0,
//   expectedShipmentAmount: 2,
//   originalExpectedShipmentAmount: 0,
//   adjustedExpectedShipmentAmount: 0,
//   finalExpectedShipmentAmount: 0,
//   budgetAmount: 2,
//   originalBudgetAmount: 0,
//   adjustedBudgetAmount: 0,
//   finalBudgetAmount: 0
// }

tableHeaderToMultidimensionalArray

把树结构表头处理成Excel的表头

js 复制代码
tableHeaderToMultidimensionalArray(Tree, [options])
  • tree:树形数组
  • options:配置项,可选,对象类型,支持基础配置项
    • itemKey:指定节点key名,默认值为id
    • childrenKey:自定义子节点key名,默认值为children
    • labelKey: 自定义节点文本key名,默认值为label
js 复制代码
import { tableHeaderToMultidimensionalArray } from 'kk-utils-library/excel-js';

const treeHeader = [
  {
    prop: 'index',
    label: '序号'
  },
  {
    prop: 'budgetCycleItemName',
    label: '预算周期项名称'
  },
  {
    prop: 'expectedShipmentAmount',
    label: '预发货金额',
    children: [
      {
        prop: 'originalExpectedShipmentAmount',
        label: '调整前金额'
      },
      {
        prop: 'adjustedExpectedShipmentAmount',
        label: '调整的金额'
      },
      {
        prop: 'finalExpectedShipmentAmount',
        label: '调整后金额'
      }
    ]
  },
  {
    prop: 'budgetAmount',
    label: '预算金额',
    children: [
      {
        prop: 'originalBudgetAmount',
        label: '调整前金额'
      },
      {
        prop: 'adjustedBudgetAmount',
        label: '调整的金额'
      },
      {
        prop: 'finalBudgetAmount',
        label: '调整后金额'
      }
    ]
  }
];

const multidimensionalArray = tableHeaderToMultidimensionalArray(treeHeader);
console.log('multidimensionalArray', multidimensionalArray);
// [
//   [
//     '序号',
//     '预算周期项名称',
//     '预发货金额',
//     '-hm',
//     '-hm',
//     '预算金额',
//     '-hm',
//     '-hm'
//   ],
//   [
//     '-vm',
//     '-vm',
//     '调整前金额',
//     '调整的金额',
//     '调整后金额',
//     '调整前金额',
//     '调整的金额',
//     '调整后金额'
//   ]
// ];

conversionToJsonArray

把Excel数据转成数组对象格式

js 复制代码
conversionToJsonArray(ExcelData, [options])
  • excelData:二维数组
  • options:配置项,可选,对象类型
    • headerStartLine:number,表头开始行数,默认1开始
    • headerTotalLine:number,表头总行数,默认1
js 复制代码
import { conversionToJsonArray } from 'kk-utils-library/excel-js';

const arrayData = [
  ['操作类型', '客户名称', '客户编码', '省', '市', '区'],
  [
    '不变',
    '苏州秦曼商贸有限公司',
    '11605028',
    '苏北省(作废)',
    '苏州市',
    '吴中区'
  ],
  [
    '不变',
    '测试-嘉士柏河南省郑州------麻三定/麻坤丽',
    'JSB12001003',
    '河南省',
    '郑州市',
    '中原区'
  ]
];
const conversionToJsonArrayResult = conversionToJsonArray(arrayData);
console.log('conversionToJsonArrayResult', conversionToJsonArrayResult);
// [
//   {
//     操作类型: '不变',
//     客户名称: '苏州秦曼商贸有限公司',
//     客户编码: '11605028',
//     省: '苏北省(作废)',
//     市: '苏州市',
//     区: '吴中区'
//   },
//   {
//     操作类型: '不变',
//     客户名称: '测试-嘉士柏河南省郑州------麻三定/麻坤丽',
//     客户编码: 'JSB12001003',
//     省: '河南省',
//     市: '郑州市',
//     区: '中原区'
//   }
// ];
相关推荐
聪明的墨菲特i29 分钟前
React与Vue:哪个框架更适合入门?
开发语言·前端·javascript·vue.js·react.js
时光少年30 分钟前
Android 副屏录制方案
android·前端
拉不动的猪37 分钟前
v2升级v3需要兼顾的几个方面
前端·javascript·面试
时光少年39 分钟前
Android 局域网NIO案例实践
android·前端
半兽先生1 小时前
VueDOMPurifyHTML 防止 XSS(跨站脚本攻击) 风险
前端·xss
冴羽1 小时前
SvelteKit 最新中文文档教程(20)—— 最佳实践之性能
前端·javascript·svelte
Jackson__1 小时前
面试官:谈一下在 ts 中你对 any 和 unknow 的理解
前端·typescript
zpjing~.~1 小时前
css 二维码始终显示在按钮的正下方,并且根据不同的屏幕分辨率自动调整位置
前端·javascript·html
红虾程序员1 小时前
Linux进阶命令
linux·服务器·前端
yinuo1 小时前
uniapp在微信小程序中实现 SSE 流式响应
前端