iPhone 14 Midnight 128Gb (В коробке) – купить за 61 900 ₽ | CristalApple
Гарантия лучшей цены!

Гарантия лучшей цены!

Беcпроцентная рассрочка!

Беcпроцентная рассрочка!

Эксклюзивные предложения!

Эксклюзивные предложения!

(0)
Exclamation Icon НАЛИЧИЕ ТОВАРА УТОЧНЯЕТСЯ ПОСЛЕ ОФОРМЛЕНИЯ ЗАКАЗА

iPhone 14 Midnight 128Gb (В коробке)

Важное примечание
iPhone продается без предустановки приложения RuStore. Это обусловлено техническими ограничениями производителя Apple, которые не предоставляют возможность предустановки приложений из неизвестных источников на территории РФ. Приобретая данное устройство, вы соглашаетесь с тем, что уведомлены о наличии указанного ограничения. *Согласно ст. 4, 10 Закона РФ "О защите прав потребителей" №2300-1 от 07.02.1992г.
Apple Logo
Только оригинальные,
не восстановленные iPhone

Нет в наличии
Описание

Идеальный баланс

Более совершенная камера, новые расцветки, больше возможностей и привычные преимущества – iPhone 14 может быть сложно назвать громким обновлением, но он точно стал практически во всех отношениях. Высокая производительность, достойная автономность, стильный и компактный влагозащищённый корпус из анодированного алюминия и несколько приятных уникальных возможностей iOS, часть которых недоступна для предыдущих смартфонов, делают iPhone 14 определённо заслуживающим внимания18486-181Overview.jpg

Стоит увидеть

В iPhone 14 установлен 6,1-дюймовый OLED-экран Retina XDR Display с небольшим вырезом под фронтальную камеру и датчики. Дисплей поддерживает тактильный отклик, True Tone и защищён прочным стеклом Ceramic Shield. В отличие от iPhone 14 Pro здесь нет "Динамического острова" и поддержки частоты обновления в 120 Гц, а пиковая яркость ниже, но высокая контрастность, внушительная цветность, поддержка HDR и впечатляющая яркость заставят забыть о различиях – стоит лишь посмотреть на этот экран вживую.

11111.png

Останется актуальным надолго

Процессор A15 Bionic, оказался настолько удачным, что в Apple решили не торопиться списывать его со счетов. Мощная встроенная графика, огромные возможности для машинного обучения, впечатляющая энергоэффективность и актуальный техпроцесс 5нм обеспечивают более чем достаточную производительность и запас возможностей на годы вперёд. А что следовало обновить, так это беспроводные интерфейсы: помимо Wi-Fi 6 (802.11ax), iPhone 14 и 14 Plus получили Bluetooth 5,3 на радость всех владельцев AirPods и других беспроводных наушников. 

Снимайте как оператор из Голливуда

И без того впечатляющие возможности iPhone для видеосъёмки стали ещё шире. Теперь можно записывать HDR-видео в Dolby Vision в разрешении 4K с частотой до 60 кадров в секунду. В отличие от iPhone 13, режим "Киноэффект" получил поддержку 4K, а новая функция Action Mode позволяет записывать суперплавное видео в разрешении до 2,8K – то, что нужно для суровых условий. Примечательно, что снимать видео в HDR или с кинематографическим эффектом, обеспечивающим эффект съёмки на кинокамеру, можно как на любую из основных, так и на фронтальную камеру iPhone 14.

Новые возможности камеры

Фронтальная камера iPhone 14 и iPhone 14 Plus получила функцию автофокуса и объектив с более широкой апертурой – f/1,9. В сочетании с усовершенствованными алгоритмами эти улучшения позволяют делать сверхчёткие селфи в любых условиях, а при тусклом освещении разница с предыдущими моделями iPhone видна особенно хорошо, ведь камера TrueDepth теперь захватывает на 38% больше света. Работа основной и сверхширокоугольной камер в темноте тоже улучшилась за счёт более совершенной автообработки с технологией Photonic Engine. Кроме того, Deep Fusion обеспечивает ещё большую детализацию и более естественные цвета.

Впечатляющая автономность

Смартфон получил довольно ёмкий аккумулятор, обеспечивающий до 80 часов прослушивания музыки и до 20 часов просмотра видео. За счёт быстрой зарядки с помощью 20-Ваттного адаптера (в комплект не входит) смартфон заряжается до 50% всего за 30 минут. Модель поддерживает магнитные зарядные устройства MagSafe (до 15 Ватт) и более привычные беспроводные зарядные устройства (до 7,5 Ватт), а за счёт традиционно безупречной оптимизации iOS, iPhone 14 не подведёт в ответственный момент: он точно выдержит целый день интенсивного использования и даже больше.

Показать полностью Свернуть
Характеристики
Тип товара
Смартфон
Бренд
Apple
Модель
iPhone 14
Память
128ГБ
Материал корпуса
Ceramic Shield/ стекло/ алюминий
Диагональ
6,1"
Емкость аккумулятора
3279 мАч
Платформа
iOS
Тип экрана
OLED
Цвет
Черный
Отзывы
Отзывов еще никто не оставлял
Написать отзыв Отмена
Оставить отзыв
Ранее просмотренные
Почему Cristal Apple
Более 12 лет                                                                               на рынке
Более 12 лет на рынке
Гарантия на каждый товар
Гарантия на каждый товар
3 физические точки продаж
3 физические точки продаж
Почему Cristal Apple
Возможность покупки в кредит
Возможность покупки в кредит
Бесплатная доставка по региону
Бесплатная доставка по региону
Самовывоз через 15 минут
Самовывоз через 15 минут
Гарантия лучшей цены
Гарантия лучшей цены
Опыт работы более 10 лет
Опыт работы более 10 лет
0
Navigation
Обратный звонок
Запрос успешно отправлен!
Имя *
Телефон *
Предзаказ
Предзаказ успешно отправлен!
Имя *
Телефон *
Добавить в корзину
Название товара
100 ₽
1 шт.
Перейти в корзину
$(function() { var isTouch = !!('ontouchstart' in window || navigator.msMaxTouchPoints); var mobile_point = 767; const isMobile = () => $(window).width() <= mobile_point; const isIOS = /iPhone|iPad|iPod/.test(navigator.userAgent); // ✅ ИСПРАВЛЕНИЕ: Определяем $widget в начале const $widget = $('.wt-widget-v4-collections-on-index'); if (isTouch) { $widget.find(".collection-preview").addClass("is-touch"); } $widget.each(function(index, el) { new LazyLoad({ container: $(el).get(0), elements_selector: '.lazyload', use_native: 'loading' in document.createElement('img') }); }); // ========== LIQUID GLASS DROP ========== function smoothStep(a, b, t) { t = Math.max(0, Math.min(1, (t - a) / (b - a))); return t * t * (3 - 2 * t); } function length(x, y) { return Math.sqrt(x * x + y * y); } function roundedRectSDF(x, y, width, height, radius) { const qx = Math.abs(x) - width + radius; const qy = Math.abs(y) - height + radius; return Math.min(Math.max(qx, qy), 0) + length(Math.max(qx, 0), Math.max(qy, 0)) - radius; } function texture(x, y) { return { x, y }; } class LiquidGlassDrop { constructor(container, sliderElement, splideInstance) { this.containerElement = container; this.sliderElement = sliderElement; this.splideInstance = splideInstance; this.splideTrack = sliderElement.querySelector('.splide__track'); this.splideList = sliderElement.querySelector('.splide__list'); this.canvasDPI = 1; this.id = 'liquid-glass-' + Math.random().toString(36).substr(2, 9); this.dragVelocity = 0; this.scaleMultiplier = 1; this.isIOS = isIOS; this.resizeObserver = null; this.currentVisibleSlide = null; this.listPadding = 16; // ✅ ИСПРАВЛЕНИЕ: Пиксельный буфер для SVG-фильтра (критично для iOS) this.filterBuffer = 20; this.container = this.containerElement.querySelector('.glass-drop'); this.dropContainer = this.containerElement.querySelector('.glass-drop-container'); // ✅ Проверка поддержки backdrop-filter const testElement = document.createElement('div'); testElement.style.backdropFilter = 'blur(1px)'; testElement.style.webkitBackdropFilter = 'blur(1px)'; this.supportsBackdropFilter = testElement.style.backdropFilter !== '' || testElement.style.webkitBackdropFilter !== ''; this.init(); } init() { // ✅ Показываем контейнер, если все готово this.dropContainer.style.display = 'block'; this.updateDimensions(); this.createElement(); this.updateShader(); this.setupResizeObserver(); this.startRenderLoop(); this.addClickHint(); this.setupDragHandler(); // Перенесли в init } updateDimensions() { // ✅ Ищем именно активный видимый слайд const activeSlide = this.sliderElement.querySelector('.splide__slide.is-active.is-visible'); const targetSlide = activeSlide || this.sliderElement.querySelector('.splide__slide.is-visible') || this.sliderElement.querySelector('.splide__slide'); if (targetSlide) { const slideRect = targetSlide.getBoundingClientRect(); // ✅ Капля должна быть чуть выше слайда const newWidth = Math.round(slideRect.width); const newHeight = Math.round(slideRect.height) + 35; // Добавляем 35px к высоте (больше снизу) const dimensionsChanged = this.width !== newWidth || this.height !== newHeight; this.width = newWidth; this.height = newHeight; this.currentVisibleSlide = targetSlide; this.radius = 37 / Math.max(this.width, this.height); document.documentElement.style.setProperty('--drop-width', `${this.width}px`); document.documentElement.style.setProperty('--drop-height', `${this.height}px`); // Обновляем размеры капли (самого div) this.dropContainer.style.width = `${this.width}px`; this.dropContainer.style.height = `${this.height}px`; if (dimensionsChanged && this.feImage) { this.updateSVGFilterDimensions(); } return dimensionsChanged; } else { // Fallback: используем размеры по умолчанию this.width = 140; this.height = 215; // 180 + 35 this.radius = 37 / Math.max(this.width, this.height); document.documentElement.style.setProperty('--drop-width', `${this.width}px`); document.documentElement.style.setProperty('--drop-height', `${this.height}px`); this.dropContainer.style.width = `${this.width}px`; this.dropContainer.style.height = `${this.height}px`; return false; } } // ✅ НОВЫЙ МЕТОД: Обновление размеров SVG фильтра с буфером для iOS updateSVGFilterDimensions() { const buffer = this.filterBuffer; const filter = this.svg.querySelector(`#${this.id}_filter`); if (filter) { // 1. Расширяем область фильтра на 2*buffer, чтобы избежать обрезки при трансформациях filter.setAttribute('width', (this.width + 2 * buffer).toString()); filter.setAttribute('height', (this.height + 2 * buffer).toString()); // 2. Сдвигаем область фильтра на -buffer, чтобы она была центрирована filter.setAttribute('x', `-${buffer}`); filter.setAttribute('y', `-${buffer}`); filter.setAttribute('primitiveUnits', 'userSpaceOnUse'); } if (this.feImage) { // feImage должен быть того же размера, что и элемент (без буфера) this.feImage.setAttribute('width', this.width.toString()); this.feImage.setAttribute('height', this.height.toString()); // 3. Сдвигаем feImage на +buffer, чтобы компенсировать сдвиг фильтра this.feImage.setAttribute('x', buffer.toString()); this.feImage.setAttribute('y', buffer.toString()); } this.canvas.width = this.width * this.canvasDPI; this.canvas.height = this.height * this.canvasDPI; this.updateShader(); } setupResizeObserver() { if ('ResizeObserver' in window) { this.resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { if (entry.target.classList.contains('splide__slide') || entry.target.classList.contains('splide__track')) { this.updateDimensions(); } } }); this.resizeObserver.observe(this.splideTrack); const slides = this.sliderElement.querySelectorAll('.splide__slide'); slides.forEach(slide => { this.resizeObserver.observe(slide); }); } } observeVisibleSlide() { // Отслеживаем именно активный видимый слайд const activeSlide = this.sliderElement.querySelector('.splide__slide.is-active.is-visible'); const visibleSlide = activeSlide || this.sliderElement.querySelector('.splide__slide.is-visible'); if (visibleSlide && visibleSlide !== this.currentVisibleSlide) { this.resize(); // Вызываем полную перерисовку/обновление размеров } } // ✅ Функция для определения активного слайда под каплей getActiveSlideUnderDrop() { if (!this.dropContainer) return null; const dropX = parseFloat(this.dropContainer.style.getPropertyValue('--drop-pos-x')) || 0; const dropWidth = parseFloat(this.dropContainer.style.getPropertyValue('--drop-width')) || 140; const dropCenter = dropX + dropWidth / 2; const slides = this.sliderElement.querySelectorAll('.splide__slide'); const trackRect = this.sliderElement.querySelector('.splide__track').getBoundingClientRect(); let closestSlide = null; let minDistance = Infinity; slides.forEach((slide) => { const slideRect = slide.getBoundingClientRect(); // slideCenter относительно trackRect.left const slideCenter = slideRect.left - trackRect.left + slideRect.width / 2; const distance = Math.abs(slideCenter - dropCenter); if (distance < minDistance) { minDistance = distance; closestSlide = slide; } }); return closestSlide; } // ✅ Функция для добавления подсказки о клике addClickHint() { if (!this.container) return; this.container.classList.add('show-click-hint'); const removeHint = () => { this.container.classList.remove('show-click-hint'); this.container.removeEventListener('click', removeHint); this.container.removeEventListener('touchstart', removeHint); }; this.container.addEventListener('click', removeHint); this.container.addEventListener('touchstart', removeHint); setTimeout(() => { this.container.classList.remove('show-click-hint'); }, 3000); } createElement() { // ✅ 1. Create SVG filter this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this.svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); this.svg.setAttribute('width', '0'); this.svg.setAttribute('height', '0'); this.svg.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:9998;'; const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs'); const filter = document.createElementNS('http://www.w3.org/2000/svg', 'filter'); filter.setAttribute('id', `${this.id}_filter`); filter.setAttribute('filterUnits', 'userSpaceOnUse'); filter.setAttribute('colorInterpolationFilters', 'sRGB'); // ✅ Инициализируем фильтр с буфером для iOS const buffer = this.filterBuffer; filter.setAttribute('x', `-${buffer}`); filter.setAttribute('y', `-${buffer}`); filter.setAttribute('width', (this.width + 2 * buffer).toString()); filter.setAttribute('height', (this.height + 2 * buffer).toString()); filter.setAttribute('primitiveUnits', 'userSpaceOnUse'); this.feImage = document.createElementNS('http://www.w3.org/2000/svg', 'feImage'); this.feImage.setAttribute('id', `${this.id}_map`); this.feImage.setAttribute('width', this.width.toString()); this.feImage.setAttribute('height', this.height.toString()); this.feImage.setAttribute('x', buffer.toString()); // Сдвигаем feImage this.feImage.setAttribute('y', buffer.toString()); // Сдвигаем feImage this.feImage.setAttribute('result', 'map'); this.feDisplacementMap = document.createElementNS('http://www.w3.org/2000/svg', 'feDisplacementMap'); this.feDisplacementMap.setAttribute('in', 'SourceGraphic'); this.feDisplacementMap.setAttribute('in2', 'map'); this.feDisplacementMap.setAttribute('xChannelSelector', 'R'); this.feDisplacementMap.setAttribute('yChannelSelector', 'G'); this.feDisplacementMap.setAttribute('scale', '0'); filter.appendChild(this.feImage); filter.appendChild(this.feDisplacementMap); defs.appendChild(filter); this.svg.appendChild(defs); // ✅ 2. Create canvas this.canvas = document.createElement('canvas'); this.canvas.width = this.width * this.canvasDPI; this.canvas.height = this.height * this.canvasDPI; this.canvas.style.display = 'none'; this.context = this.canvas.getContext('2d'); // ✅ 3. Apply filter to glass-drop element if (this.container) { const filterURL = `url(#${this.id}_filter)`; this.container.style.webkitBackdropFilter = filterURL; this.container.style.backdropFilter = filterURL; this.container.style.isolation = 'isolate'; this.container.style.webkitTransform = 'translateZ(0)'; this.container.style.transform = 'translateZ(0)'; this.container.style.willChange = 'backdrop-filter, transform'; this.container.style.webkitBackfaceVisibility = 'hidden'; this.container.style.backfaceVisibility = 'hidden'; this.container.style.webkitPerspective = '1000'; this.container.style.perspective = '1000'; // ✅ Обработчик клика const clickHandler = (e) => { if (e.type.startsWith('touch') && this.dragVelocity > 5) return; e.preventDefault(); e.stopPropagation(); const activeSlide = this.getActiveSlideUnderDrop(); if (activeSlide) { const link = activeSlide.querySelector('.collection-link'); if (link) { this.container.classList.add('is-clicked'); setTimeout(() => { this.container.classList.remove('is-clicked'); window.location.href = link.getAttribute('href'); }, 150); } } }; this.container.addEventListener('click', clickHandler); this.container.addEventListener('touchend', clickHandler); } // ✅ 4. Append SVG и Canvas document.body.appendChild(this.svg); document.body.appendChild(this.canvas); } fragment(pos) { const { x, y } = pos; const normX = (x * 2 - 1) / this.scaleMultiplier; const normY = (y * 2 - 1) / this.scaleMultiplier; const normWidth = (this.width * this.scaleMultiplier) / Math.max(this.width, this.height) * this.radius; const normHeight = (this.height * this.scaleMultiplier) / Math.max(this.width, this.height) * this.radius; const normRadius = this.radius; const distanceToEdge = roundedRectSDF( normX, normY, normWidth * this.scaleMultiplier, normHeight * this.scaleMultiplier, normRadius ); const displacement = smoothStep(0.8, 0, distanceToEdge - 0.15); const scaled = smoothStep(0, 1, displacement); return texture(x * scaled + 0.5, y * scaled + 0.5); } updateShader() { const w = this.width * this.canvasDPI; const h = this.height * this.canvasDPI; const data = new Uint8ClampedArray(w * h * 4); let maxScale = 0; const rawValues = []; for (let i = 0; i < data.length; i += 4) { const x = (i / 4) % w; const y = Math.floor(i / 4 / w); const pos = this.fragment({ x: x / w, y: y / h }); const dx = pos.x * w - x; const dy = pos.y * h - y; maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)); rawValues.push(dx, dy); } maxScale *= 0.5; let index = 0; for (let i = 0; i < data.length; i += 4) { const r = rawValues[index++] / maxScale + 0.5; const g = rawValues[index++] / maxScale + 0.5; data[i] = r * 255; data[i + 1] = g * 255; data[i + 2] = 0; data[i + 3] = 255; } try { this.context.putImageData(new ImageData(data, w, h), 0, 0); this.feImage.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.canvas.toDataURL()); const baseScale = maxScale / this.canvasDPI; const velocityMultiplier = 0.05; const finalScale = baseScale * (1 + this.dragVelocity * velocityMultiplier); this.feDisplacementMap.setAttribute('scale', isNaN(finalScale) ? '0' : finalScale.toString()); } catch (error) { console.error('Shader update error:', error); } } updateDragState(velocity) { this.dragVelocity = Math.min(Math.abs(velocity), 50); this.scaleMultiplier = 1 + (this.dragVelocity * 0.005); if (this.container) { const scaleX = 1 + (this.dragVelocity * 0.01); const scaleY = 1 - (this.dragVelocity * 0.005); this.container.style.setProperty('--scale-x', scaleX); this.container.style.setProperty('--scale-y', scaleY); if (velocity !== 0) { this.container.classList.add('is-dragging'); } else { this.container.classList.remove('is-dragging'); } } this.updateShader(); } startRenderLoop() { const render = () => { this.observeVisibleSlide(); if (this.dragVelocity > 0.1) { this.dragVelocity *= 0.92; this.updateDragState(this.dragVelocity); } else if (this.dragVelocity > 0) { this.dragVelocity = 0; this.updateDragState(0); } requestAnimationFrame(render); }; requestAnimationFrame(render); } resize() { const changed = this.updateDimensions(); if (changed) { // SVG/Canvas удаляются/создаются заново только при изменении размеров слайда if (this.svg && this.svg.parentNode) { this.svg.remove(); } if (this.canvas && this.canvas.parentNode) { this.canvas.remove(); } this.createElement(); this.updateShader(); // Обновляем точки привязки после ресайза this.calculateSnapPoints(); this.updateDropPosition(this.splideInstance.index); } } // ============= DRAG LOGIC REFACTOR ============= calculateSnapPoints() { this.snapPoints = []; const track = this.sliderElement.querySelector('.splide__track'); if (!track) return; const trackRect = track.getBoundingClientRect(); const slides = this.sliderElement.querySelectorAll('.splide__slide'); slides.forEach((slide) => { const slideRect = slide.getBoundingClientRect(); // Позиция капли = (Центр слайда - Левый край трека) - (Ширина капли / 2) const dropX = (slideRect.left + slideRect.width / 2) - trackRect.left - (this.width / 2); this.snapPoints.push(dropX); }); // Устанавливаем ширину контейнера капли this.dropContainer.style.width = `${this.width}px`; } updateDropPosition(index) { if (this.snapPoints && this.snapPoints[index] !== undefined) { this.currentDropX = this.snapPoints[index]; this.dropContainer.style.setProperty('--drop-pos-x', `${this.currentDropX}px`); } } setupDragHandler() { const dropContainer = this.dropContainer; const splide = this.splideInstance; let isDragging = false; let startX = 0; let startDropX = 0; let lastTime = 0; let lastX = 0; let animationFrameId = null; let isSettling = false; let dragVelocity = 0; this.currentDropX = 0; this.calculateSnapPoints(); this.updateDropPosition(splide.index); // Начальная позиция const animateDrag = () => { if (!isDragging && !isSettling) { cancelAnimationFrame(animationFrameId); animationFrameId = null; return; } if (isDragging) { const currentTime = performance.now(); const deltaTime = currentTime - lastTime; if (deltaTime > 0) { dragVelocity = (this.currentDropX - lastX) / deltaTime * 100; // px/ms -> px/s } lastTime = currentTime; lastX = this.currentDropX; this.updateDragState(dragVelocity); } else if (isSettling) { dragVelocity *= 0.85; if (Math.abs(dragVelocity) < 0.5) { dragVelocity = 0; isSettling = false; } this.updateDragState(dragVelocity); } animationFrameId = requestAnimationFrame(animateDrag); } // DRAG START const startDrag = (e) => { if (isMobile() && e.type === 'mousedown') return; if (!isMobile() && e.type.startsWith('touch')) return; if (e.touches) { if (e.touches.length > 1) return; e.preventDefault(); } e.stopPropagation(); isDragging = true; isSettling = false; const clientX = e.touches ? e.touches[0].clientX : e.clientX; startX = clientX; startDropX = this.currentDropX; lastX = this.currentDropX; lastTime = performance.now(); this.container.style.transition = 'none'; dropContainer.style.transition = 'none'; if (!animationFrameId) { animateDrag(); } } // DRAG MOVE const drag = (e) => { if (!isDragging) return; const clientX = e.touches ? e.touches[0].clientX : e.clientX; const dx = clientX - startX; this.currentDropX = startDropX + dx; dropContainer.style.setProperty('--drop-pos-x', `${this.currentDropX}px`); // СИНХРОНИЗАЦИЯ СЛАЙДЕРА const dropCenter = this.currentDropX + (this.width / 2); let minDistance = Infinity; let closestIndex = -1; this.snapPoints.forEach((snapX, index) => { const snapCenter = snapX + (this.width / 2); const distance = Math.abs(dropCenter - snapCenter); if (distance < minDistance) { minDistance = distance; closestIndex = index; } }); // Двигаем слайдер, если капля сместилась к другому слайду if (closestIndex !== -1 && splide.index !== closestIndex) { splide.go(closestIndex); } if (e.type.startsWith('touch') && Math.abs(dx) > 10) { e.preventDefault(); } } // DRAG END const endDrag = (e) => { if (!isDragging) return; isDragging = false; isSettling = true; this.container.style.transition = ''; dropContainer.style.transition = ''; // Находим ближайшую точку для привязки капли let closestIndex = splide.index; // Анимируем каплю к точке привязки if (this.snapPoints[closestIndex] !== undefined) { this.currentDropX = this.snapPoints[closestIndex]; dropContainer.style.setProperty('--drop-pos-x', `${this.currentDropX}px`); } } // Инициализация событий dropContainer.addEventListener('mousedown', startDrag); window.addEventListener('mousemove', drag); window.addEventListener('mouseup', endDrag); window.addEventListener('mouseleave', endDrag); dropContainer.addEventListener('touchstart', startDrag, { passive: false }); window.addEventListener('touchmove', drag, { passive: false }); window.addEventListener('touchend', endDrag); // Обновление позиции капли при переключении слайдера splide.on('move', (newIndex) => { if (!isDragging) { this.updateDropPosition(newIndex); } }); // Пересчет точек при изменении размера window.addEventListener('resize', () => { setTimeout(() => { this.calculateSnapPoints(); this.updateDropPosition(splide.index); }, 100); this.resize(); }); } // ============= END DRAG LOGIC REFACTOR ============= } // ========== SLIDER INITIALIZATION (unchanged) ========== if (isMobile()) { let specialCollections = $widget.find(".js-collections"); let slider_mobile_right_padding; let slide_width_mobile; let slide_gap_mobile = specialCollections.find(".js-collections-slider").attr("data-slide-gap-mobile") / 2; $(window).on("resize", function() { slide_width_mobile = specialCollections.find(".splide__slide").width(); slider_mobile_right_padding = slide_width_mobile * 0.5 + slide_gap_mobile; specialCollections.find(".js-collections-slider").attr("data-mobile-right-padding", slider_mobile_right_padding); }); specialCollections.each(function() { let collections_block = $(this); let slider_block = collections_block.find(".js-collections-slider"); let slide_min_width = 160; let slide_min_width_mobile = 130; let slide_gap = 30; let slide_gap_mobile = 15; if (slider_block.is("[data-slide-min-width]")) { slide_min_width = parseInt(slider_block.attr("data-slide-min-width")); } else { slider_block.attr("data-slide-min-width", slide_min_width); } if (slider_block.is("[data-slide-min-width-mobile]")) { slide_min_width_mobile = parseInt(slider_block.attr("data-slide-min-width-mobile")); } else { slider_block.attr("data-slide-min-width-mobile", slide_min_width_mobile); } if (slider_block.is("[data-slide-gap]")) { slide_gap = parseInt(slider_block.attr("data-slide-gap")); } else { slider_block.attr("data-slide-gap", slide_gap); } if (slider_block.is("[data-slide-gap-mobile]")) { slide_gap_mobile = parseInt(slider_block.attr("data-slide-gap-mobile")); } else { slider_block.attr("data-slide-gap-mobile", slide_gap_mobile); } slide_width_mobile = slider_block.find(".splide__slide").width(); slider_mobile_right_padding = slide_width_mobile * 0.5 + slide_gap_mobile; slider_block.attr("data-mobile-right-padding", slider_mobile_right_padding); let slider = slider_block.splide({ type: "slide", drag: "free", snap: true, arrows: false, pagination: false, gap: slide_gap_mobile, padding: { right: slider_mobile_right_padding }, breakpoints: { 767: { arrows: false, gap: slide_gap_mobile, padding: { right: slider_mobile_right_padding }, }, }, }); configureSlider(slider, slider_block, slide_min_width, slide_min_width_mobile, slide_gap, slide_gap_mobile); // ✅ Инициализация Liquid Glass Drop только после монтирования Splide slider[0].splide.on('mounted', function() { if (isMobile()) { const dropInstance = new LiquidGlassDrop(collections_block[0], slider_block[0], slider[0].splide); slider_block.data('liquidGlassDrop', dropInstance); } }); // На случай, если Splide уже смонтирован if (slider[0].splide.root.classList.contains('is-initialized') && !slider_block.data('liquidGlassDrop')) { if (isMobile()) { const dropInstance = new LiquidGlassDrop(collections_block[0], slider_block[0], slider[0].splide); slider_block.data('liquidGlassDrop', dropInstance); } } }); } else { // Desktop initialization logic (без изменений) $widget.find(".js-collections-slider").each(function() { let slider_block = $(this); let slide_min_width = 160; let slide_min_width_mobile = 130; let slide_gap = 30; let slide_gap_mobile = 15; if (slider_block.is("[data-slide-min-width]")) { slide_min_width = parseInt(slider_block.attr("data-slide-min-width")); } if (slider_block.is("[data-slide-min-width-mobile]")) { slide_min_width_mobile = parseInt(slider_block.attr("data-slide-min-width-mobile")); } if (slider_block.is("[data-slide-gap]")) { slide_gap = parseInt(slider_block.attr("data-slide-gap")); } if (slider_block.is("[data-slide-gap-mobile]")) { slide_gap_mobile = parseInt(slider_block.attr("data-slide-gap-mobile")); } let slider = slider_block.splide({ type: "slide", arrows: true, pagination: false, gap: slide_gap, breakpoints: { 767: { arrows: false, gap: slide_gap_mobile, }, }, }); configureSlider(slider, slider_block, slide_min_width, slide_min_width_mobile, slide_gap, slide_gap_mobile); }); } function isMobileWidth() { return $(window).width() <= mobile_point; } function configureSlider(slider, sliderBlock, slide_min_width, slide_min_width_mobile, slide_gap, slide_gap_mobile) { let sliderInst = slider[0].splide; sliderInst.on("mounted", function() { sliderInst.go(0); recalcSlidesPerView(); displaySliderControls(slider); }); sliderInst.on("refresh", function() { recalcSlidesPerView(); displaySliderControls(slider); }); $(window).on("resize", function() { setTimeout(function() { if (sliderInst) { sliderInst.refresh(); // При ресайзе уведомляем каплю о необходимости обновления const dropInstance = sliderBlock.data('liquidGlassDrop'); if (dropInstance) { dropInstance.resize(); } } }, 0); }); function recalcSlidesPerView() { setTimeout(() => { let init_slide_min_width = isMobileWidth() ? slide_min_width_mobile : slide_min_width; let init_slide_gap = isMobileWidth() ? slide_gap_mobile : slide_gap; let new_per_page = getSlidesPerView(sliderBlock, init_slide_min_width, init_slide_gap); sliderInst.options = { perPage: new_per_page }; }, 0); } configureDragOption(slider); } function getSlidesPerView(sliderBlock, slideMinWidth, slideGap) { let right_padding = 0; if (sliderBlock.is("[data-mobile-right-padding]") && isMobileWidth()) { right_padding = parseInt(sliderBlock.data("mobileRightPadding")) + slideGap; } return Math.floor((sliderBlock.width() + slideGap - right_padding) / (slideMinWidth + slideGap)); } function displaySliderControls(slider) { let sliderInst = slider[0].splide; let collections = slider.parents(".js-collections"); let slider_arrow = collections.find(".collections__slider-arrow"); if (sliderInst.length <= sliderInst.options.perPage) { slider_arrow.addClass("is-hide"); slider.addClass("is-hide-paging"); } else { slider_arrow.removeClass("is-hide"); slider.removeClass("is-hide-paging"); } } function configureDragOption(slider) { if (slider[0].splide.length <= slider[0].splide.options.perPage) { slider.splide().options = { drag: false }; } } });
Заявка

Я ознакомлен и согласен с условиями оферты и политики конфиденциальности.

Заказ в один клик

Я ознакомлен и согласен с условиями оферты и политики конфиденциальности.