0 }, get firstVideoIndex() { return this.hasVideos ? this.images.length : -1 }, get total() { return this.images.length + this.productVideos.length }, modalOpen: false, modalActive: 0, // Drag/swipe state isDragging: false, wasDragging: false, startX: 0, currentX: 0, dragOffset: 0, containerWidth: 0, startY: 0, directionLocked: null, isRtl: false, imageLoading: false, // Zoom state zoomScale: 1, zoomPanX: 0, zoomPanY: 0, zoomPinching: false, zoomPanning: false, zoomInitialDistance: 0, zoomInitialScale: 1, zoomPanStartX: 0, zoomPanStartY: 0, zoomPanOffsetX: 0, zoomPanOffsetY: 0, zoomLastTap: 0, zoomLastTouchX: 0, zoomLastTouchY: 0, zoomAnimating: false, lastInputWasTouch: false, init() { this.isRtl = document.documentElement.dir === 'rtl'; this.$nextTick(() => { this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; // Handle already-cached images where x-on:load won't fire this.$el.querySelectorAll('img.lqip-placeholder').forEach(lqip => { const realImg = lqip.nextElementSibling; if (realImg && realImg.complete && realImg.naturalWidth > 0) { realImg.dataset.lqipDone = '1'; lqip.style.display = 'none'; } }); }); window.addEventListener('resize', () => { this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; }); // Preload first image of each variant for instant switching Object.values(this.variationImagesMap).forEach(variant => { if (variant.images && variant.images[0]) { new Image().src = variant.images[0]; } }); // Only the active slide may play. Clearing startedVideo also // drops the bound src, so swiping away stops the download and // not just the playback. this.$watch('active', () => { this.startedVideo = null; this.$el.querySelectorAll('video[data-product-video]').forEach(v => v.pause()); }); }, handleDragStart(e) { if (this.total <= 1) return; this.isDragging = true; this.directionLocked = null; this.startX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX; this.startY = e.type.includes('mouse') ? e.clientY : e.touches[0].clientY; this.currentX = this.startX; this.containerWidth = this.$refs.carouselContainer?.offsetWidth || 0; }, handleDragMove(e) { if (!this.isDragging) return; const clientX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX; const clientY = e.type.includes('mouse') ? e.clientY : e.touches[0].clientY; if (this.directionLocked === null) { const deltaX = Math.abs(clientX - this.startX); const deltaY = Math.abs(clientY - this.startY); if (deltaX < 5 && deltaY < 5) return; if (deltaY > deltaX) { this.directionLocked = 'vertical'; this.isDragging = false; this.dragOffset = 0; return; } this.directionLocked = 'horizontal'; } if (this.directionLocked === 'vertical') return; e.preventDefault(); this.currentX = clientX; let diff = this.currentX - this.startX; // Limit drag at edges const atFirst = this.active === 0; const atLast = this.active === this.total - 1; const isAtEdge = this.isRtl ? (atFirst && diff < 0) || (atLast && diff > 0) : (atFirst && diff > 0) || (atLast && diff < 0); if (isAtEdge) { diff = diff * 0.3; // Resistance at edges } this.dragOffset = diff; }, handleDragEnd() { this.directionLocked = null; if (!this.isDragging) return; this.isDragging = false; // Mark that we just finished dragging to prevent click from opening modal if (Math.abs(this.dragOffset) > 5) { this.wasDragging = true; setTimeout(() => { this.wasDragging = false; }, 100); } const threshold = this.containerWidth * 0.2; if (Math.abs(this.dragOffset) > threshold) { if (this.isRtl) { // RTL: drag left (negative) = prev, drag right (positive) = next if (this.dragOffset < 0) { this.prev(); } else { this.next(); } } else { // LTR: drag right (positive) = prev, drag left (negative) = next if (this.dragOffset > 0) { this.prev(); } else { this.next(); } } } this.dragOffset = 0; }, getSlideTransform() { // RTL: images flow right-to-left, so we use positive offset // LTR: images flow left-to-right, so we use negative offset const baseOffset = this.isRtl ? this.active * 100 : -this.active * 100; const dragPercent = this.containerWidth > 0 ? (this.dragOffset / this.containerWidth) * 100 : 0; return `translateX(${baseOffset + dragPercent}%)`; }, next() { if (this.active < this.total - 1) { this.active = this.active + 1; } }, prev() { if (this.active > 0) { this.active = this.active - 1; } }, goTo(idx) { this.active = idx }, openModal(idx) { if (this.isDragging || this.wasDragging) return; // The lightbox is images only. Its surface is touch-action:none // with modalDragStart calling preventDefault() on every touch, // which would swallow the native video control bar - and // native fullscreen is one tap away from the inline player // anyway. Video slides simply never open it. if (this.hasVideos && idx >= this.firstVideoIndex) return; this.modalActive = idx; this.modalOpen = true; document.body.style.overflow = 'hidden'; }, closeModal() { this.resetZoom(); this.modalOpen = false; document.body.style.overflow = 'auto'; }, // Wrap on the image count, not `total`: the modal never shows a // video, so paging must not land on a video index. get modalTotal() { return Math.max(1, this.images.length) }, modalNext() { this.resetZoom(); this.modalActive = (this.modalActive + 1) % this.modalTotal }, modalPrev() { this.resetZoom(); this.modalActive = (this.modalActive - 1 + this.modalTotal) % this.modalTotal }, modalGoTo(idx) { this.resetZoom(); this.modalActive = idx }, // Modal drag/swipe modalDragging: false, modalWasDragging: false, modalStartX: 0, modalDragOffset: 0, // Zoom helpers resetZoom() { this.zoomScale = 1; this.zoomPanX = 0; this.zoomPanY = 0; this.zoomPinching = false; this.zoomPanning = false; }, getTouchDistance(touches) { return Math.hypot( touches[0].clientX - touches[1].clientX, touches[0].clientY - touches[1].clientY ); }, clampPan() { const maxPanX = Math.max(0, (this.zoomScale - 1) * window.innerWidth / 2); const maxPanY = Math.max(0, (this.zoomScale - 1) * window.innerHeight / 2); this.zoomPanX = Math.max(-maxPanX, Math.min(maxPanX, this.zoomPanX)); this.zoomPanY = Math.max(-maxPanY, Math.min(maxPanY, this.zoomPanY)); }, modalDragStart(e) { const isTouch = e.type.includes('touch'); this.lastInputWasTouch = isTouch; // Store touch position for double-tap zoom center if (isTouch && e.touches[0]) { this.zoomLastTouchX = e.touches[0].clientX; this.zoomLastTouchY = e.touches[0].clientY; } // Two fingers: start pinch-to-zoom if (isTouch && e.touches.length === 2) { this.zoomPinching = true; this.zoomInitialDistance = this.getTouchDistance(e.touches); this.zoomInitialScale = this.zoomScale; this.modalDragging = false; this.zoomPanning = false; e.preventDefault(); return; } // Single finger/mouse while zoomed: start panning if (this.zoomScale > 1) { this.zoomPanning = true; this.zoomPanStartX = isTouch ? e.touches[0].clientX : e.clientX; this.zoomPanStartY = isTouch ? e.touches[0].clientY : e.clientY; this.zoomPanOffsetX = this.zoomPanX; this.zoomPanOffsetY = this.zoomPanY; e.preventDefault(); return; } // Single finger not zoomed or mouse: existing swipe // Prevent browser double-tap-to-zoom so our custom handler works if (isTouch) { e.preventDefault(); } if (this.total <= 1) return; this.modalDragging = true; this.modalStartX = isTouch ? e.touches[0].clientX : e.clientX; this.modalDragOffset = 0; }, modalDragMove(e) { const isTouch = e.type.includes('touch'); // Pinch-to-zoom if (this.zoomPinching && isTouch && e.touches.length >= 2) { e.preventDefault(); const newDist = this.getTouchDistance(e.touches); let newScale = this.zoomInitialScale * (newDist / this.zoomInitialDistance); this.zoomScale = Math.max(1, Math.min(4, newScale)); this.clampPan(); return; } // Panning while zoomed if (this.zoomPanning) { e.preventDefault(); const px = isTouch ? e.touches[0].clientX : e.clientX; const py = isTouch ? e.touches[0].clientY : e.clientY; const dx = px - this.zoomPanStartX; const dy = py - this.zoomPanStartY; this.zoomPanX = this.zoomPanOffsetX + dx; this.zoomPanY = this.zoomPanOffsetY + dy; this.clampPan(); return; } // Existing swipe logic if (!this.modalDragging) return; e.preventDefault(); const x = isTouch ? e.touches[0].clientX : e.clientX; this.modalDragOffset = x - this.modalStartX; }, modalDragEnd(e) { const isTouch = e && e.type && e.type.includes('touch'); // End pinch if (this.zoomPinching) { this.zoomPinching = false; // Snap to 1 if nearly unzoomed if (this.zoomScale < 1.1) { this.resetZoom(); } this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); // If one finger remains after pinch, start panning if (isTouch && e.touches && e.touches.length === 1 && this.zoomScale > 1) { this.zoomPanning = true; this.zoomPanStartX = e.touches[0].clientX; this.zoomPanStartY = e.touches[0].clientY; this.zoomPanOffsetX = this.zoomPanX; this.zoomPanOffsetY = this.zoomPanY; } return; } // End pan if (this.zoomPanning) { this.zoomPanning = false; this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); // Double-tap to zoom out while panned if (isTouch) { const now = Date.now(); if (now - this.zoomLastTap < 300) { this.zoomAnimating = true; setTimeout(() => { this.zoomAnimating = false; }, 300); this.resetZoom(); this.zoomLastTap = 0; } else { this.zoomLastTap = now; } } return; } // Existing swipe end logic const wasDragging = this.modalDragging; if (this.modalDragging) { this.modalDragging = false; const absDrag = Math.abs(this.modalDragOffset); if (absDrag > 5) { this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 100); } const threshold = 80; if (absDrag > threshold) { if (this.isRtl) { this.modalDragOffset < 0 ? this.modalPrev() : this.modalNext(); } else { this.modalDragOffset > 0 ? this.modalPrev() : this.modalNext(); } this.modalDragOffset = 0; this.zoomLastTap = 0; return; } this.modalDragOffset = 0; } // Double-tap detection (works for both zoomed and not zoomed) if (isTouch) { const now = Date.now(); if (now - this.zoomLastTap < 300) { this.zoomAnimating = true; setTimeout(() => { this.zoomAnimating = false; }, 300); this.modalWasDragging = true; setTimeout(() => { this.modalWasDragging = false; }, 200); if (this.zoomScale > 1) { this.resetZoom(); } else { const cx = this.zoomLastTouchX - window.innerWidth / 2; const cy = this.zoomLastTouchY - window.innerHeight / 2; this.zoomScale = 2.5; this.zoomPanX = -cx * (this.zoomScale - 1) / this.zoomScale; this.zoomPanY = -cy * (this.zoomScale - 1) / this.zoomScale; this.clampPan(); } this.zoomLastTap = 0; return; } this.zoomLastTap = now; // Single tap on backdrop: close modal (touch equivalent of @click.self) if (e.target === e.currentTarget) { this.closeModal(); } } }, switchToVariation(attrValueId) { const varImages = this.variationImagesMap[attrValueId]; let newImages, newLargeImages, newLqipImages; if (varImages && varImages.images && varImages.images.length > 0) { newImages = varImages.images; newLargeImages = varImages.largeImages || varImages.images; newLqipImages = varImages.lqipImages || []; } else { newImages = this.defaultImages; newLargeImages = this.defaultLargeImages; newLqipImages = this.defaultLqipImages; } // Show loading state while first image loads this.imageLoading = true; const firstImg = new Image(); firstImg.onload = () => { this.localImages = newImages; this.localLargeImages = newLargeImages; this.localLqipImages = newLqipImages; this.active = 0; this.modalActive = 0; this.imageLoading = false; }; firstImg.onerror = () => { this.localImages = newImages; this.localLargeImages = newLargeImages; this.localLqipImages = newLqipImages; this.active = 0; this.modalActive = 0; this.imageLoading = false; }; firstImg.src = newImages[0]; // If already cached, onload fires synchronously or near-instantly } }" x-on:keydown.escape.window="closeModal()" x-on:keydown.arrow-left.window="modalOpen && modalPrev()" x-on:keydown.arrow-right.window="modalOpen && modalNext()" x-on:switch-variation-images.window="switchToVariation($event.detail.attrValueId ?? $event.detail[0]?.attrValueId)">
/

ماكينة إزالة الشعر الكلاسيكية Classic Epilator من إنزوENZO Classic Epilator Model EN-6089

ENZO Professional Electric Thread Epilator EN-6088 إنزو ENZO العلامة الإيطالية المعروفة في أجهزة العناية الشخصية تقدم حفافة EN-6088 الاحترافية بتقنية الخيط الكهربائي، لتمنحك إزالة دقيقة للشعر من الجذور بسهولة وراحة داخل المنزل، مع نتائج ناعمة تدوم لفترة أطول دون الحاجة إلى الشمع أو الحلاقة التقليدية. • تعتمد على تقنية الخيط القطني لإزالة الشعر من الجذور بدقة عالية • تزيل حتى الشعيرات القصيرة والخفيفة التي يصعب التخلص منها بالطرق التقليدية • تمنح البشرة نعومة تدوم لفترة أطول مقارنة بالحلاقة • مناسبة للوجه والشارب والذقن والخدين والرقبة وكذلك الذراعين والساقين والإبطين • تساعد على تقليل ظهور الشعر بسرعة مع الاستخدام المنتظم • تصميم لاسلكي قابل لإعادة الشحن عبر USB لسهولة الاستخدام في أي مكان • خفيفة الوزن وسهلة الحمل والتخزين • تأتي مع بكرة خيط قطني وملحقات تساعد على الاستخدام العملي • مناسبة للاستخدام المنزلي مع نتائج دقيقة تشبه مراكز التجميل • تساعد على الحفاظ على نعومة البشرة وإبراز صفائها وإشراقتها

المكونات

• نظام إزالة شعر يعتمد على الخيط القطني الطبيعي لالتقاط الشعر من الجذور
• محرك كهربائي يمنح حركة ثابتة وسريعة للخيط أثناء الاستخدام
• بطارية قابلة لإعادة الشحن عبر منفذ USB للاستخدام اللاسلكي
• بكرة خيط قطنية مخصصة لسهولة الاستبدال عند الحاجة
• بودرة مرفقة في بعض الإصدارات للمساعدة على امتصاص الرطوبة وتحسين كفاءة إزالة الشعر
• هيكل مريح وخفيف يوفر تحكماً أفضل أثناء الاستخدام

طريقة الاستخدام

• نظفي البشرة وجففيها جيداً قبل البدء
• يمكن وضع كمية قليلة من البودرة على البشرة إذا كانت رطبة
• ركبي الخيط القطني بالشكل الصحيح وفق مسار الجهاز
• شغلي الجهاز ومرريه بلطف بعكس اتجاه نمو الشعر دون الضغط على البشرة
• بعد الانتهاء استخدمي جل الألوفيرا أو كريم مهدئ لترطيب البشرة وتهدئتها
• نظفي الجهاز والخيط بعد كل استخدام للحفاظ على الأداء والنظافة

التحذيرات

• للاستعمال الخارجي فقط
• لا يستخدم على البشرة الملتهبة أو المجروحة أو المصابة بالحروق
• تجنبي استخدامه على الشامات أو الجروح المفتوحة
• أوقفي الاستخدام عند ظهور تهيج شديد أو حساسية غير طبيعية
• يحفظ بعيداً عن الماء أثناء الشحن وبعيداً عن متناول الأطفال
• ينظف الجهاز بعد كل استخدام ويحفظ في مكان جاف

0 (0 تقييمات)

لا توجد تقييمات بعد. كن أول من يقيم هذا المنتج!

تسجيل الدخول لكتابة تقييم

منتجات مرتبطة

من نحن
  • متجر باريس متخصص في منتجات ماركة وموثوقة وبأسعار تنافسية مقابل الجودة في مجال العناية الصحية والجمالية والعلاجية، نوفر منتجات مختارة بعناية تساعد على تحسين صحة الشعر والبشرة والجسم، مع التركيز على الجودة والنتائج الفعالة وتجربة تسوق سهلة وسريعة. احذروا المنتجات المحلية الرخيصة حتى وإن كانت تشبه المنتجات الماركات الأصلية
التصنيفات
اتصل بنا
  • للاستفسارات أو الطلبات يرجى التواصل معنا عبر واتساب، فريقنا جاهز لخدمتكم والرد على جميع أسئلتكم بسرعة. ‏‪07819959299

تم إنشاء وتصميم المتجر الإلكتروني بواسطة ترينافو

™Paris Store متجر باريس لطلب المنتجات الاتصال بالرقم(07819959299) او النقر على علامة واتساب او ادخاله يدويا اذا تعثر العثور عليه هنا وتزويدنا ب(رقم الموبايل)و(العنوان)و(صورة المنتج)و(عدد القطع) التوصيل لجميع المحافظات.

أضف متجرنا إلى شاشتك الرئيسية

  1. 1 اضغط على زر المشاركة في شريط المتصفح
  2. 2 اختر "إضافة إلى الشاشة الرئيسية"