前端开发常用工具与易错点(持续总结中)

302 阅读6分钟

引言

日常开发中,许多业务的特殊处理依赖于各种工具函数。令人头疼的:为了开发效率我们总是需要去查询工具函数。如下是个人开发遇到的工具函数封装总结。

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

  1. 创建项目

app.apifox.com/main

  1. 创建接口
  2. 定义接口数据类型

image.png

  1. 根据步骤3点击下方生成数据
  2. 开启云端接口(任何地方都能访问)

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
  })
}