🎈 perf(优化购物车):

This commit is contained in:
czm 2022-11-24 13:51:42 +08:00
parent c3a6e017f0
commit 566f429051
5 changed files with 208 additions and 208 deletions

View File

@ -0,0 +1,136 @@
import { Input, View } from '@tarojs/components'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import Big from 'big.js'
import styles from './index.module.scss'
type params = {
minNum?: number //最小值
maxNum?: number //最大值
step?: number //步长
defaultNum?: number //默认值
digits?: number //多少位小数
onChange?: (val: number) => void
onBlue?: (val: number) => void //失去焦点触发
onClickBtn?: (val: number) => void
unit?: string
disable?: true | false //是否禁用
}
export default memo((props: params) => {
return <Counter {...props}></Counter>
})
function areEqual(prevProps: params, nextProps: params) {
return (
prevProps.defaultNum == nextProps.defaultNum &&
prevProps.unit == nextProps.unit &&
prevProps.minNum == nextProps.minNum &&
prevProps.maxNum == nextProps.maxNum &&
prevProps.step == nextProps.step &&
prevProps.digits == nextProps.digits
)
}
const Counter = memo((props: params) => {
let { minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '', disable = false } = props
const [value, setValue] = useState<any>({ count: defaultNum })
// useEffect(() => {
// setValue({ count: defaultNum })
// }, [defaultNum])
console.log('1231231231231212')
const onPlus = () => {
if (disable) return false
let { count } = value
let num_res = Big(count).add(step).toNumber()
num_res = num_res >= maxNum ? maxNum : num_res
num_res = formatDigits(num_res)
// setValue({ ...value, count: num_res })
onChange?.(parseFloat(num_res))
onClickBtn?.(parseFloat(num_res))
}
const minus = () => {
if (disable) return false
let { count } = value
let num_res = Big(count).minus(step).toNumber()
num_res = num_res < minNum ? minNum : num_res
// setValue({ ...value, count: num_res })
onChange?.(parseFloat(num_res))
onClickBtn?.(parseFloat(num_res))
}
//保留小数
const formatDigits = (num) => {
num = num + ''
if (num.includes('.') && digits > 0) {
console.log('num::', num.includes('.'))
let res = num.split('.')
let last_num = res[1].substr(0, digits)
return res[0] + '.' + last_num
}
return parseFloat(num)
}
//检查数据
const checkData = (val) => {
let num = parseFloat(val)
if (num > maxNum) return maxNum
if (num < minNum) return minNum
return val
}
const onInputEven = (e) => {
// let res = e.detail.value
// if (res === '') {
// // setValue({ ...value, count: minNum })
// onChange?.(minNum)
// } else if (!isNaN(Number(res))) {
// let count = formatDigits(res)
// count = checkData(count)
// // setValue({ ...value, count })
// onChange?.(parseFloat(count as string))
// } else {
// let num = parseFloat(res)
// if (!isNaN(num)) {
// let count = formatDigits(num)
// count = checkData(count)
// // setValue({ ...value, count })
// onChange?.(count as number)
// } else {
// // setValue({ ...value, count: defaultNum })
// onChange?.(defaultNum)
// }
// }
}
const onBluerEven = (e) => {
let num = parseFloat(e.detail.value)
if (!isNaN(num)) {
let count = formatDigits(num)
count = checkData(count)
// setValue({ ...value, count })
onBlue?.(count as number)
} else {
// setValue({ ...value, count: defaultNum })
onBlue?.(minNum)
}
}
return (
<View className={styles.main}>
<View className={styles.reduce} onClick={() => minus()}>
-
</View>
<View className={styles.input}>
<Input
value={String(props.defaultNum)}
onInput={onInputEven}
onBlur={onBluerEven}
type='digit'
disabled={disable}
alwaysEmbed={true}
cursorSpacing={150}
/>
<View className={styles.unit}>{unit}</View>
</View>
<View className={styles.plus} onClick={() => onPlus()}>
+
</View>
</View>
)
}, areEqual)

View File

@ -1,46 +1,44 @@
.main {
.main{ display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.plus {
color: $color_main;
width: 46px;
height: 46px;
text-align: center;
line-height: 43px;
font-size: 50px;
background-color: $color_main;
color: #fff;
border-radius: 8px;
}
.reduce {
font-size: 50px;
width: 46px;
height: 46px;
text-align: center;
line-height: 43px;
color: #007aff;
}
.input {
display: flex; display: flex;
align-items: center; align-items: flex-end;
justify-content: space-between; background-color: #fff;
width: 100%; padding: 5px 10px;
.plus{ box-sizing: border-box;
color: $color_main; width: 106px;
width: 46px; border-radius: 10px;
height: 46px; input {
text-align: center; font-size: $font_size_medium;
line-height: 43px; // text-align: right;
font-size: 50px; padding-right: 10px;
background-color: $color_main;
color: #fff;
border-radius: 8px;
}
.reduce {
font-size: 50px;
width: 46px;
height: 46px;
text-align: center;
line-height: 43px;
color:#007AFF;
}
.input{
display: flex;
align-items: flex-end;
background-color: #fff;
padding: 5px 10px;
box-sizing: border-box;
width: 106px;
border-radius: 10px;
input{
font-size: $font_size_medium;
text-align: right;
padding-right: 10px;
}
}
.unit{
font-size: $font_size_min;
color: $color_font_two;
} }
}
.unit {
font-size: $font_size_min;
color: $color_font_two;
}
} }

View File

@ -1,5 +1,5 @@
import { Input, View } from '@tarojs/components' import { Input, View } from '@tarojs/components'
import { useEffect, useMemo, useRef, useState } from 'react' import { memo, useEffect, useMemo, useRef, useState } from 'react'
import Big from 'big.js' import Big from 'big.js'
import styles from './index.module.scss' import styles from './index.module.scss'
type params = { type params = {
@ -12,14 +12,21 @@ type params = {
onBlue?: (val: number) => void //失去焦点触发 onBlue?: (val: number) => void //失去焦点触发
onClickBtn?: (val: number) => void onClickBtn?: (val: number) => void
unit?: string unit?: string
disable?: true | false //是否禁用 disabled?: true | false //是否禁用
} }
export default ({ minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '', disable = false }: params) => { export default memo((props: params) => {
const [value, setValue] = useState<any>({ count: defaultNum }) return <Counter {...props}></Counter>
})
const Counter = memo((props: params) => {
let { minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '', disabled = false } = props
const [value, setValue] = useState<any>({ count: defaultNum })
useEffect(() => {
setValue({ count: defaultNum })
}, [defaultNum])
const onPlus = () => { const onPlus = () => {
if (disable) return false if (disabled) return false
let { count } = value let count = value.count
let num_res = Big(count).add(step).toNumber() let num_res = Big(count).add(step).toNumber()
num_res = num_res >= maxNum ? maxNum : num_res num_res = num_res >= maxNum ? maxNum : num_res
num_res = formatDigits(num_res) num_res = formatDigits(num_res)
@ -28,8 +35,8 @@ export default ({ minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum =
onClickBtn?.(parseFloat(num_res)) onClickBtn?.(parseFloat(num_res))
} }
const minus = () => { const minus = () => {
if (disable) return false if (disabled) return false
let { count } = value let count = value.count
let num_res = Big(count).minus(step).toNumber() let num_res = Big(count).minus(step).toNumber()
num_res = num_res < minNum ? minNum : num_res num_res = num_res < minNum ? minNum : num_res
setValue({ ...value, count: num_res }) setValue({ ...value, count: num_res })
@ -60,37 +67,40 @@ export default ({ minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum =
const onInputEven = (e) => { const onInputEven = (e) => {
let res = e.detail.value let res = e.detail.value
if (res === '') { if (res === '') {
setValue({ ...value, count: minNum }) // setValue({ ...value, count: minNum })
onChange?.(minNum) onChange?.(minNum)
} else if (!isNaN(Number(res))) { } else if (!isNaN(Number(res))) {
let count = formatDigits(res) let count = formatDigits(res)
count = checkData(count) count = checkData(count)
setValue({ ...value, count }) // setValue({ ...value, count })
onChange?.(parseFloat(count as string)) onChange?.(parseFloat(count as string))
} else { } else {
let num = parseFloat(res) let num = parseFloat(res)
if (!isNaN(num)) { if (!isNaN(num)) {
let count = formatDigits(num) let count = formatDigits(num)
count = checkData(count) count = checkData(count)
setValue({ ...value, count }) // setValue({ ...value, count })
onChange?.(count as number) onChange?.(count as number)
} else { } else {
setValue({ ...value, count: defaultNum }) // setValue({ ...value, count: defaultNum })
onChange?.(defaultNum) onChange?.(defaultNum)
} }
} }
} }
const onBluerEven = () => { const onBluerEven = (e) => {
let num = parseFloat(value.count) let num = parseFloat(e.detail.value)
if (!isNaN(num)) { if (e.detail.value == '') {
onBlue?.(minNum)
setValue({ count: minNum })
} else if (!isNaN(num)) {
let count = formatDigits(num) let count = formatDigits(num)
count = checkData(count) count = checkData(count)
setValue({ ...value, count }) setValue({ count })
onBlue?.(count as number) onBlue?.(count as number)
} else { } else {
setValue({ ...value, count: defaultNum }) setValue({ count: minNum })
onBlue?.(defaultNum) onBlue?.(minNum)
} }
} }
return ( return (
@ -99,7 +109,7 @@ export default ({ minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum =
- -
</View> </View>
<View className={styles.input}> <View className={styles.input}>
<Input value={String(value.count)} onInput={onInputEven} onBlur={onBluerEven} type='digit' disabled={disable} alwaysEmbed={true} cursorSpacing={150} /> <Input value={String(value.count)} onInput={onInputEven} onBlur={onBluerEven} disabled={disabled} alwaysEmbed={true} cursorSpacing={150} />
<View className={styles.unit}>{unit}</View> <View className={styles.unit}>{unit}</View>
</View> </View>
<View className={styles.plus} onClick={() => onPlus()}> <View className={styles.plus} onClick={() => onPlus()}>
@ -107,4 +117,4 @@ export default ({ minNum = 0, maxNum = 10000, step = 1, digits = 0, defaultNum =
</View> </View>
</View> </View>
) )
} })

View File

@ -1,37 +0,0 @@
.main{
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.reduce, .plus{
font-size: $font_size_big;
color: $color_main;
width: 46px;
height: 46px;
display: flex;
align-items: center;
justify-content:center;
font-size: 50px;
background-color: $color_main;
color: #fff;
border-radius: 8px;
}
.input{
display: flex;
align-items: flex-end;
background-color: #fff;
padding: 5px 10px;
box-sizing: border-box;
width: 106px;
border-radius: 10px;
}
input{
font-size: $font_size_medium;
}
.unit{
font-size: $font_size_min;
color: $color_font_two;
}
}

View File

@ -1,107 +0,0 @@
import { Input, View } from '@tarojs/components'
import { useEffect, useMemo, useRef, useState } from 'react'
import Big from 'big.js'
import styles from './index.module.scss'
type params = {
minNum?: number //最小值
maxNum?: number //最大值
step?: number //步长
defaultNum?: number //默认值
digits?: number //多少位小数
onChange?: (val: number) => void
onBlue?: (val: number) => void //失去焦点触发
onClickBtn?: (val: number) => void
unit?: string
}
export default ({ minNum = 0, maxNum = 100, step = 1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = '' }: params) => {
const [value, setValue] = useState<any>({ count: defaultNum })
const onPlus = () => {
let { count } = value
let num_res = Big(count).add(step).toNumber()
num_res = num_res >= maxNum ? maxNum : num_res
num_res = formatDigits(num_res)
setValue({ ...value, count: num_res })
onChange?.(parseFloat(num_res))
onClickBtn?.(parseFloat(num_res))
}
const minus = () => {
let { count } = value
let num_res = Big(count).minus(step).toNumber()
num_res = num_res < minNum ? 0 : num_res
setValue({ ...value, count: num_res })
onChange?.(parseFloat(num_res))
onClickBtn?.(parseFloat(num_res))
}
//保留小数
const formatDigits = (num) => {
num = num + ''
if (num.includes('.') && digits > 0) {
console.log('num::', num.includes('.'))
let res = num.split('.')
let last_num = res[1].substr(0, digits)
return res[0] + '.' + last_num
}
return parseFloat(num)
}
//检查数据
const checkData = (val) => {
let num = parseFloat(val)
if (num > maxNum) return maxNum
if (num < minNum) return minNum
return val
}
const onInputEven = (e) => {
let res = e.detail.value
if (res === '') {
setValue({ ...value, count: minNum })
onChange?.(minNum)
} else if (!isNaN(Number(res))) {
let count = formatDigits(res)
count = checkData(count)
setValue({ ...value, count })
onChange?.(parseFloat(count as string))
} else {
let num = parseFloat(res)
if (!isNaN(num)) {
let count = formatDigits(num)
count = checkData(count)
setValue({ ...value, count })
onChange?.(count as number)
} else {
setValue({ ...value, count: defaultNum })
onChange?.(defaultNum)
}
}
}
const onBluerEven = () => {
let num = parseFloat(value.count)
if (!isNaN(num)) {
let count = formatDigits(num)
count = checkData(count)
setValue({ ...value, count })
onBlue?.(count as number)
} else {
setValue({ ...value, count: defaultNum })
onBlue?.(defaultNum)
}
}
return (
<View className={styles.main}>
<View className={styles.reduce} onClick={() => minus()}>
-
</View>
<View className={styles.input}>
<Input value={String(value.count)} onInput={onInputEven} onBlur={onBluerEven} type='digit' alwaysEmbed={true} cursorSpacing={150} />
<View className={styles.unit}>{unit}</View>
</View>
<View className={styles.plus} onClick={() => onPlus()}>
+
</View>
</View>
)
}