🎈 perf(首页优化页面基本完成,未对接):

This commit is contained in:
czm 2022-11-22 21:05:50 +08:00
parent cddb3b93e6
commit 03df61b555
9 changed files with 424 additions and 162 deletions

View File

@ -15,7 +15,7 @@
width: 100%; width: 100%;
input { input {
font-size: 27px; font-size: 27px;
background: #eee; background: #f6f7f9;
width: 100%; width: 100%;
height: 72px; height: 72px;
border-radius: 50px; border-radius: 50px;

View File

@ -2,7 +2,7 @@
display: flex; display: flex;
height: 100%; height: 100%;
.sideBar_select { .sideBar_select {
width: 150px; width: 160px;
height: 100%; height: 100%;
background-color: #eaeaea; background-color: #eaeaea;
border-radius: 0 10px 10px 0; border-radius: 0 10px 10px 0;
@ -16,30 +16,39 @@
height: 100px; height: 100px;
width: 100%; width: 100%;
font-size: $font_size; font-size: $font_size;
color: #727272; color: rgba(0, 0, 0, 0.6);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-weight: 400; font-weight: 400;
.title_con { .title_con {
width: 74px; padding: 0 20px;
text-align: center;
// width: 74px;
@include common_ellipsis($params: 4); @include common_ellipsis($params: 4);
} }
} }
.sideBar_select_title_select { .sideBar_select_title_select {
background-color: #007AFF; background-color: #007aff;
color: #fff; color: #fff;
border-radius: 0px 14px 14px 0px; border-radius: 0px 14px 14px 0px;
} }
} }
.sideBar_con { .sideBar_con {
flex: 1; flex: 1;
min-width: 0;
position: relative;
padding-top: 90px;
.product_class {
width: 100%;
position: absolute;
top: 0;
z-index: 999;
}
.sideBar_con_scroll { .sideBar_con_scroll {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }

View File

@ -1,27 +1,29 @@
import { ScrollView, View } from "@tarojs/components" import { ScrollView, View } from '@tarojs/components'
import React, { memo, ReactNode, useEffect, useRef, useState } from "react" import React, { memo, ReactNode, useEffect, useRef, useState } from 'react'
import styles from "./index.module.scss" import styles from './index.module.scss'
import classnames from "classnames"; import classnames from 'classnames'
import Taro, { useReady } from "@tarojs/taro"; import Taro, { useReady } from '@tarojs/taro'
import InfiniteScroll, {StatusParam} from "../infiniteScroll"; import InfiniteScroll, { StatusParam } from '../infiniteScroll'
import LoadingCard from "../loadingCard"; import LoadingCard from '../loadingCard'
import ProductClass from '@/pages/index/components/productClass'
type Params = { type Params = {
list?: any[], list?: any[]
defaultValue?: number|string, defaultValue?: number | string
children?: ReactNode, children?: ReactNode
height?: string, height?: string
heightItem?: number, heightItem?: number
sideBarOnClick?: (val:any) => void, sideBarOnClick?: (val: any) => void
refresherTriggered?: true|false, refresherTriggered?: true | false
selfOnRefresherRefresh?: () => void selfOnRefresherRefresh?: () => void
selfOnScrolltolower?: () => void, selfOnScrolltolower?: () => void
hasMore?: true|false, hasMore?: true | false
statusMore?: StatusParam statusMore?: StatusParam
} }
export default memo(({list = [], export default memo(
({
list = [],
defaultValue = 0, defaultValue = 0,
height = '100vh', height = '100vh',
sideBarOnClick, sideBarOnClick,
@ -31,9 +33,8 @@ export default memo(({list = [],
selfOnRefresherRefresh, selfOnRefresherRefresh,
selfOnScrolltolower, selfOnScrolltolower,
hasMore = true, hasMore = true,
statusMore = 0 statusMore = 0,
}: Params) => { }: Params) => {
let num_half = useRef(0) let num_half = useRef(0)
const [selected, setSelected] = useState(defaultValue) const [selected, setSelected] = useState(defaultValue)
@ -44,7 +45,7 @@ export default memo(({list = [],
}, [defaultValue]) }, [defaultValue])
const init = () => { const init = () => {
const index = list?.findIndex(item => { const index = list?.findIndex((item) => {
return item.id == defaultValue return item.id == defaultValue
}) })
if (index !== -1) { if (index !== -1) {
@ -52,66 +53,74 @@ export default memo(({list = [],
} }
} }
const clickEvent = ({item, index}: {item, index:number}) => { const clickEvent = ({ item, index }: { item; index: number }) => {
setSelected(item.id) setSelected(item.id)
sideBarOnClick?.(item) sideBarOnClick?.(item)
computeSelectTab(index) computeSelectTab(index)
} }
const computeSelectTab = (index) => { const computeSelectTab = (index) => {
if((index + 1) > num_half.current) { if (index + 1 > num_half.current) {
let num = index + 1 - num_half.current let num = index + 1 - num_half.current
setTabId(list[num].id.toString()) setTabId(list[num].id.toString())
} else { } else {
setTabId(list[0].id.toString()) setTabId(list[0].id.toString())
} }
} }
useReady(() => { useReady(() => {
Taro.nextTick(() => { Taro.nextTick(() => {
let query = Taro.createSelectorQuery(); let query = Taro.createSelectorQuery()
query.select('.side_bar_select').boundingClientRect(rect=>{ query
.select('.side_bar_select')
.boundingClientRect((rect) => {
console.log('rect::', rect) console.log('rect::', rect)
let clientHeight = rect.height; let clientHeight = rect.height
let clientWidth = rect.width; let clientWidth = rect.width
let ratio = 750 / clientWidth; let ratio = 750 / clientWidth
let height = clientHeight * ratio; let height = clientHeight * ratio
num_half.current = Math.ceil(height / 2 / heightItem) num_half.current = Math.ceil(height / 2 / heightItem)
init() init()
}).exec(); })
.exec()
}) })
}) })
const [openClass, setOpenClass] = useState(false)
return ( return (
<> <>
<View className={classnames(styles.sideBar_main, 'side_bar_select')}> <View className={classnames(styles.sideBar_main, 'side_bar_select')}>
<ScrollView scrollWithAnimation={true} style={{ height }} className={styles.sideBar_select} scrollY scrollIntoView={`tab_${tabId}`}> <ScrollView scrollWithAnimation={true} style={{ height }} className={styles.sideBar_select} scrollY scrollIntoView={`tab_${tabId}`}>
{ {list?.map((item, index) => {
list?.map((item, index) => {
return ( return (
<View <View
className={classnames(styles.sideBar_select_title, {[styles.sideBar_select_title_select]:(selected == item.id)})} className={classnames(styles.sideBar_select_title, { [styles.sideBar_select_title_select]: selected == item.id })}
onClick={() => clickEvent({ item, index })} onClick={() => clickEvent({ item, index })}
id={`tab_${item.id}`} id={`tab_${item.id}`}
key={item.id} key={item.id}
style={{height:heightItem+'rpx'}} style={{ height: heightItem + 'rpx' }}>
> <View className={styles.title_con}>{item.name}</View>
<View className={styles.title_con}>
{item.name}
</View>
</View> </View>
) )
}) })}
}
</ScrollView> </ScrollView>
<View className={styles.sideBar_con}> <View className={styles.sideBar_con}>
<InfiniteScroll statusMore={statusMore} hasMore={hasMore} selfonScrollToLower={() => selfOnScrolltolower?.()} refresherTriggered={refresherTriggered} refresherEnabled={true} selfOnRefresherRefresh={() => selfOnRefresherRefresh?.()}> <View className={styles.product_class} style={{ height: openClass ? '100%' : '' }}>
<ProductClass open={openClass} onOpenClick={(val) => setOpenClass(val)} />
</View>
<InfiniteScroll
statusMore={statusMore}
hasMore={hasMore}
selfonScrollToLower={() => selfOnScrolltolower?.()}
refresherTriggered={refresherTriggered}
refresherEnabled={true}
selfOnRefresherRefresh={() => selfOnRefresherRefresh?.()}>
{children} {children}
</InfiniteScroll> </InfiniteScroll>
</View> </View>
</View> </View>
</> </>
) )
}) },
)

View File

@ -1,18 +1,20 @@
import { Image, View } from "@tarojs/components" import { Image, View } from '@tarojs/components'
import styles from './index.module.scss' import styles from './index.module.scss'
export default () => { export default () => {
return ( return (
<View className={styles.products_list}> <View className={styles.products_list}>
{new Array(10).fill('').map(item => { {new Array(10).fill('').map((item) => {
return <View className={styles.products_item}> return (
<View className={styles.products_item}>
<View className={styles.item_img}> <View className={styles.item_img}>
<Image src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ214233446-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651827249&t=b2fc2a3672dc8ced9e0f37ce7e2ff901"/> <Image src='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp01%2F1ZZQ214233446-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651827249&t=b2fc2a3672dc8ced9e0f37ce7e2ff901' />
<View className={styles.num}>230</View> <View className={styles.num}>230</View>
</View> </View>
<View className={styles.item_con}> <View className={styles.item_con}>
<View className={styles.title}><text>0770#</text>21S单面平纹()</View> <View className={styles.title}>
<text>0770#</text>21S单面平纹()
</View>
<View className={styles.tag_list}> <View className={styles.tag_list}>
<View className={styles.tag}>160cm</View> <View className={styles.tag}>160cm</View>
<View className={styles.tag}>110g</View> <View className={styles.tag}>110g</View>
@ -21,6 +23,7 @@ export default () => {
<View className={styles.des}></View> <View className={styles.des}></View>
</View> </View>
</View> </View>
)
})} })}
</View> </View>
) )

View File

@ -0,0 +1,114 @@
.product_class_main_line {
width: 100%;
height: 80px;
position: relative;
display: flex;
align-items: center;
margin-bottom: 20px;
background-color: #fff;
.product_class_scroll {
padding: 0 88px 0 19px;
box-sizing: border-box;
.product_class_list {
white-space: nowrap;
display: flex;
box-sizing: border-box;
.product_class_item {
min-width: 170px;
height: 56px;
background: #f5f5f5;
border-radius: 29px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: rgba(0, 0, 0, 0.8);
box-sizing: border-box;
&:nth-last-child(n + 1) {
margin-right: 16px;
}
}
.product_class_item_selected {
border: 1px solid #3c78f4;
color: #3c78f4;
background: #ecf2ff;
}
}
}
.product_class_more {
position: absolute;
right: 0;
top: 0;
width: 88px;
height: 100%;
background-color: #fff;
box-shadow: -7px 0px 7px -5px rgba(0, 0, 0, 0.16);
line-height: 100%;
display: flex;
align-items: center;
.product_class_more_icon {
margin-left: 20px;
display: inline-block;
transform: rotate(90deg);
font-size: 30px;
color: rgba(0, 0, 0, 0.5);
}
}
}
.product_class_main_block {
width: 100%;
height: 100%;
box-sizing: border-box;
position: relative;
.product_class_block_con {
max-height: 500px;
background-color: #fff;
z-index: 999;
position: relative;
}
.product_class_scroll {
box-sizing: border-box;
max-height: 500px;
padding: 20px 20px 0 20px;
.product_class_list {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
.product_class_item {
min-width: 167px;
height: 56px;
background: #ecf2ff;
border: 1px solid #3c78f4;
border-radius: 29px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #3c78f4;
margin: 0 6px 20px 6px;
}
}
}
.product_class_close {
font-size: 24px;
color: rgba(0, 0, 0, 0.6);
text-align: center;
padding-bottom: 20px;
.product_class_close_icon {
display: inline-block;
transform: rotate(-90deg);
font-size: 27px;
color: rgba(0, 0, 0, 0.5);
padding: 0 10px;
}
}
.product_class_block_mask {
position: absolute;
top: 0;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 100;
}
}

View File

@ -0,0 +1,114 @@
import { ScrollView, Text, View } from '@tarojs/components'
import styles from './index.module.scss'
import classnames from 'classnames'
import { useEffect, useMemo, useState } from 'react'
type Param = {
open: boolean
onOpenClick?: (val: boolean) => void
onSelect?: (val: number) => void
}
type ParamProduct = Omit<Param, 'open'> & {
defaultSelectIded: number
}
export default (option: Param) => {
const { open = false, onOpenClick, onSelect } = option
const [defaultSelectIded, setDefaultSelectIded] = useState(-1)
return (
<>
{open ? (
<ProductClassBlock defaultSelectIded={defaultSelectIded} onSelect={onSelect} onOpenClick={(val) => onOpenClick?.(val)}></ProductClassBlock>
) : (
<ProductClassLine defaultSelectIded={defaultSelectIded} onSelect={onSelect} onOpenClick={(val) => onOpenClick?.(val)}></ProductClassLine>
)}
</>
)
}
const ProductClassLine = (option: ParamProduct) => {
const { onOpenClick, defaultSelectIded = -1, onSelect } = option
const [selectInfo, setSelectInfo] = useState({
selected: -1, //当前选中的id
tabId: '', //需要滚动到的id
})
const list = useMemo(() => {
const data = new Array(10).fill('').map((item, index) => {
return { id: index, name: '二级分类' + index }
})
data.unshift({ id: -1, name: '全部' })
return data
}, [])
useEffect(() => {
let data: { item: any; index: number } = {}
list.filter((item, index) => {
if (item.id == defaultSelectIded) {
data = { item, index }
}
})
clickEvent(data)
}, [defaultSelectIded])
const clickEvent = ({ item, index }: { item: any; index: number }) => {
const num = index > 0 ? index - 1 : 0
setSelectInfo((e) => ({ ...e, tabId: list[num].id.toString(), selected: item.id }))
}
return (
<View className={styles.product_class_main_line}>
<ScrollView scrollX scrollWithAnimation={true} className={styles.product_class_scroll} scrollIntoView={`tabs_${selectInfo.tabId}`}>
<View className={styles.product_class_list}>
{list.map((item, index) => (
<View
id={`tabs_${item.id}`}
className={classnames(styles.product_class_item, item.id == selectInfo.selected ? styles.product_class_item_selected : '')}
onClick={() => clickEvent({ item, index })}>
{item.name + item.id}
</View>
))}
</View>
</ScrollView>
<View className={styles.product_class_more} onClick={() => onOpenClick?.(true)}>
<Text className={classnames('iconfont icon-a-moreback', styles.product_class_more_icon)}></Text>
</View>
</View>
)
}
const ProductClassBlock = (option: ParamProduct) => {
const { onOpenClick } = option
const [selectInfo, setSelectInfo] = useState(-1)
const list = useMemo(() => {
const data = new Array(10).fill('').map((item, index) => {
return { id: index, name: '二级分类' + index }
})
data.unshift({ id: -1, name: '全部' })
return data
}, [])
const clickEvent = (item) => {
setSelectInfo(item.id)
}
return (
<View className={styles.product_class_main_block}>
<View className={styles.product_class_block_con}>
<ScrollView scrollY className={styles.product_class_scroll}>
<View className={styles.product_class_list}>
{list.map((item, index) => (
<View className={styles.product_class_item} onClick={() => clickEvent(item)}>
{item.name}
</View>
))}
</View>
</ScrollView>
<View className={styles.product_class_close} onClick={() => onOpenClick?.(false)}>
<Text className={classnames('iconfont icon-a-moreback', styles.product_class_close_icon)}></Text>
</View>
</View>
<View className={styles.product_class_block_mask} onClick={() => onOpenClick?.(false)}></View>
</View>
)
}

View File

@ -1,8 +1,12 @@
.main { .main {
background-color: $color_bg_one; background-color: #f6f6f6;
height: 100vh; height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.header {
background-color: #fff;
padding-bottom: 20px;
}
.search { .search {
width: 100%; width: 100%;
display: flex; display: flex;
@ -29,5 +33,12 @@
flex: 1; flex: 1;
height: 0; height: 0;
margin-top: 20px; margin-top: 20px;
.product_right_con {
position: relative;
.product_class {
position: absolute;
top: 0;
}
}
} }
} }

View File

@ -12,6 +12,7 @@ import Taro, { Events, useDidShow, usePullDownRefresh } from '@tarojs/taro'
import { GetProductKindListApi, GetProductListApi } from '@/api/material' import { GetProductKindListApi, GetProductListApi } from '@/api/material'
import useLogin from '@/use/useLogin' import useLogin from '@/use/useLogin'
import { dataLoadingStatus } from '@/common/util' import { dataLoadingStatus } from '@/common/util'
import ProductClass from './components/productClass'
export default () => { export default () => {
useLogin() useLogin()
@ -84,13 +85,14 @@ export default () => {
return ( return (
<MoveBtn onClick={() => setShowShopCart(!showShopCart)}> <MoveBtn onClick={() => setShowShopCart(!showShopCart)}>
<View className={styles.main}> <View className={styles.main}>
<View className={styles.header}>
<View className={styles.search}> <View className={styles.search}>
<View className={styles.search_input} onClick={() => goLink('/pages/searchList/search')}> <View className={styles.search_input} onClick={() => goLink('/pages/searchList/search')}>
<Search disabled={true} style={{ width: '263rpx' }} borderRadius='16rpx' placeholder='请输入搜索布料' /> <Search disabled={true} style={{ width: '263rpx' }} borderRadius='16rpx' placeholder='请输入搜索布料' />
</View> </View>
</View> </View>
<Banner /> <Banner />
</View>
<View className={styles.products}> <View className={styles.products}>
<SideBar <SideBar
list={kindData.list} list={kindData.list}

View File

@ -26,7 +26,7 @@ export default () => {
const router = useRouter() const router = useRouter()
useEffect(() => { useEffect(() => {
if (router?.params.status != undefined && router?.params.status !== '') { if (router?.params.status != undefined && router?.params.status !== '') {
setSearchField((e) => ({ ...e, status: router?.params.status as number })) setSearchField((e) => ({ ...e, status: router?.params.status as unknown as number }))
} else { } else {
setSearchField((e) => ({ ...e, status: -1 })) setSearchField((e) => ({ ...e, status: -1 }))
} }
@ -200,7 +200,7 @@ export default () => {
<View className={styles.order_list_main}> <View className={styles.order_list_main}>
<View className={styles.title}> <View className={styles.title}>
<Search placeIcon='out' placeholder='搜索商品/名称/颜色/订单号' showBtn={true} changeOnSearch={getSearchData} debounceTime={300} /> <Search placeIcon='out' placeholder='搜索商品/名称/颜色/订单号' showBtn={true} changeOnSearch={getSearchData} debounceTime={300} />
<OrderStatusList list={statusList} onSelect={changeStatus} defaultId={router?.params.status as number} /> <OrderStatusList list={statusList} onSelect={changeStatus} defaultId={router?.params.status as unknown as number} />
</View> </View>
<View className={styles.order_list}> <View className={styles.order_list}>
<InfiniteScroll <InfiniteScroll