前言
新人报道,定期分享自己遇到的问题跟常用的方法,有更好的写法可以留言😅😅
1、分组
// 按照oaCode进行数据分组
let list = [
{
oaCode: 'zhangfei',
age: 12,
text: '我是1号'
},
{
oaCode: 'zhangfei',
age: 120,
text: '我是2号'
},
{
oaCode: 'zhangfei',
age: 1200,
text: '我是2号'
},
{
oaCode: 'guanyu',
age: 11,
text: '我是关羽1号'
},
{
oaCode: 'guanyu',
age: 111,
text: '我是关羽2号'
},
{
oaCode: 'guanyu',
age: 1111,
text: '我是关羽2号'
}
]
let map = {}
let dest = []
for(let i = 0; i < list.length; i++) {
let ai = list[i]
if(!map[ai.oaCode]) {
dest.push({
oaCode: ai.oaCode,
data: [ai]
})
map[ai.oaCode] = ai
} else {
console.log(dest, map)
for(let j = 0; j < dest.length; j++) {
let dj = dest[j]
if(dj.oaCode == ai.oaCode) {
dj.data.push(ai)
break
}
}
}
}
console.log('dest', dest)
2、简单实现antd面包屑
import {withRouter} from ‘react-router-dom’
import { Breadcrumb } from 'antd'
let list = {
‘/home’: ’首页’,
….
}
export default withRouter(props => {
let { location, userInfo } = props
let pathList = [] // 切割url
let urlKey = location.pathname // 拿到当前页面的url
if(urlKey === ‘/’){
…
} else {
pathList = location.pathname.split(‘/’).filter(I=>i)
}
const showListUrl = pathList.map((ele,index) =>{
let url = `/${pathList.split(0, index +1).join(‘/‘)}/`
let urlName = list[url] // 对象根据键名查找值
if (urlName) {
return (
<Breadcrumb.Item key={url}>
{urlName}
</Breadcrumb.Item>
)
}
}).filter(i=>i)
return (
<Breadcrumb separator=‘>’>
{showListUrl}
</Breadcrumb>
)
})
// 在app中引入次组件
3、antd3.x的日期输入框的年份选择
this.state = {
timeYear: null,
isOpen: false
}
let handlePanelChange = (e) => {
this.setState({ isOpen: false, timeYear: e})
}
let handleOpenChange = (e) => {
if(e) {
this.setState({ isOpen: true })
} else {
this.setState({ isOpen: false })
}
}
<DatePicker
mode='year'
allowClear={false}
value={timeYear}
open={isOpen}
format='YYYY'
// 如果设置月份 'month' 的话,可以如下设置月份为数组类型
// monthCellContentRender={date => {
// return `${moment(date).format('M')}月`; // 修改中文显示为数字
// }}
onPanelChange={this.handlePanelChange}
onOpenChange={this.handleOpenChange}
>
</DatePicker>
4、水印实现
function createwater (oaName,oaCode) {
// 创建水印浮层
const watermark = document.createElement('div')
if ('pointerEvents' in watermark.style) {
//判断是否支持pointerEvents 属性,避免 IE8,9
watermark.style.cssText="position:fixed;width:100%;height:100%;top:0;left:0;z-index:99999;pointer-events:none;"
document.body.appendChild(watermark)// 初始化 画布
const canvas = document.createElement('canvas')
canvas.width = 200
canvas.height = 200
const ctx=canvas.getContext('2d')
ctx.globalAlpha= 0.2
ctx.fill()// 处理图片
const image = new window.Image
image.src =''
// 登录状态下不会出现这行文字,点击页面右上角一键登录'
image.setAttribute('crossOrigin', 'anonymous')
if(oaCode) {
ctx.font = 'lighter 10px SimHei'
ctx.fillstvle ='RGBA(0,0,0,0.085)'
// ctx.fillText(oaCode,0,25)
// ctx.fillText(oaCode,0,50)
// ctx.fillText(oaCode,0,75)
// ctx.fillText(oaCode,0,100)
// ctx.fillText(oaCode,0,125)
image.onload =()=>{
ctx.fillstyle='#666'
ctx.font="lighter 16px SimHei"
ctx.rotate(-Math.PI/8)
ctx.drawImage(image,-10,70,canvas.width,image.height * canvas.width / image.width)
ctx.fillText(oaName,20,120)
watermark.style.backgroundImage = `url(${canvas.toDataURL('image/png')})`
}
}
}
}
createwater('张飞', 'zhangfei')
5、循环异步调用(promise)
// all()方法,如果有一个Promise对象报错了,则all()无法执行,会报错你的错误,无法获得其他成功的数据。
let list = [1,2,3,4,5,2]
let promiseList = []
// 模拟异步接口调用
let timeOut = (data) => {
return new Promise((resolve) => {
setTimeout(()=>{
resolve(data + '号')
},)
})
}
// 循环数组调用接口, all只适合调用都成功
list.map(ele => {
promiseList.push(timeOut(ele))
})
Promise.all(promiseList).then(res => {
console.log('el', res)
})
// allSettled()方法是不管有没有报错,把所有的Promise实例的数据都返回回来,放入到一个对象中。
let list = [1, 2, 3, 4, 5]
let newList = list.map(ele => {
return new Promise(resolve => {
setTimeout(()=> {
resolve(ele+'嘿嘿')
}, 1)
})
})
let fun = async() => {
await Promise.allSettled(newList).then(res => {
console.log('res', res)
})
console.log('9999')
}
fun()
6、原生图片上传
<body>
<input type='file' id='inp' onchange="onImgUpload()" />
<img src='' id='img' />
</div>
</body>
</html>
<script>
let onImgUpload = () => {
let fileDom = document.getElementById('inp')
let file = fileDom.files[0]
let Img = document.getElementById('img')
console.log(file)
if(!file) return
if(file.type === 'image/jpeg' || file.type === 'image/png') {
const reader = new window.FileReader()
reader.addEventListener('load', e => {
const imgData = e.target.result
const image = new window.Image()
image.onload = () => {
console.log('image', file, imgData)
// 异步操作调接口....
file.value = ''
}
image.src = imgData
Img.src = imgData
})
reader.readAsDataURL(file)
} else {
console.log('图片格式有误,请重新上传')
}
}
</script>
7、滚动到顶部
export const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
}
8、qrcode包二维码生成器并下载
// 引入qrocde包
const Qrcode = require('qrcode')
// 使用
getCode = () => {
Qrcode.toDataURL(rul) // 设置二维码的链接
.then(res => {
this.setState({ img: res }) // 二维码图片的url
})
.catch(err => {
console.log(err)
})
// 调用接口 dispatch....
}
// 使用a标签的download属性下载,将二维码的url给a标签的herf属性赋值,之后使用download属性定义下载的名称
<a herf='' id='aId' onClick={this.onDownload}>下载<a>
let onDownload = () => {
let aLink = document.getElementById('aId')
aLink.herf = img
aLink.download = '下载'
}
9、打印
<body >
<div id='container'>
<div class='print-content' onclick='textPrint()'>
<img />
</div>
</div>
</body>
</html>
<script>
// 当前窗口打印
let textPrint = () => {
// 可以打印文本,也可以将二维码图片打印
window.document.body.innerHTML = document.querySelector('.print-content').innerHTML; // 需要打印的内容
window.print();
window.location.reload(); // 打印完成后重新加载页面
}
// 打开新窗口打印
let textPrint = () => {
const printHtml = document.querySelector('.print-content').innerHTML; // 需要打印的内容
const newWin = window.open('', 'newwindow');
newWin.document.write('<html><head><title>Print title!</title><style>// 添加样式内容</style></head><body>')
newWin.document.write(printHtml);
newWin.document.write('</body></html>');
newWin.print();
newWin.close(); // 打印完成后关闭
}
</script>
10、下载二进制流文件
let onDownload = () => {
axios({
method: 'post',
url: '/export',
responseType: 'arraybuffer',
headers: {}
})
.then(res => {
// 假设 data 是返回来的二进制数据
const fileName = '下载名称.xlx'
const data = res.data
const blob = new Blob([data], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"})
// 通过 FileReader 读取这个 blob
const reader = new FileReader()
reader.onload = e => {
const res = e.target.result
// 此处对fileReader读出的结果进行JSON解析
// 可能会出现错误,需要进行捕获
try {
const json = JSON.parse(res)
if (json) {
// 解析成功说明后端导出出错,进行导出失败的操作,并直接返回
return message.error('失败,格式错误')
}
} catch (err) {
// 该异常为无法将字符串转为json,说明返回的数据是一个流文件
// IE和EDGE上不兼容,因为这两款浏览器无法通过a标签直接下载blob对象,可直接通过window.navigator.msSaveBlob下载
if (window.navigator.msSaveBlob) {
let url = fileName // ie需要引用一下才能获取值
window.navigator.msSaveBlob(blob, url)
} else {
const link = document.createElement('a')
// 兼容不同浏览器的URL对象
const url = window.URL || window.webkitURL || window.moxURL
// 创建下载链接
const downloadHref = url.createObjectURL(blob)
// a标签添加属性
link.style.display = 'none'
link.href = downloadHref
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
}
}
// 将blob对象以文本的方式读出,读出完成后将会执行 onload 方法
reader.readAsText(tempBlob)
})
}
11、immutable 第三方深复制包
// 1、使用 ...运算符只能对基本数据类型进行复制,无法复制复杂数据类型
// 2、使用JSON.parse(JSON.stringify()) 无法对undefined进行复制,如果强行复制会出现问题
// 3、immutable可解决上面的缺点
// 1、cnpm i immutable -S
import { Map } from 'immutable'
let obj = {
name: '章三',
list: [1, 2, 3]
}
let oldObj = Map(obj) // 旧的数据
// 方式一
let newObj = olbObj.set('name', 'hahha') // 设置新的值
console.log(oldObj.get('name'), newObj.get('name')) // 获取值
// 方式二
let objectObj = oldObj.toJS() // 上面的方式不好查看,这样可以将值转为常用的对象的方式
console.log(objectObj)
12、node的eventss事件触发器
cnpm i events -S
import { EventEmitter } from 'events'
// 封装
class MyEmitter extends EventEmitter {};
exprot default new MyEmitter()
// 使用,可用在某个事件中,在其他地方可用addlistener监听
MyEmitter.emit('btn') // 标示
// 在其他组件可用
MyEmitter.addListener('btn', ()=>{}) // 监听
// 文档:http://nodejs.cn/api/events.html#events
13、递归tree结构
// 根据orgId拿到父节点的id跟orgName
let list = [
{
orgId: 1,
orgName: '我是节点1',
subNode: [
{
orgId: 11,
orgName: '我是节点1的子节点1',
subNode: [
{
orgId: 111,
orgName: '我是节点1的子节点1的子节点'
}
]
},
{
orgId: 12,
orgName: '我是节点1的子节点2',
}
]
},
{
orgId: 2,
orgName: '我是节点2',
subNode: [
{
orgId: 21,
orgName: '我是节点2的子节点1',
subNode: [
{
orgId: 211,
orgName: '我是节点2的子节点1的子节点'
}
]
},
{
orgId: 22,
orgName: '我是节点2的子节点2',
}
]
}
]
function headlData(treeData, id) {
const targetData = {}
function loops(data = [], parent) {
return data.map(({ subNode, orgId: orgId, orgName: orgName }) => {
const node = {
orgId,
orgName,
parent
}
targetData[orgId] = node
node.subNode = loops(subNode, node)
})
}
function getNode(orgId) {
let node = []
let currentNode = targetData[orgId]
//node.push(currentNode.orgName) 获取父节点的orgName
node.push(currentNode.orgId) // 获取父节点的orgId
if(currentNode.parent) {
node = [...getNode(currentNode.parent.orgId), ...node]
}
return node
}
loops(treeData)
return getNode(id)
}
let a = headlData(list, 22)
console.log('a', a)
14、js实现图片懒加载
<body>
<div>
<img src="./2.jpg" data-src='./1.jpg' alt="pig">
<img src="./2.jpg" data-src='./1.jpg' alt="pig">
<img src="./2.jpg" data-src='./1.jpg' alt="pig">
<img src="./2.jpg" data-src='./1.jpg' alt="pig">
</div>
</body>
function imgonload() {
let img = document.querySelectorAll("img");
for(let i=0; i<img.length; i++) {
if(img[i].getBoundingClientRect().top < window.innerHeight) {
//图片一旦有src就会加载出来,所以图片的路径不会放在src中,而是一个自定义的属性data-src中
// dataset 获取自定义属性
console.log(img[i].dataset.src)
img[i].src = img[i].dataset.src;
}
}
}
function scollImg(fn) {
let timer = null;
let context = this;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context);
}, 500)
}
}
window.onload = imgonload;
window.onscroll = scollImg(imgonload);
15、关于Antd Table组件selectRows 翻页后不保留上一页已选items的解决方案
class Parts extends React.Component {
state = {
selectedRowKeys: [],
doubleArr: [], // 存放双数组的数组
filterRows: [], // 存放拼接后的一维数组的变量
page: 1 // 页码
}
const rowSelection => {
selectedRowKeys: this.state.selectedRowKeys,
onChange: (selectedRowKeys, selectedRows) => {
const { doubleArr, page } = this.state
// 勾选生成二维数组
doubleArr[page ? page - 1 : 0] = selectedRows
// 这块扁平化成为一位数组,并过滤空
const filterRows = doubleArr.flat().filter(Boolean)
this.setState({
selectedRowKeys: selectedRowKeys,
filterRows: filterRows // 存放拼接好的一维数组
});
}
}
render() {
return (
<Table
rowKey={record => record.componentId}
rowSelection={rowSelection}
/>
)
}
}
16、日期的判断(根据天数判断)
// 获取两个日期相差的月跟天数
let month = moment('结束日期').diff(moment('开始日期'), 'moth')
let day = moment('结束日期').diff(moment('开始日期', 'day'))
// 获取两个日期之间的月份
const getMonth = (start, end) => {
let startData = moment(start)
let endData = moment(end)
const allYearMonth = []
while(endData > startData || startData.format('M') === endData.format('M')){
allYearMonth.push(startData.format('YYYY-MM'))
startData.add(1, 'month')
}
return allYearMonth
}
let list = getMonth('开始日期', '结束日期')
// 处理月份天数不同的情况
let thirtyOne = 0
let thirty = 0
list.map(ele => {
if(moment(ele).daysInMonth() === 31) {
thirtyOne++
} else if(moment(ele).daysInMonth() === 28) {
thirty = -3
}
})
// 最后一个月如果是31天的话需要减1
let num = 0
moment(list[list.length -1]).daysInMonth() === 31 ? num = -1 : ''
// 场景:结束时间需要在开始时间 2022-03-05 后3个月
// 相差的天数
let dayNum = 60 + thirtyOne + thirty + num
if(dayNum > day) {
console.log('满足')
}
17、深克隆
// 无法正确克隆undefined
function deepClone(obj = {}, map = new Map()) {
if (typeof obj !== "object") {
return obj;
}
console.log('--', map.get(obj), obj)
if (map.get(obj)) {
return map.get(obj);
}
let result = {};
// 初始化返回结果
if (
obj instanceof Array ||
// 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
Object.prototype.toString(obj) === "[object Array]"
) {
result = [];
}
// 防止循环引用
map.set(obj, result);
console.log('map',map)
for (const key in obj) {
// 保证 key 不是原型属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key], map);
}
}
// 返回结果
return result;
}
18、过滤数组中的空值跟空对象
function distinctArrObj(arr) {
let MyShow=(typeof arr!="object")? [arr] : arr //确保参数总是数组
for (let i = 0; i < MyShow.length; i++) {
if (MyShow[i] == null || MyShow[i] == "" || JSON.stringify(MyShow[i]) == "{}") {
MyShow.splice(i, 1);
i = i - 1;
}
}
return MyShow
}
console.log(distinctArrObj([{},{},1,0,2,null,undefined,{a:1}]))