JS Attention
push 返回的是数组增加后的长度!!!
对象名可变
setFieldsValue({ [`bank${index}`]: val });
判断是否空对象
Object.keys(obj);
JSON.stringify(obj) !== "{}";
还有
$.isEmptyObject(data2);
Object.getOwnPropertyNames(data3); // 和Object.keys
类似
关闭标签替换背景图
注意这里的background-size
属性是cover
,也就是让背景图撑满的关键属性。
.exit-btn {
position: fixed;
right: 30px;
top: 30px;
color: white;
background-image: url(../../../../../assets/closeNormal@2x.png);
&:hover {
background-image: url(../../../../../assets/closeHover@2x.png);
}
background-size: cover;
border-radius: 2px;
width: 50px;
height: 49px;
cursor: pointer;
}
获取鼠标点击 DOM 的类名
Event.currentTarget
Event 接口的只读属性 currentTarget 表示的,标识是当事件沿着 DOM 触发时事件的当前目标。它总是指向事件绑定的元素,而 Event.target 则是事件触发的元素。
Event.currentTarget - Web API 接口参考 | MDN (mozilla.org)
// 根据当前点击的选色器,取index
const clickWhichOne = (e: any) => {
const clickDom = e.currentTarget;
if (clickDom) {
// 得到当前类名 形如 ChartColorConfig-x
const rightClassName = clickDom.classList[2];
// 转换成数字
const name = rightClassName.split("ChartColorConfig-")[1];
setChooseIndex(name - 0);
}
};
splice 删除与 slice 保留
splice 移除 start 到 end 的词
slice 保留 start 到 end-1 的词
树的修改
JS 树结构操作:查找、遍历、筛选、树结构和列表结构相互转换 - 沐码小站 (wintc.top)
// 树的过滤方法
export function treeFilter(tree, func) {
// 使用map复制一下节点,避免修改到原树
return tree
.map((node) => ({ ...node }))
.filter((node) => {
node.children = node.children && treeFilter(node.children, func);
return func(node) || (node.children && node.children.length);
});
}
getGlobalChooseValues;
// 树的寻找
export function treeFind(tree, func, keyWord) {
for (const data of tree) {
if (func(data, keyWord)) return data;
if (data.children) {
const res = treeFind(data.children, func, keyWord);
if (res) return res;
}
}
return null;
}
enum 枚举类型
首字母大写
// 首字母大写 tableTrColor -> TableTrColor
function upperFirstWord(str: string) {
const wordList = str.split("");
const oneWord = wordList[0];
const otherWord = wordList.slice(1);
otherWord.unshift(oneWord.toUpperCase());
return otherWord.join("");
}
掘金更换动头
// 沸点界面F12 输入以下内容 回车发起 等待新头像审核通过即可拥有 动头!
var ajax = new XMLHttpRequest();
ajax.open("post", "https://juejin.cn/web/user/update/user_info/", true);
ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded");
// avatar更换为你想要的图片链接
ajax.send(
"aid=2608&avatar=https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c38e0574bf6949c28e3c75957a3e3893~tplv-k3u1fbpfcp-jj-mark:345:345:345:345:q75.awebp"
);
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
var c = ajax.responseText;
console.log(c);
}
};
文件下载
iframe 下载
function iframeDownload(url) {
try {
const elemIF = document.createElement('iframe');
elemIF.src = url;
elemIF.style.display = 'none';
document.body.appendChild(elemIF);
} catch (e) {
console.log('下载异常!');
}
}
```
> https://www.cnblogs.com/xiong950413/p/14209813.html
重定向下载
window.location.href = "www.baidu.com";
需要注意的一个问题
如果是在非 https 环境下,重定向到其他页面,会有一个报错提示
The file at 'http://192.168.208.163/OI9G84ddvg2-0aF_QWpYsxIqhgJCfYI9M5GnJ90ZXyWA4xMpHYP2bGFZw9-GJOqaIQDNEleKjF4G_5t9AmQN_XHuH7gKrzSjpImjNHK5xsJwjivlNU9Zs1YWAuv9yqSh.ofd' was loaded over an insecure connection. This file should be served over HTTPS
与代码和网页安全性相关。当浏览器尝试通过不安全的 HTTP 连接加载资源时,会出现此警告。要解决这个问题,你应该确保所有资源都通过安全的 HTTPS 连接提供。
https://juejin.cn/post/6964958019998187557
https 是如何加密的
个人网站配置 HTTPS 证书
关于 debounce
今天修 bug 的时候,遇到一个需用防抖的,但我发现即使用了debounce
方法,期内需要运行的fn
妹有运行,实际上就是对函数的不理解。
我的写法就是把他当作一个普通的箭头函数直接用了,实际上,当时debounce
返回的只是fn
,还需要debounce()
(即fn()
)使用。
也可以参照下面这种写法,直接运行debounce
。
btnGetResumeContainer.onclick = debounce(function () {
getResume(dataResume);
}, 3000);
//防抖debounce代码:
function debounce(fn, delay) {
var timer = null; // 创建一个标记用来存放定时器的返回值
return function (e) {
// 每当用户输入的时候把前一个 setTimeout clear 掉
if (timer !== null) {
clearTimeout(timeout);
}
// 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
timer = setTimeout(() => {
timer = null;
fn.apply(this, arguments);
}, delay);
};
}
https://segmentfault.com/q/1010000040099131
清除页面路由
const cleanQuery = () => {
// 获取当前URL
const url = window.location.href;
const isHaveQuery = url.includes("isJumpToBussinessVoucherTemplate");
if (isHaveQuery) {
// 创建URLSearchParams对象
const params = new URLSearchParams(url);
// 清除查询参数
params.delete("isJumpToBussinessVoucherTemplate"); // 假设要清除的查询参数名为queryParam1
// 跳转到新的URL
router.location("/setting/voucher-template");
}
};
科学计数法
Number 强转 出来的还是科学计数法
function getFullNum(num) {
// 处理非数字
if (isNaN(num)) return num;
// 处理不需要转换的数字
var str = "" + num;
if (!/e/i.test(str)) return num;
return num.toFixed(18).replace(/\.?0+$/, "");
}
https://juejin.cn/post/7194002669755695161
项目里用到的 util
// 科学计数法数字转为正常数字字符串
util.getFullNum = (num) => {
if (isNaN(num)) {
return num;
}
const str = "" + num;
if (!/e/i.test(str)) {
return num;
}
const fixed = ("" + num).match(/\d+$/)[0];
return Number(num).toFixed(fixed);
};
edge 中拓展不可用
找到隐私和服务中的Microsoft Defender Smartscreen
并关掉他
关于批量按顺序下载
参考文章
promise resolve reject
https://www.cnblogs.com/lunlunshiwo/p/8852984.html#4917337
reduce 按顺序调用
https://juejin.cn/post/7030625338065420302?searchId=202311041036275432B88F9F3A984960AA
demo
// import React from 'react';
import { Button } from "antd";
const Test = () => {
// 准备回调的次数 模拟待发送的文件数量
const waitForUpdateList = [1, 2, 3];
let resultList = [];
function simulateRequest(lastOneValue) {
// 这里传入的index - 1,是为了获取上一轮的返回值
console.log("lastOneValue", lastOneValue);
const time = 500;
return new Promise(function (resolve, reject) {
setTimeout(() => {
let num = Math.ceil(Math.random() * 10);
if (num > 5) {
// 上一轮值存在 且是res 就绑定在这一轮
if (lastOneValue !== undefined) {
resolve(num + lastOneValue);
} else {
resolve(num);
}
} else {
reject(num);
}
}, time);
});
}
// 循环顺序请求
function cycleRequest() {
console.log("新的一轮开始请求");
// 一个请求周期,这边为了模拟方便长度为 10,实际情况可能是 10000 或 99999 这样的
const arr = waitForUpdateList;
arr.reduce(async (last, _, index) => {
let lastOneValue;
await last;
if (index) {
lastOneValue = resultList[index - 1];
}
return simulateRequest(lastOneValue)
.then((res) => {
console.log("res", res);
resultList.push(res);
})
.catch((e) => {
console.log("e", e);
resultList.push(e);
})
.finally(() => {
// 达到边界 显示所有的promise结果
// 为什么不用useState? 会有延迟
if (index + 1 === arr.length) {
console.log("最终", resultList);
}
});
}, undefined);
}
// 启动
const everyThingDone = () => {
console.log("每轮重新开始,清空result");
resultList = [];
cycleRequest();
};
return <Button onClick={everyThingDone}>探索链式调用</Button>;
};
export default Test;
关于轮询 以获取数电文件为例
注意这里每次调用的时机,是在确保上次任务存在的情况下,再调用
async getBtnLoading() {
const { dispatch } = this.props;
try {
const res = await services.getNoDiskExtractStateForFile();
if (res) {
// 递归 如果当前还是任务中 就再次调用
this.times = setTimeout(() => {
if (this.times) {
this.getBtnLoading();
}
}, 10000);
}
} catch (e) {
// 丢到这里的如果是 执行失败\成功 需要更新横幅
// ...
}
}
如果是多个轮询同时调用,这里要将定时器的优先级提高!
// 置于当前/effect/index.js的顶级
let timer;
async getList(params) {
const { year, pageSize, current, risk, accountName = '' } = this.getState();
const deliver = { pageSize, current, year, accountName, risk, ...params };
try {
const res = await services.list(deliver);
const { list, executingAccountIdList, total } = res;
this.updateState({ dataSource: list, executingAccountIdList, total });
// 当前是否存在正在生成的列表 是的话 继续轮询
const isExistBuilding = executingAccountIdList && executingAccountIdList.length;
if (isExistBuilding) {
// 似乎这两步可以去掉一个?
timer && clearTimeout(timer);
timer = setTimeout(() => {
if (timer) {
// 当前定时器存在 就清除再开始轮询
clearTimeout(timer);
this.getList(params);
}
}, 10000);
}
} catch (e) {
// ...
}
}
简略策略模式优化 if else
// 客户列表
const currencyList = ["美元", "澳元", "泰铢", "欧元"];
// 汇率
const rateList = {
美元: 0.144881,
澳元: 0.216258,
泰铢: 5.3383,
欧元: 0.143649,
};
// 实际开发中,上述两个数据都是动态从后端获得的
const rateKeys = Object.keys(rateList);
// 策略容器
const stratagy = {};
// 为每种汇率添加一个key,并赋值为一个计算对应价格的方法
rateKeys.forEach((item) => {
// 传入 RMB 价格作为基数
stratagy[item] = (RMPPrice) => {
return RMPPrice * rateList[item];
};
});
function getAbroadPrice(RMBPrice = 100, target = "美元") {
return stratagy[target](RMBPrice);
}
getAbroadPrice(100, "美元"); // 14.481...
input 无法重上传图片
e.target.value=''
https://www.cnblogs.com/momo798/p/13926851.html
原生列表美化
<table>
<thead>
<tr>
<th class="risk-level">风险等级</th>
<th>风险明细</th>
</tr>
<tr>
<td>高</td>
<td>往来款项存在长期挂账</td>
</tr>
<tr>
<td>低</td>
<td>广告和业务宣传费累计发生85,302,23,超过营业收入的15%</td>
</tr>
</thead>
</table>
table {
margin-top: 1rem;
width: 100%;
border: 1px #e6e7e8 solid;
border-collapse: collapse;
text-align: center;
}
td,
th {
border: 1px solid #e6e7e8;
}
th {
background: #e9ecf0;
border: 1px solid #dcdddf;
}
thead {
height: 40px;
background-color: #e9ecf0;
font-family: MicrosoftYaHei-Bold;
font-size: 18px;
color: #3f3f3f;
letter-spacing: 0.9px;
text-align: center;
font-weight: 700;
}
tr {
height: 4rem;
background-color: #fff;
}
td {
font-family: MicrosoftYaHei;
font-size: 18px;
color: #3f3f3f;
letter-spacing: 0.9px;
font-weight: 400;
}
/* 注意 04 05 页中的数字项是右对齐 写在了单独样式里面
通用的是左对齐
*/
td:not(:first-child) {
text-align: left;
padding-left: 1rem;
}
/* 奇数项添加背景色 */
tr:nth-child(odd) {
background-color: #f8fafb;
}
按钮禁用样式 不触发点击动作
.delete-disabled {
color: #c8c9cc;
&:hover {
pointer-events: none;
}
}
关于文件流下载
https://juejin.cn/post/7027431356443394084
https://juejin.cn/post/6878912072780873742
// 使用
// downloadType 0 预览 1 下载
const deliver = { year, quarters, accountIdList, downloadType: 1 };
const url = '/instead/v2/customer/financial/report/download.do';
const res = await axios({
method: 'post',
url,
responseType: 'blob', // 必须,服务器返回的数据类型
headers: {
'Content-Type': 'application/json',
},
data: deliver,
});
// 下载正常处理
downloadFileByBlod(res, fileName);
```
```js
import { message } from "antd";
// 文件流下载
export const downloadFileByBlod = (res, fileName) => {
// 兼容ie11
if (window.navigator.msSaveOrOpenBlob) {
try {
const blobObject = new Blob([res.data]);
window.navigator.msSaveOrOpenBlob(blobObject, fileName);
} catch (e) {
console.log(e);
}
return;
}
// a标签实现下载
const curUrl = window.URL || window.webkitURL || window.moxURL;
const link = document.createElement("a");
link.style.display = "none";
// 创建下载链接,将文件流转化为一个文件地址
link.href = curUrl.createObjectURL(new Blob([res.data]));
link.setAttribute("download", fileName); // 下载的文件名
document.body.appendChild(link);
link.click(); // 触发点击事件执行下载
document.body.removeChild(link); // 下载完成进行释放
};
// 根据文件名后缀获取当前文件类型
export const getLastFileTypeByName = (value) => {
const dotArray = value.split(".");
const lastDotArray = dotArray[dotArray.length - 1];
return lastDotArray;
};
export const getFileTypeBySource = (file, legitTypeList) => {
// 注意这里的类型判断一定要从文件名读取! ios 无 file.type!!!
const exactFileValue = file.name;
const lastFileTypeByName = getLastFileTypeByName(exactFileValue);
// 实测移动端 不走相册 直接选图片文件 尾缀为大写PNG 这里多加一层逻辑
// ↑ 从H5抄过来的 问题不大
// 这里全部转换成小写 进入匹配
let isLegitType = false;
isLegitType = legitTypeList.some((key) =>
lastFileTypeByName.toLowerCase().includes(key)
);
return isLegitType;
};
// 1 KB = 1024 B
// 转换文件大小为可读单位
export const getFileSize = (fileSize) => {
let result = "";
if (fileSize >= 1073741824) {
// B => GB
result =
fileSize % 1073741824 === 0
? `${fileSize / 1073741824}G`
: `${Math.trunc(fileSize / 1073741824)}G`;
} else if (fileSize >= 1048576) {
// B => MB
result =
fileSize % 1048576 === 0
? `${fileSize / 1048576}MB`
: `${Math.trunc(fileSize / 1048576)}MB`;
} else if (fileSize >= 1024) {
// B => KB
result =
fileSize % 1024 === 0
? `${fileSize / 1024}KB`
: `${Math.trunc(fileSize / 1024)}KB`;
} else if (fileSize !== undefined) {
result = `${fileSize}B`;
}
return result;
};
// 上传文件前置校验 文件类型 文件大小
export const beforeUpload = (files, fileSizeLimit, legTypeList) => {
const readableMaxFileSize = getFileSize(fileSizeLimit);
const fileSupportTypeText = legTypeList.join("、");
// if (!(files && files.length)) {
// message.error(`请添加${kind}`);
// return false;
// }
let flag = true;
// eslint-disable-next-line consistent-return
files.forEach((file) => {
const isLegFileType = getFileTypeBySource(file, legTypeList);
if (!isLegFileType) {
message.error(`文件支持格式: ${fileSupportTypeText}`);
flag = false;
}
if (file.size > fileSizeLimit) {
message.error(`文件最大支持${readableMaxFileSize}`);
flag = false;
}
});
return flag;
};
关于安卓滚动条样式
一个关键样式
overflow:overlay
悬浮在上方,目前只有移动端支持webkit
内核的可用,PC 上已废弃
https://zhuanlan.zhihu.com/p/88347981
https://zhuanlan.zhihu.com/p/88347981
使用 JS 直接获取子元素
https://www.coder.work/article/5383247
JQ 遍历元素方法
https://www.runoob.com/jquery/jquery-ref-traversing.html
禁止输入 emoji
请注意,由于 Emoji 字符的范围广泛且可能随时间变化,无法保证完全过滤所有的 Emoji 字符。因此,如果需要更严格的过滤或更全面的 Emoji 支持,可能需要使用专门的 Emoji 过滤库或更复杂的验证逻辑。
https://segmentfault.com/q/1010000007329875
JavaScript 下含有 emoji 字符串的处理
PHP 开发中涉及到 emoji 表情的几种处理方法
// 过滤掉emoji表情
// 基本思想就是遍历字符串中的每个字符,如果该字符的长度为4个字节,就将其删除。
function filterEmoji($str)
{
$str = preg_replace_callback(
'/./u',
function (array $match) {
return strlen($match[0]) >= 4 ? '' : $match[0];
},
$str);
return $str;
}
input 的聚焦动作无效 autofocus
https://juejin.cn/post/7034707796545241095
react 中要用autoFocus
moment 对象操作的影响去除
moment()再包裹 生成新的对象
npm yarn pnpm 的区别
https://zhuanlan.zhihu.com/p/494076214
本文暂时没有评论,来添加一个吧(●'◡'●)