onEachFeature используется в Leaflet как параметр
конфигурации при создании слоя GeoJSON и предназначен для постобработки
каждого объекта данных после его добавления на карту. Механизм работы
основан на том, что при разборе GeoJSON каждый элемент преобразуется в
слой Leaflet, после чего к нему применяется пользовательская функция,
позволяющая навесить поведение, события или связать дополнительные
данные.
Параметр onEachFeature передаётся в объект настроек при
создании слоя:
L.geoJSON(data, {
onEachFeature: function (feature, layer) {
// логика обработки
}
});
Функция получает два аргумента:
feature — исходный объект GeoJSON, содержащий свойства
(properties) и геометрию (geometry)layer — созданный Leaflet-слой, соответствующий
геометрии объектаКаждый объект GeoJSON проходит через эту функцию индивидуально, что делает возможным точечное управление поведением элементов.
При добавлении GeoJSON в Leaflet происходит последовательная обработка:
pointToLayer (для точек), style
(для векторных объектов)onEachFeatureonEachFeature выполняется после создания слоя, что
делает его ключевой точкой для навешивания логики.
Наиболее распространённый сценарий — связывание данных GeoJSON с popup:
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
if (feature.properties && feature.properties.name) {
layer.bindPopup(feature.properties.name);
}
}
});
В этом случае каждый объект получает индивидуальный popup на основе свойств.
Через onEachFeature удобно навешивать обработчики
событий:
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
layer.on('click', function () {
console.log(feature.properties);
});
layer.on('mouseover', function () {
layer.setStyle({
weight: 5
});
});
layer.on('mouseout', function () {
layer.setStyle({
weight: 2
});
});
}
});
Каждый слой становится интерактивным без необходимости обхода коллекции вручную.
GeoJSON часто содержит атрибуты, которые необходимо использовать внутри логики приложения:
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
layer.featureId = feature.properties.id;
layer.category = feature.properties.type;
}
});
Таким образом слой расширяется пользовательскими полями.
onEachFeature работает совместно с другими опциями:
style — применяется к полигональным и линейным
объектамpointToLayer — отвечает за создание маркеровfilter — определяет, какие объекты будут включеныТипичный порядок взаимодействия:
L.geoJSON(geoData, {
filter: function (feature) {
return feature.properties.active;
},
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng);
},
style: function (feature) {
return { color: feature.properties.color };
},
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.name);
}
});
Функция onEachFeature вызывается без привязки к
конкретному контексту приложения. Значение this внутри
callback зависит от способа вызова и не гарантирует доступ к внешнему
состоянию. Поэтому при необходимости доступа к внешним переменным
используется замыкание:
const selectedId = 10;
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
if (feature.properties.id === selectedId) {
layer.setStyle({ color: 'red' });
}
}
});
onEachFeature не зависит от типа геометрии, однако слой,
передаваемый вторым аргументом, может отличаться:
Marker или CircleMarkerPolylinePolygonЭто важно при применении методов, специфичных для типа слоя:
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
if (layer instanceof L.Polygon) {
layer.setStyle({ fillOpacity: 0.5 });
}
if (layer instanceof L.Marker) {
layer.setOpacity(0.8);
}
}
});
При увеличении сложности данных onEachFeature часто
становится центральной точкой бизнес-логики для слоя:
function createPopupContent(props) {
return `
<div>
<h4>${props.name}</h4>
<p>Тип: ${props.type}</p>
<p>Рейтинг: ${props.rating}</p>
</div>
`;
}
L.geoJSON(geoData, {
onEachFeature: function (feature, layer) {
const props = feature.properties;
layer.bindPopup(createPopupContent(props));
if (props.priority === 'high') {
layer.setStyle({ color: 'red' });
}
layer.on('click', function () {
layer.openPopup();
});
}
});
При отсутствии properties или некорректной структуре
GeoJSON функция всё равно вызывается, поэтому требуется защита от
undefined:
onEachFeature: function (feature, layer) {
if (!feature || !feature.properties) return;
layer.bindPopup(feature.properties.name || 'Без названия');
}
Разделение ответственности между параметрами:
pointToLayer — создание визуального представления
точкиstyle — оформление геометрииonEachFeature — логика поведения и привязка данныхТакое разделение позволяет избегать смешивания визуальной и функциональной логики.
L.geoJSON(geoData, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng);
},
style: function (feature) {
return { color: 'blue' };
},
onEachFeature: function (feature, layer) {
layer.bindTooltip(feature.properties.name);
}
});
При обновлении данных onEachFeature снова применяется ко
всем объектам, что позволяет автоматически пересоздавать поведение без
дополнительной ручной обработки коллекции слоёв.
function render(data) {
return L.geoJSON(data, {
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.title);
}
});
}