引言
日常开发中,许多业务的特殊处理依赖于各种工具函数。令人头疼的:为了开发效率我们总是需要去查询工具函数。如下是个人开发遇到的工具函数封装总结。
1.价格逗号分割
const formatMoney = num => num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
2.日期处理
moment插件
0.下载导入
npm i moment
import moment from "moment"
1. 获取日期
moment()//当前日期
moment(123131)//指定日期
moment(new Date())//通过原生js获取,并转换成momennt日期
2. 获取日期的年月日等
moment().get('year')
moment().get('month')
3.格式化日期字符串
moment().format('YYYY-MM-DD HH-MM-SS')
4. 日期操作
moment().add(1,'d') //多1天
moment().subtract(1,'y')//少1年
dayjs
0.下载导入
npm i dayjs
import * as dayjs from "dayjs"
使用
dayjs的使用和moment一模一样啊,真踏马爽。
3.获取路由参数
URLSearchParams:可以十分方便的获取页面url传递的参数信息。传递的参数通常是location的search部分(?xxx=xxx)
1.new URLSearchParams(search) 构造函数
2. get(str) 获取对应参数的value值
3. has(str) 判断是否存在某个key
//http://www.baidu.com?name=dzp
let urls = new URLSearchParams(location.search)
console.log(urls.has('name'))//true
console.log(urls.get('name')//dzp
4.吸顶效果
指定某盒子在页面滚动到指定位置时,出现吸顶效果。同时使用节流对吸顶进行优化处理。
import {useEffect,useState} from "react";
import _ from "lodash";
import './App.css';
function App() {
const [fixed,setFixed] = useState(false);
//滚动距离判断
const scrollJudge = () => {
if(document.documentElement.scrollTop>300) {
setFixed(true);
}else {
setFixed(false);
}
}
useEffect(()=>{
//全局监听滚动事件
window.addEventListener('scroll',_.throttle(scrollJudge,500))
return ()=>{
window.removeEventListener('scroll',_.throttle(scrollJudge,500))
}
},[])
return (
<div className="App">
<div className={fixed?'fixed':'header'}>header</div>
</div>
);
}
export default App;
5.移入移出事件(有巨坑)
移入移出事件必须得重视,这里面有两类相似的api,当你使用时会发现很容易出现错误。
移入事件
1. onmouseover:移入事件(bug点:如果当前盒子存在子元素,移入子元素也会触发事件)
2. onmouseenter:移入事件(建议以后就用它,子元素移入不会受影响)
移出事件
1. onmouseout:移出事件(bug点:如果当前盒子存在子元素,移出子元素也会触发事件)
2. onmouseleave:移出事件(建议以后就用它,子元素移出不会受影响)
6.禁止页面滚动
开发中经常遇到需要禁止浏览器滚动的问题,例如在弹窗出现时我们需要禁止浏览器任意滚动。
//visible判断是否需要禁止滚动
if (visible) {
document.documentElement.style.overflow = 'hidden';
} else {
document.documentElement.style.overflow = 'scroll';
}
7. 长背景图中间内容适配不同屏幕尺寸
在开发网站banner背景图时,产品要求banner图在不同屏幕像素下,图片中间核心内容始终要显示给用户。 如何解决这个问题?
方案
根据需求,我们需要在屏幕不同像素下将背景图的中间核心内容展示出来,那么我们可以使用背景图定位属性,将背景图中间部分定位到盒子上就可以。
div{
background-image: url(xxx);
background-position: center;
}
8.网页宽高与滚动相关
1.获取网页当前宽高
window.innerWidth--宽
window.innerHeight--高
2.获取网页滚动出去的距离
document.documentElement.scrollTop
3.设置网页滚动到某个位置
window.scrollTo(x,y);
9.z-index设置
z-index表示层叠上下文,它只能设置在脱离标准流元素身上。如相对定位,绝对定位,浮动等是有效的。z-index越大其显示在界面上方。
10. 设置指定范围的随机数
const randomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
11.copy复制功能
import React, { useState } from 'react';
const CopyToClipboard = ({ text }) => {
const [copied, setCopied] = useState(false);
const handleCopy = () => {
navigator.clipboard.writeText(text).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000); // 2秒后重置状态
}).catch(err => {
console.error('Failed to copy text: ', err);
});
};
return (
<div>
<button onClick={handleCopy}>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
);
};
export default CopyToClipboard;
12.eslint插件在vscode的全局配置json
"eslint.enable": true,
"eslint.run": "onType",
"eslint.options": {
"extensions": [
".js",
".vue",
".jsx",
".tsx"
]
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
13.target与currentTarget区别
target指触发事件的元素
currentTarget指绑定事件的元素
currentTarget的范围大于target
<div class="target">
<div></div>
</div>
let oBox = document.querySelector('.target');
oBox.onclick = function(e) {
console.log('click');
console.log(e.target)//触发事件的元素。当前点击的元素本身 <div></div>
console.log(e.currentTarget)//绑定事件的元素 <div class='target'>...</div>
}
14.前端mock工具
apifox
- 创建项目
- 创建接口
- 定义接口数据类型
- 根据步骤3点击下方生成数据
- 开启云端接口(任何地方都能访问)
15.Form初始化表单问题
以antd为例子,给Form表单初始化值方式
不具备响应式的初始化
下面方式给表单初始化值时,数据不具备响应式(数据如果更改,表单内容不变化)
<Form initialValues={password:'123'}>
<Form.Item name="password" label="Password" >
<Input.Password />
</Form.Item>
</Form>
具备响应式的初始化
直接通过form对象操作方法可以让数据具备响应式。
const [form] = Form.useForm();
form.setFieldValue({password:'123})
<Form form={form} initialValues={password:'123'}>
<Form.Item name="password" label="Password" >
<Input.Password />
</Form.Item>
</Form>
16.RangePick组件禁止选择某个日期范围
<RangePicker
disabledDate={(e:any)=>{
return e && e < Date.now()
}}
/>
17.axios请求饶过baseUrl
1.get请求添加参数
-
参数1:string-url
-
参数2:object-数据与其他配置项组成的一个对象
axios.get('/api/getInfo', {params:{name:'dzp',age:24}) .then(msg=>{ console.log(msg) })
2.post请求添加参数
-
参数1:string-url地址
-
参数2:object-数据
-
参数3:object-所有配置项
axios.post('/api/getInfo', {name:'dzp',age:24}) .then(msg=>{ console.log(msg) })
3.添加认证信息
withCredentials设置true,添加身份认证信息到请求头
axios.get(
'/api/getInfo',
{params:{name:'dzp'},withCredentials:true})
.then(msg=>{
console.log(msg)
})
axios.post(
'/api/getInfo',
{name:'dzp'},
{withCredentials:true}
)
.then(msg=>{
console.log(msg)
})
4.绕过封装axios的baseurl
axios.get(
'/api/getInfo',
{params:{name:'dzp'},withCredentials:true,baseURL:'www.baidu.com'})
.then(msg=>{
console.log(msg)
})
axios.post(
'/api/getInfo',
{name:'dzp'},
{withCredentials:true,baseURL:'www.baidu.com'}
)
.then(msg=>{
console.log(msg)
})
18 数值计算工具
js在进行小数计算时存在精度丢失问题,因此我们在日常开发中必须借助第三方工具进行计算。
安装
npm i numeral
使用
import numeral from "numeral"
const init = numeral(0)//初始化
init.add(1)//add
19. 域名各属性获取
一个url域名的组成由以下几部分组成
协议+域名+路径+参数(哈希值)
http://www.baicu.com/a/b/c?name=dzp
- protocol: http/https
- host: www.baidu.com
- pathname: /a/b/c
- search: name=dzp
- hash: #后面的
获取各个部分的参数
let target = new URL('http://www.baicu.com/a/b/c?name=dzp')
target.protocol
target.host
target.pathname
target.search
target.hash
20. 错误处理标准设计
try catch发生错误的地方赋值操作不会完成
let res
try{
res = 1+adada
}catch(e){
message.error('error')
}
if(res) {
//未出错,处理后续的逻辑
}
21. css文本换行
word-break: break-all;
22. 快速交换两个变量值
交换两个变量值
let a = 1,b = 2
[a,b] = [b,a]
console.log(a,b) //2,1
交换数组中两个值
let a = [1,2,3]
[a[0],a[1]] = [a[1],a[0]]
console.log(a) //[2,1,3]
23. js路由跳转
histrory路由
window.location.href='adada'
hash路由
window.location.hash='xx'
24. 表单上传包含图片
前端
import React from 'react';
import { Form, Input, Button, Upload, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import axios from "@/utils/net.ts"
const FormWithUpload = () => {
let filePath = ''
/**表单提交接口 */
const onFinish = async(values) => {
const {name,description} = values
axios({url:'/update_info',method:'post',data:{name,description,filePath}})
}
/**图片上传接口 */
const uploadProps = {
action: 'http://localhost:9999/upload',
name: 'image',//name必须和后端统一
headers: {
authorization: 'authorization-text',
},
onChange(info) {
if (info.file.status !== 'uploading') {
console.log('deal')
}
if (info.file.status === 'done') {
filePath = info.fileList[0].response
message.success(`file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
};
return (
<Form
name="form_with_upload"
onFinish={onFinish}
>
<Form.Item
name="name"
label="Name"
rules={[
{
required: true,
message: 'Please input your name!',
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="description"
label="Description"
rules={[
{
required: true,
message: 'Please input your name!',
},
]}
>
<Input.TextArea />
</Form.Item>
<Form.Item
name="images"
label="Image"
rules={[
{
required: true,
message: 'Please input your name!',
},
]}
>
<Upload {...uploadProps} listType="picture">
<Button icon={<UploadOutlined />}>Upload</Button>
</Upload>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
export default FormWithUpload;
后端
const express = require('express')
const userRouter = require('./router/user/index')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const multer = require('multer');
const fs = require("fs")
const path = require("path")
const db_connect = require('./db/connect');
const privateKey = 'da1213a'
const app = express()
global.connect = null
db_connect()
app.use(express.json())
app.use('/user',userRouter)
app.use(cors())
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// 设置文件上传的目标目录
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
// 设置文件名
cb(null, Date.now()+file.originalname);
}
});
const upload = multer({ storage: storage });
/**
* 图片上传接口
*/
app.post('/upload',upload.single('image'),(req,res)=>{
const {filename} = req.file
res.send(filename)
})
/* 表单接口 */
app.post('/update_info',(req,res)=>{
const { filePath,name,description } = req.body
console.log(filePath,name,description)
res.send('updata_info ok')
})
app.listen(9999,()=>{
console.log('9999 listen ok')
})
25. ??和??=
??
1.语法:a??b
如果a是null或者undefined,则返回b,否则返回a
2.例子
1 ?? 2//1
null ?? 3 //3
undefined ?? {} //{}
0 ?? 1 //0
3.与||区别
||和??常用来添加默认值,||针对所有空的情况,而??只针对unll和undefined
a = a || 1
//等价于
if(a===0 || a==='' || a===null || a=== undefined || a===0){
a = 1
}
a = a ?? 1
//等价于
if(a===null || a===undefined){
a = 1
}
??=
1.语法:a ??= b
当且仅当a是null或者undefined时,a=b。
2. 例子
a = 1,b = 2
a ??= b //a = 1
a = null,b = 2
a ?? = b //a = 2
a = undefined,b = 2
a ?? = b //a = 2
26. !!(常用)
!!可以将任何数据类型转换为boolean类型
!!0 false
!!'' false
!! null false
!!undefined false
!! nan false
27. useCallback
如果react发现绑定的函数不执行,或者只执行1次,那99%概率去看看useCallback依赖问题。
28. axios不想使用全局配置
现象:有些场景我们并不想使用axios的全局配置,而是想单独配置请求头,跨越设置等。
方法:单独封装本次请求的axios配置
import axios from 'axios'
const customAxios = axios.create({
withCredentials: false, // 单独配置
})
export const getMisList = (keyword = '', loop = 10) => {
const queryString = new URLSearchParams({ keyword, loop }).toString()
const url = `https://serverless.sankuai.com/org-http/search?${queryString}`
return customAxios.get(url).then(res => {
return res?.data
})
}