Merge branch 'light_v4'
This commit is contained in:
@@ -49,13 +49,20 @@
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #3C3C4399;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.location-position {
|
||||
max-width: 50%;
|
||||
flex: 1;
|
||||
min-width: 0; // 允许缩小
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
// 不使用 CSS 的省略号,由 JS 控制
|
||||
}
|
||||
|
||||
.location-time-distance {
|
||||
flex-shrink: 0; // 固定信息不压缩,始终显示
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.location-text {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { View, Text, Image } from "@tarojs/components";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { useMemo } from "react";
|
||||
import img from "../../config/images";
|
||||
import { ListCardProps } from "../../../types/list/types";
|
||||
import { formatGameTime, calculateDuration } from "@/utils/timeUtils";
|
||||
@@ -54,6 +55,59 @@ const ListCard: React.FC<ListCardProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
// 处理地点截断,确保固定信息始终显示
|
||||
const displayLocation = useMemo(() => {
|
||||
if (!location) return '';
|
||||
|
||||
// 获取屏幕宽度,用于计算实际容器宽度
|
||||
const systemInfo = Taro.getSystemInfoSync();
|
||||
const screenWidth = systemInfo.windowWidth || 375;
|
||||
// 容器宽度 = 屏幕宽度 - 左右 padding - 图片区域宽度
|
||||
const containerWidthPx = screenWidth - 130;
|
||||
|
||||
// 计算固定信息宽度
|
||||
const extraInfo = `${court_type ? `・${court_type}` : ''}${distance_km ? `・${distance_km}km` : ''}`;
|
||||
|
||||
// 估算字符宽度(基于 12px 字体)
|
||||
const getTextWidth = (text: string) => {
|
||||
let width = 0;
|
||||
for (let char of text) {
|
||||
if (/[\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]/.test(char)) {
|
||||
width += 12; // 中文字符 12px
|
||||
} else {
|
||||
width += 6; // 英文字符和数字 6px
|
||||
}
|
||||
}
|
||||
return width;
|
||||
};
|
||||
|
||||
const extraWidth = getTextWidth(extraInfo);
|
||||
const locationWidth = getTextWidth(location);
|
||||
|
||||
// 可用宽度 = 容器宽度 - 固定信息宽度 - 省略号宽度(18px)
|
||||
const availableWidth = containerWidthPx - extraWidth - 18;
|
||||
|
||||
// 如果地点宽度小于可用宽度,不需要截断
|
||||
if (locationWidth <= availableWidth) {
|
||||
return location;
|
||||
}
|
||||
|
||||
// 需要截断地点
|
||||
let maxChars = 0;
|
||||
let currentWidth = 0;
|
||||
for (let i = 0; i < location.length; i++) {
|
||||
const char = location[i];
|
||||
const charWidth = /[\u4e00-\u9fa5\u3000-\u303f\uff00-\uffef]/.test(char) ? 12 : 6;
|
||||
if (currentWidth + charWidth > availableWidth) {
|
||||
break;
|
||||
}
|
||||
currentWidth += charWidth;
|
||||
maxChars++;
|
||||
}
|
||||
|
||||
return location.slice(0, maxChars) + '...';
|
||||
}, [location, court_type, distance_km]);
|
||||
|
||||
// 根据图片数量决定展示样式
|
||||
const renderImages = () => {
|
||||
if (image_list?.length === 0) return null;
|
||||
@@ -128,9 +182,9 @@ const ListCard: React.FC<ListCardProps> = ({
|
||||
{/* 地点,室内外,距离 */}
|
||||
|
||||
<View className="location">
|
||||
{location && (
|
||||
{displayLocation && (
|
||||
<Text className="location-text location-position">
|
||||
{location}
|
||||
{displayLocation}
|
||||
</Text>
|
||||
)}
|
||||
<Text className="location-text location-time-distance">
|
||||
|
||||
@@ -206,13 +206,12 @@ box-sizing: border-box;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
transform: rotate(45deg);
|
||||
|
||||
transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
&.rotated {
|
||||
.closeIcon{
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ interface IProps {
|
||||
leftIconClick?: () => void;
|
||||
};
|
||||
onCityPickerVisibleChange?: (visible: boolean) => void; // 城市选择器显示/隐藏回调
|
||||
onScrollToTop?: () => void; // 滚动到顶部回调
|
||||
}
|
||||
|
||||
function CityPicker(props) {
|
||||
@@ -50,7 +51,7 @@ function CityPicker(props) {
|
||||
}
|
||||
|
||||
const ListHeader = (props: IProps) => {
|
||||
const { config, onCityPickerVisibleChange } = props;
|
||||
const { config, onCityPickerVisibleChange, onScrollToTop } = props;
|
||||
const { showInput = false, inputLeftIcon, leftIconClick } = config || {};
|
||||
const { getLocationLoading, statusNavbarHeightInfo } = useGlobalState();
|
||||
const { gamesNum, searchValue, cities, area, updateArea, getMatchesData, fetchGetGamesCount, refreshBothLists } = useListState();
|
||||
@@ -89,10 +90,16 @@ const ListHeader = (props: IProps) => {
|
||||
const handleLogoClick = () => {
|
||||
// 如果当前在列表页,点击后页面回到顶部
|
||||
if (getCurrentFullPath() === "/game_pages/list/index") {
|
||||
Taro.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300,
|
||||
});
|
||||
// 使用父组件传递的滚动方法(适配 ScrollView)
|
||||
if (onScrollToTop) {
|
||||
onScrollToTop();
|
||||
} else {
|
||||
// 降级方案:使用页面滚动(兼容旧版本)
|
||||
Taro.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: 300,
|
||||
});
|
||||
}
|
||||
}
|
||||
Taro.redirectTo({
|
||||
url: "game_pages/list/index", // 列表页
|
||||
|
||||
@@ -63,6 +63,7 @@ const ListPage = () => {
|
||||
|
||||
// 滚动相关状态
|
||||
const scrollContextRef = useRef(null);
|
||||
const scrollViewRef = useRef(null); // ScrollView 的 ref
|
||||
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const lastScrollTopRef = useRef(0);
|
||||
const scrollDirectionRef = useRef<'up' | 'down' | null>(null);
|
||||
@@ -70,6 +71,7 @@ const ListPage = () => {
|
||||
const loadingMoreRef = useRef(false); // 防止重复加载更多
|
||||
const scrollStartPositionRef = useRef(0); // 记录开始滚动的位置
|
||||
const [showSearchBar, setShowSearchBar] = useState(true); // 控制搜索框显示/隐藏(筛选始终显示)
|
||||
const [scrollTop, setScrollTop] = useState(0); // 控制 ScrollView 滚动位置
|
||||
|
||||
// 动态控制 GuideBar 的 z-index
|
||||
const [guideBarZIndex, setGuideBarZIndex] = useState<'low' | 'high'>('high');
|
||||
@@ -92,6 +94,12 @@ const ListPage = () => {
|
||||
setIsCityPickerVisible(visible);
|
||||
}, []);
|
||||
|
||||
// 滚动到顶部的方法
|
||||
const scrollToTop = useCallback(() => {
|
||||
// 使用一个唯一值触发 scrollTop 更新,确保每次都能滚动到顶部
|
||||
setScrollTop(prev => prev === 0 ? 0.1 : 0);
|
||||
}, []);
|
||||
|
||||
// 监听所有弹窗和菜单的状态,动态调整 GuideBar 的 z-index
|
||||
useEffect(() => {
|
||||
if (isPublishMenuVisible) {
|
||||
@@ -432,6 +440,7 @@ const ListPage = () => {
|
||||
showInput: isShowInputCustomerNavBar,
|
||||
}}
|
||||
onCityPickerVisibleChange={handleCityPickerVisibleChange}
|
||||
onScrollToTop={scrollToTop}
|
||||
/>
|
||||
{area_city !== "上海" ? (
|
||||
renderCityQrcode()
|
||||
@@ -485,7 +494,9 @@ const ListPage = () => {
|
||||
|
||||
{/* 可滚动的列表内容 */}
|
||||
<ScrollView
|
||||
ref={scrollViewRef}
|
||||
scrollY
|
||||
scrollTop={scrollTop}
|
||||
className={styles.listScrollView}
|
||||
scrollWithAnimation
|
||||
enhanced
|
||||
|
||||
Reference in New Issue
Block a user