ClusterPopupContent优化建议
Создано: 4 февраля 2025 г.
Создано: 4 февраля 2025 г.
import React, { useState, useEffect, useRef } from 'react';
const ClusterPopupContent = ({
leaves,
count,
maxMarkers = 10,
maxHeight = 300,
}) => {
const [currentPage, setCurrentPage] = useState(1);
const scrollContainerRef = useRef(null);
// get totol page number
const totalPages = Math.ceil(leaves.length / maxMarkers);
// cur page display
const displayedLeaves = leaves.slice(
(currentPage - 1) * maxMarkers,
currentPage * maxMarkers
);
useEffect(() => {
if (scrollContainerRef.current) {
scrollContainerRef.current.scrollTop = 0;
}
}, [currentPage]);
// page buttons
const handlePrevPage = (e) => {
e.stopPropagation();
setCurrentPage((prev) => Math.max(prev - 1, 1));
};
const handleNextPage = (e) => {
e.stopPropagation();
setCurrentPage((prev) => Math.min(prev + 1, totalPages));
};
return (
<div style={{ minWidth: 220 }}>
<h4>Cluster ({count} markers)</h4>
text<div ref={scrollContainerRef} style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto', border: '1px solid #ccc', padding: '4px', marginBottom: '6px', }} > {displayedLeaves.map((marker, i) => { const properties = marker.properties || {}; const geometry = marker.geometry || {}; let lat = 'N/A', lng = 'N/A'; if (geometry.type === 'Point' && Array.isArray(geometry.coordinates)) { [lng, lat] = geometry.coordinates; } const { time, ...restProps } = properties; const timeValue = time != null ? time : 'N/A'; return ( <div key={i} style={{ marginBottom: 8, paddingBottom: 4, borderBottom: '1px dashed #ccc', }} > <div> <b>Coordinate:</b> {typeof lat === 'number' ? `${lat}, ${lng}` : 'N/A'} </div> <div> <b>Time:</b> {timeValue} </div> <div style={{ marginLeft: 6, marginTop: 4 }}> <b>Properties:</b> {Object.keys(restProps).length === 0 ? ( <div style={{ marginLeft: 6 }}> <i>No more props</i> </div> ) : ( Object.entries(restProps).map(([k, v]) => { let displayVal = v == null ? 'N/A' : typeof v === 'object' ? JSON.stringify(v) : String(v); if (displayVal.length > 200) { displayVal = displayVal.slice(0, 200) + '...'; } return ( <div key={k} style={{ marginLeft: 6 }}> <b>{k}:</b> {displayVal} </div> ); }) )} </div> </div> ); })} </div> {/* paging control */} {totalPages > 1 && ( <div style={{ textAlign: 'center' }}> <button onClick={handlePrevPage} disabled={currentPage === 1}> Prev </button> <span style={{ margin: '0 8px' }}> Page {currentPage} / Total {totalPages} </span> <button onClick={handleNextPage} disabled={currentPage === totalPages}> Next </button> </div> )} </div>
);
};
export default ClusterPopupContent;
// src/MarkerPopupContent.jsx
import React from 'react';
const MarkerPopupContent = ({
properties = {},
coords = null,
hideCoordinate = false,
}) => {
// Separate 'time' from other properties
const { time, ...restProps } = properties;
const timeValue = (time !== undefined && time !== null) ? time : 'N/A';
// If coords is an array [lat, lng], use it. Otherwise 'N/A'
let lat = 'N/A';
let lng = 'N/A';
if (Array.isArray(coords) && coords.length >= 2) {
lat = coords[0];
lng = coords[1];
}
// Convert remaining properties into an array of entries
const entries = Object.entries(restProps);
return (
<div
style={{
minWidth: 200,
maxHeight: 200,
overflowY: 'auto',
paddingRight: 4,
}}
>
{!hideCoordinate && (
<div>
<b>Coordinate:</b>{' '}
{typeof lat === 'number' && typeof lng === 'number'
? ${lat}, ${lng}
: 'N/A'}
</div>
)}
text<div> <b>Time:</b> {timeValue} </div> <hr /> {entries.length === 0 ? ( <div><i>No additional properties</i></div> ) : ( <div> <b>Properties:</b> {entries.map(([key, value]) => { // If value is null/undefined => 'N/A' if (value == null) { return ( <div key={key} style={{ marginLeft: 8 }}> <b>{key}:</b> N/A </div> ); } // If value is an object or array => JSON-stringify it let displayValue = typeof value === 'object' ? JSON.stringify(value) : String(value); return ( <div key={key} style={{ marginLeft: 8 }}> <b>{key}:</b> {displayValue} </div> ); })} </div> )} </div>
);
};
export default MarkerPopupContent;
帮我改成是N/A的值就都不显示了,谢谢你,别动我别的功能和逻辑哈,给我完整代码
下面给出两份修改后的完整代码,仅在渲染时对值为 'N/A'
的字段做了“隐藏不显示”的处理,其它逻辑不变。
jsximport React, { useState, useEffect, useRef } from 'react'; const ClusterPopupContent = ({ leaves, count, maxMarkers = 10, maxHeight = 300, }) => { const [currentPage, setCurrentPage] = useState(1); const scrollContainerRef = useRef(null); // get total page number const totalPages = Math.ceil(leaves.length / maxMarkers); // current page display const displayedLeaves = leaves.slice( (currentPage - 1) * maxMarkers, currentPage * maxMarkers ); useEffect(() => { if (scrollContainerRef.current) { scrollContainerRef.current.scrollTop = 0; } }, [currentPage]); // page buttons const handlePrevPage = (e) => { e.stopPropagation(); setCurrentPage((prev) => Math.max(prev - 1, 1)); }; const handleNextPage = (e) => { e.stopPropagation(); setCurrentPage((prev) => Math.min(prev + 1, totalPages)); }; return ( <div style={{ minWidth: 220 }}> <h4>Cluster ({count} markers)</h4> <div ref={scrollContainerRef} style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto', border: '1px solid #ccc', padding: '4px', marginBottom: '6px', }} > {displayedLeaves.map((marker, i) => { const properties = marker.properties || {}; const geometry = marker.geometry || {}; let lat = 'N/A', lng = 'N/A'; if ( geometry.type === 'Point' && Array.isArray(geometry.coordinates) ) { [lng, lat] = geometry.coordinates; } const { time, ...restProps } = properties; const timeValue = time != null ? time : 'N/A'; // 准备对剩余属性做过滤,排除 'N/A' const mappedProps = Object.entries(restProps).map(([k, v]) => { let displayVal = v == null ? 'N/A' : typeof v === 'object' ? JSON.stringify(v) : String(v); if (displayVal.length > 200) { displayVal = displayVal.slice(0, 200) + '...'; } // 如果是 'N/A',返回 null,不渲染 if (displayVal === 'N/A') return null; return ( <div key={k} style={{ marginLeft: 6 }}> <b>{k}:</b> {displayVal} </div> ); }); // 过滤掉 null,只剩真实可显示的属性 const filteredProps = mappedProps.filter(Boolean); return ( <div key={i} style={{ marginBottom: 8, paddingBottom: 4, borderBottom: '1px dashed #ccc', }} > {/* 坐标显示:只有当 lat / lng 都是 number 时才显示 */} {typeof lat === 'number' && typeof lng === 'number' && ( <div> <b>Coordinate:</b> {`${lat}, ${lng}`} </div> )} {/* 时间显示:只有当 timeValue !== 'N/A' 时才显示 */} {timeValue !== 'N/A' && ( <div> <b>Time:</b> {timeValue} </div> )} <div style={{ marginLeft: 6, marginTop: 4 }}> <b>Properties:</b> {/* 如果没有可显示的属性则提示 “No more props”,否则依次渲染 */} {filteredProps.length === 0 ? ( <div style={{ marginLeft: 6 }}> <i>No more props</i> </div> ) : ( filteredProps )} </div> </div> ); })} </div> {/* paging control */} {totalPages > 1 && ( <div style={{ textAlign: 'center' }}> <button onClick={handlePrevPage} disabled={currentPage === 1}> Prev </button> <span style={{ margin: '0 8px' }}> Page {currentPage} / Total {totalPages} </span> <button onClick={handleNextPage} disabled={currentPage === totalPages}> Next </button> </div> )} </div> ); }; export default ClusterPopupContent;
jsximport React from 'react'; const MarkerPopupContent = ({ properties = {}, coords = null, hideCoordinate = false, }) => { // Separate 'time' from other properties const { time, ...restProps } = properties; const timeValue = time != null ? time : 'N/A'; // 如果 coords 是 [lat, lng] 数组则使用,否则为 'N/A' let lat = 'N/A'; let lng = 'N/A'; if (Array.isArray(coords) && coords.length >= 2) { lat = coords[0]; lng = coords[1]; } // 把其余属性转成 [key, value] 的数组,后面统一处理 'N/A' const entries = Object.entries(restProps); // 先映射再过滤掉 'N/A' const mappedProps = entries.map(([key, value]) => { if (value == null) { // 空值 => 'N/A' return null; } // 如果是对象或数组 => JSON-stringify let displayValue = typeof value === 'object' ? JSON.stringify(value) : String(value); // 如果依然是 'N/A',就跳过 if (displayValue === 'N/A') { return null; } return ( <div key={key} style={{ marginLeft: 8 }}> <b>{key}:</b> {displayValue} </div> ); }); const filteredProps = mappedProps.filter(Boolean); return ( <div style={{ minWidth: 200, maxHeight: 200, overflowY: 'auto', paddingRight: 4, }} > {/* Coordinate: 只有当 !hideCoordinate 且 lat/lng 为数字时才显示 */} {!hideCoordinate && typeof lat === 'number' && typeof lng === 'number' && ( <div> <b>Coordinate:</b> {`${lat}, ${lng}`} </div> )} {/* Time: 只有当 timeValue !== 'N/A' 时才显示 */} {timeValue !== 'N/A' && ( <div> <b>Time:</b> {timeValue} </div> )} <hr /> {filteredProps.length === 0 ? ( <div> <i>No additional properties</i> </div> ) : ( <div> <b>Properties:</b> {filteredProps} </div> )} </div> ); }; export default MarkerPopupContent;
坐标:
N/A
的位置,改成了 条件渲染。只有当 lat
、lng
同为数值时才渲染 “Coordinate” 这一行,否则不显示。时间:
timeValue
是否为 'N/A'
,如果是就不渲染这一行。其它属性 (Properties
):
'N/A'
,直接返回 null
,不渲染这一行。最后通过 filter(Boolean)
过滤掉 null
。除了对 'N/A'
值的渲染逻辑进行隐藏处理之外,其它功能和逻辑(分页、布局、CSS 样式等)都未做变动。希望对你有帮助。