Contrôle des Empreintes Digitales
Appel par Microphone
Audio de Haute Qualité
39.98
19.99
Acheter Maintenant
SIXRAISONS DE
CHOISIR DES ÉCOUTEURS
Nouveau Écouteurs à Conduction
  • ERGONOMIE
    Caché dans l'oreille
    sans lumière clignotante
  • AFFICHAGE DE L'ALIMENTATION
    Vérifier le niveau de la batterie à tout moment.
  • JOUER PENDANT
    24 HEURES
    Il peut jouer en continu pendant
    24 heures avec un compartiment de charge
  • PAVILLON DYNAMIQUE DE 13 MM
    Qualité sonore HF de mille yuans, basses solides et puissantes
  • AUTO-APPAIRAGE
    Lorsque vous retirez les écouteurs, ils
    se couplent automatiquement avec votre téléphone.
  • BLUETOOTH 5.3
    Consommation d'énergie réduite de près de 50 %, une plus longue durée de vie de la batterie
ÉCOUTEURS À OREILLE OUVERTE
Conception d'oreille ouverte
Autres écouteurs intra-auriculaires
Les écouteurs peuvent être placés délicatement et fermement sur le dessus de l'oreille.
OPÉRATION PAR SIMPLE CONTACT
CLIC SIMPLE
SON DE L'ADDITION
ET DE LA SOUSTRACTION
DOUBLE CLIC
LECTURE/PAUSE
RÉPONDRE / RACCROCHER
APPUI LONG PENDANT 2 SECONDES
CHANSON PRÉCÉDENTE/SUIVANTE
ACHETER MAINTENANT
STABLE ET NE TOMBE PAS FACILEMENT

Une Nouvelle Façon d'Entendre !

Né pour le sport !

IPX5
IMPERMÉABLE À L'EAU
AUTONOMIE DE 24 HEURES AFFICHAGE DIGITAL
GAUCHE

ALIMENTATION
DE L'ÉCOUTEUR

DROITE

ALIMENTATION
DE L'ÉCOUTEUR

Profitez de 24 heures de lecture avec une seule charge et de 24 heures supplémentaires avec l'étui de chargement.

L'affichage LED de la puissance vous informe de l'état de la batterie, pour que vous n'ayez jamais à craindre d'être à court d'énergie.

PUISSANT

SON STÉRÉO
Audio adaptative
Cavité de structure acoustique
Les écouteurs sans fil à conduction osseuse sont équipés de crochets d'oreille, qui s'adaptent confortablement à vos oreilles pendant longtemps.
Prise en charge du mode jeu, de la faible latence et de la localisation par reconnaissance vocale
Ne manquez jamais les avis importants
Prêtez attention à l'environnement lorsque vous faites de l'exercice
Écouter de la musique tout en pouvant parler

La conception ouverte des écouteurs à conduction osseuse vous permet d'être conscient de votre environnement. Que vous fassiez du vélo, de la marche, de la course à pied, de l'exercice ou du sport, restez conscient de votre environnement et en sécurité.

CONFORTABLE À
PORTER
APPELS CLAIRS
CONFORTABLE À
PORTER
APPELS CLAIRS
SPÉCIFICATIONS
Couleur :
Noire
Blanche
Peau
Quantité :
19.99
39.98
Ajoutez au panier
Achetez 2, obtenez 10% de réduction!
Achetez maintenant
De plus en plus d'utilisateurs choisissent d'acheter deux pièces
Livraison dans le monde entier
Retours gratuits
Assistance à la clientèle 24 heures sur 24, 7 jours sur 7
Paiements sécurisés
Ajouté avec succès !
/** @private {string} */ class SpzCustomAnchorScroll extends SPZ.BaseElement { static deferredMount() { return false; } constructor(element) { super(element); /** @private {Element} */ this.scrollableContainer_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } buildCallback() { this.viewport_ = this.getViewport(); this.initActions_(); } setTarget(containerId, targetId) { this.containerId = '#' + containerId; this.targetId = '#' + targetId; } scrollToTarget() { const container = document.querySelector(this.containerId); const target = container.querySelector(this.targetId); const {scrollTop} = container; const eleOffsetTop = this.getOffsetTop_(target, container); this.viewport_ .interpolateScrollIntoView_( container, scrollTop, scrollTop + eleOffsetTop ); } initActions_() { this.registerAction( 'scrollToTarget', (invocation) => this.scrollToTarget(invocation?.caller) ); this.registerAction( 'setTarget', (invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId) ); } /** * @param {Element} element * @param {Element} container * @return {number} * @private */ getOffsetTop_(element, container) { if (!element./*OK*/ getClientRects().length) { return 0; } const rect = element./*OK*/ getBoundingClientRect(); if (rect.width || rect.height) { return rect.top - container./*OK*/ getBoundingClientRect().top; } return rect.top; } } SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll); const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings"; class SpzCustomStrengthenTrust extends SPZ.BaseElement { constructor(element) { super(element); this.renderElement_ = null; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { this.xhr_ = SPZServices.xhrFor(this.win); const renderId = this.element.getAttribute('render-id'); SPZCore.Dom.waitForChild( document.body, () => !!document.getElementById(renderId), () => { this.renderElement_ = SPZCore.Dom.scopedQuerySelector( document.body, `#${renderId}` ); if (this.renderElement_) { this.render_(); } this.registerAction('track', (invocation) => { this.track_(invocation.args); }); } ); } render_() { this.fetchData_().then((data) => { if (!data) { return; } SPZ.whenApiDefined(this.renderElement_).then((apis) => { apis?.render(data); document.querySelector('#strengthen-trust-render-1710495796818').addEventListener('click',(event)=>{ if(event.target.nodeName == 'A'){ this.track_({type: 'trust_content_click'}); } }) }); }); } track_(data = {}) { const track = window.sa && window.sa.track; if (!track) { return; } track('trust_enhancement_event', data); } parseJSON_(string) { let result = {}; try { result = JSON.parse(string); } catch (e) {} return result; } fetchData_() { return this.xhr_ .fetchJson(STRENGTHEN_TRUST_URL) .then((responseData) => { if (!responseData || !responseData.data) { return null; } const data = responseData.data; const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => { return result.concat(Object.assign(moduleSetting, { logos: (moduleSetting.logos || []).map((item) => { return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item; }) })); }, []); return Object.assign(data, { module_settings: moduleSettings, isEditor: window.self !== window.top, }); }); } } SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust);

❤️ASTUCE : Tous nos produits sont authentiques, avec de vrais brevets, les contrefaçons doivent être examinées ! Veuillez marquer nos produits !!!

😊Si vous n'êtes pas satisfait des articles reçus, veuillez nous contacter dans les 15 jours suivant la réception et nous vous apporterons la meilleure assistance possible !

🚢Livraison >> Livraison express efficace disponible dans toute la France.

🔥98,9 % de nos clients achètent 2 articles ou plus. Obtenez le vôtre dès maintenant !

Si vous avez encore des questions, veuillez nous contacter directement à l'adresse e-mail 👉 service@bonusvogue.com

émettre un commentaire
Commentaire de clients
tu as atteint le fond
Le plus récent
Le plus aimé
Meilleures notes
Notes les plus basses
×
class SpzCustomFileUpload extends SPZ.BaseElement { constructor(element) { super(element); this.uploadCount_ = 0; this.fileList_ = []; } buildCallback() { this.action = SPZServices.actionServiceForDoc(this.element); this.registerAction('upload', (data) => { this.handleFileUpload_(data.event?.detail?.data || []); }); this.registerAction('delete', (data) => { this.handleFileDelete_(data?.args?.data); }); this.registerAction('preview', (data) => { this.handleFilePreview_(data?.args?.data); }); this.registerAction('limit', (data) => { this.handleFileLimit_(); }); this.registerAction('sizeLimit', (data) => { this.handleFileSizeLimit_(); }); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } setData_(count, file) { this.uploadCount_ = count; this.fileList_ = file; } handleFileUpload_(data) { data.forEach(i => { if(this.fileList_.some(j => j.url === i.url)) return; this.fileList_.push(i); }) this.uploadCount_++; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileUpload", { count: this.uploadCount_, files: this.fileList_}); if(this.fileList_.length >= 5){ document.querySelector('#review_upload').style.display = 'none'; } if(this.fileList_.length > 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '8px'; } } handleFileDelete_(index) { this.fileList_.splice(index, 1); this.uploadCount_--; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleFileDelete", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; if(this.fileList_?.length === 0){ document.querySelector('.apps-reviews-write-anonymous-box').style.marginTop = '132px'; } } handleFilePreview_(index) { const finalPreviewData = this.fileList_[index]; const filePreviewModal = document.getElementById('filePreviewModal'); const fullScreenVideo = document.getElementById('fullScreenVideo'); const fullScreenImage = document.getElementById('fullScreenImage'); const previewModalClose = document.getElementById('previewModalClose'); const previewLoading = document.getElementById('previewLoading'); filePreviewModal.style.display = 'block'; previewLoading.style.display = 'flex'; if(finalPreviewData?.type === 'video'){ const media = this.mediaParse_(this.fileList_[index]?.url); fullScreenVideo.addEventListener('canplaythrough', function() { previewLoading.style.display = 'none'; }); fullScreenImage.src = ''; fullScreenImage.style.display = 'none'; fullScreenVideo.style.display = 'block'; fullScreenVideo.src = media.mp4 || ''; } else { fullScreenImage.onload = function() { previewLoading.style.display = 'none'; }; fullScreenVideo.src = ''; fullScreenVideo.style.display = 'none'; fullScreenImage.style.display = 'block'; fullScreenImage.src = finalPreviewData.url; } previewModalClose.addEventListener('click', function() { filePreviewModal.style.display = 'none'; }); } handleFileLimit_() { alert(window.AppReviewsLocale.comment_file_limit || 'please do not upload files more than 5'); this.triggerEvent_("handleFileLimit"); } handleFileSizeLimit_() { alert(window.AppReviewsLocale.comment_file_size_limit || 'File size does not exceed 10M'); } clear(){ this.fileList_ = []; this.uploadCount_ = 0; sessionStorage.setItem('fileList', JSON.stringify(this.fileList_)); this.triggerEvent_("handleClear", { count: this.uploadCount_, files: this.fileList_}); document.querySelector('#review_upload').style.display = 'block'; } mediaParse_(url) { var result = {}; try { url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) { try { result[key] = decodeURIComponent(value); } catch (e) { result[key] = value; } }); result.preview_image = url.split('?')[0]; } catch (e) {}; return result; } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, name, data); this.action.trigger(this.element, name, event); } } SPZ.defineElement('spz-custom-file-upload', SpzCustomFileUpload);
The review would not show in product details on storefront since it does not support to.
class SpzSmartBlockComponent extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = null; this.container_ = null; this.i18n_ = {}; this.config_ = {}; this.show_type_ = 3; this.product_resource_id_ = ''; this.collection_resource_id_ = ''; this.cart_items_ = []; this.customer_id_ = ''; this.order_id_ = ''; } static deferredMount() { return false; } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } buildCallback() { const template_type = window.SHOPLAZZA.meta.page.template_type; if (template_type === 1) { this.show_type_ = 3; this.product_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 2) { this.show_type_ = 4; this.collection_resource_id_ = window.SHOPLAZZA.meta.page.resource_id; } else if (template_type === 15){ this.show_type_ = 5; } else if (template_type === 13){ this.show_type_ = 6; } else if (template_type === 20){ this.show_type_ = 7; this.customer_id_ = window.SHOPLAZZA.customer.customer_id; } else if (template_type === 35){ this.show_type_ = 8; this.order_id_ = window.location.pathname.split('/').pop(); } this.templates_ = SPZServices.templatesForDoc(this.element); this.setAction_(); } mountCallback() { console.log('smart mounted'); const that = this; const themeName = window.SHOPLAZZA.theme.merchant_theme_name; const isGeek = /Geek/.test(themeName); this.fetchRules().then((res) => { if (res && res.rules && res.rules.length) { const blockEl = document.getElementById('smart_recommend_block'); SPZ.whenApiDefined(blockEl).then((api) => { api.render({data: res}, true).then(() => { if (isGeek && that.show_type_ === 6) { blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0'; } const recommendStyle = document.createElement('style'); recommendStyle.innerHTML = ` .plugin__recommend_container,.app-recommend-card { display: none !important; } `; document.head.appendChild(recommendStyle); const fetchList = []; res.rules.forEach((rule) => { fetchList.push(this.fetchRuleProductList(rule.id)); }); const fetchAll = Promise.all(fetchList); fetchAll.then((p_res) => { res.rules.forEach((rule, index) => { rule.products = p_res[index] && p_res[index].products; const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id); SPZ.whenApiDefined(ruleEl).then((api) => { api.render({data: rule}, true).then(() => { that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){ that.trackRuleImpress(rule); }); const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`); btnElList.forEach((btnEl) => { if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) { btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color; btnEl.style.color = rule.config.quick_shop_button_text_color; } }) }); }); }); }); }) }) } else { if (window.top !== window.self) { const template_type = window.SHOPLAZZA.meta.page.template_type; const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder'); SPZ.whenApiDefined(holderEl).then((api) => { api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true); }); } } }); } setAction_() { this.registerAction('quickShop', (data) => { const that = this; const product_id = data.args.product_id; const productIndex = data.args.productIndex; const rule_id = data.args.rule_id; const ssp = data.args.ssp; const scm = data.args.scm; const cfb = data.args.cfb; const ifb = data.args.ifb; const modalRender = document.getElementById('smart_recommend_product_modal_render'); if (product_id) { this.fetchProductData(product_id).then((res) => { const product = res.products && res.products.length && res.products[0] || {}; product.cfb = cfb; product.ifb = ifb; SPZ.whenApiDefined(modalRender).then((api) => { api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => { const modalEl = document.getElementById('smart_recommend_product_modal'); SPZ.whenApiDefined(modalEl).then((modal) => { that.impressListen('#smart_recommend_product_modal', function(){ that.trackQuickShop({ rule_id: rule_id, product_id: product_id }); }); modal.open(); }); const formEl = document.getElementById('smart_recommend_product_form'); SPZ.whenApiDefined(formEl).then((form) => { form.setProduct(product); }); const variantEl = document.getElementById('smart_recommend_product_variants'); SPZ.whenApiDefined(variantEl).then((variant) => { variant.handleRender(product); }); }); }) }); } }); this.registerAction('handleScroll', (data) => { this.directTo(data.args.rule_id, data.args.direction); }); this.registerAction('handleProductChange', (data) => { const variant = data.args.data.variant; const product = data.args.data.product; const imageRenderEl = document.getElementById('smart_recommend_product_image'); SPZ.whenApiDefined(imageRenderEl).then((api) => { api.render({ variant: variant, product: product }, true); }); }); this.registerAction('handleAtcSuccess', (detail) => { const data = detail.args; data.data.product = data.data.product || {}; data.data.variant = data.data.variant || {}; const product_id = data.data.product.id; const product_title = data.data.product.title; const variant_id = data.data.variant.id; const price = data.data.variant.price; const rule_id = data.rule_id; const aid = `smart_recommend.${this.show_type_}.${rule_id}`; const ifb = data.data.product.ifb; const cfb = data.data.product.cfb; const ssp = data.ssp; const scm = data.scm; const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`; const params = { id: product_id, product_id: product_id, number: 1, name: product_title, variant_id: variant_id, childrenId: variant_id, item_price: price, source: 'add_to_cart', _extra: { aid: aid, ifb: ifb, cfb: cfb, scm: scm, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, ssp: ssp, } }; this.tranckAddToCart(params); }); this.registerAction('addATCHook', (data) => { const params = data.args; const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`; this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({ event: 'dj.addToCart', params: { aid: `smart_recommend.${this.show_type_}.` + params.rule_id, ssp: params.ssp, scm: params.scm, cfb: params.cfb, spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`, }, once: true }); }); } tranckAddToCart(detail) { if (window.$) { window.$(document.body).trigger('dj.addToCart', detail); } } fetchRules() { const payload = { show_type: this.show_type_, }; let that = this; if (this.show_type_ === 6) { let line_items = []; return this.fetchCart().then((res) => { if (res && res.cart && res.cart.line_items) { line_items = res.cart.line_items.map((item) => { return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price } }); } payload.line_items = line_items; that.cart_items_ = line_items; return that.fetchRulesRequest(payload); }); } else { if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return this.fetchRulesRequest(payload); } } fetchRulesRequest(payload) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }); } fetchCart() { return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`) .then((res) => { if (res.ok) { return res.json(); } }); } fetchRuleProductList(rule_id) { const payload = { page: 1, limit: 100, fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"], rule_id: rule_id, }; if (this.show_type_ === 3) { payload.line_items = [{ product_id: this.product_resource_id_ }]; } else if (this.show_type_ === 4) { payload.collection_id = this.collection_resource_id_; } else if (this.show_type_ === 6) { payload.line_items = this.cart_items_; } else if (this.show_type_ === 7) { payload.customer_id = this.customer_id_; } else if (this.show_type_ === 8) { payload.order_id = this.order_id_; } return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); }); } fetchProductData(product_id) { return fetch(window.SHOPLAZZA.routes.root + "/api/possum/products", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ product_ids: [product_id], fields: [ "images", "options", "min_price_variant", "variants"] }) }).then(function(res){ if(res.ok){ return res.json(); } }).catch(function(err){ console.log(err); const loadingEl = document.getElementById('smart_recommend_loading'); if (loadingEl) { loadingEl.style.display = 'none'; } }); } getStyle(ele, style) { if (!ele) return; if (window.getComputedStyle) { return window.getComputedStyle(ele)[style]; } return ele.currentStyle[style]; } directTo(id, direction) { const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`); const blockWidth = parseInt(this.getStyle(scrollElement, 'width')); const scrollLength = (blockWidth * 0.19 - 12) * 5; const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth; if (!scrollElement) return; if (direction === 'left') { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: Math.max(scrollElement.scrollLeft - scrollLength, 0), behavior: 'smooth' }); } else { if (document.dir === 'rtl') { scrollElement.scrollTo({ left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); return; } scrollElement.scrollTo({ left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength, behavior: 'smooth' }); } } trackRuleImpress(rule) { if (window.sa && window.sa.track) { window.sa.track("plugin_common", { plugin_name: "upsell", event_type: "impressions", rule_id: rule.id, ssp: rule.ssp, scm: rule.scm, show_type: this.show_type_, support_app_block: window.SHOPLAZZA.theme.support_app_block }); window.sa.track("module_impressions", { aid: `smart_recommend.${this.show_type_}.${rule.id}`, support_app_block: window.SHOPLAZZA.theme.support_app_block }); } } trackQuickShop(data) { window.sa && sa.track && sa.track("plugin_common", { plugin_name: "upsell", event_type: "quick_shop", rule_id: data.rule_id, product_id: data.product_id, show_type: this.show_type_, }); } impressListen(selector, cb) { const el = document.querySelector(selector); const onImpress = (e) => { if (e) { e.stopPropagation(); } cb(); }; if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress) } else if (el) { onImpress(); } } } SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);
const TAG = 'spz-custom-painter-button-animation'; const MAX_ITERATION_COUNT = 99999999; const SITE = (window.C_SETTINGS && window.C_SETTINGS.routes && window.C_SETTINGS.routes.root) || ''; const ADD_TO_CART_ANIMATION_SETTING = `${SITE}/api/marketing_atmosphere_app/add_to_cart_btn_animation/setting`; class SpzCustomPainterButtonAnimation extends SPZ.BaseElement { /**@override */ static deferredMount() { return false; } /** @param {!SpzElement} element */ constructor(element) { super(element); /** @private {!../../src/service/xhr-impl.Xhr} */ this.xhr_ = SPZServices.xhrFor(this.win); /** @private {Object} */ this.data_ = null; /** @private {Element} */ this.addToCartButton_ = null; /** @private {boolean} */ this.productAvailable_ = true; /** @private {number} */ this.timerId_ = null; /** @private {number} */ this.animationExecutionCount_ = 0; /** @private {boolean} */ this.selectedVariantAvailable_ = true; /** @private {number} */ this.delay_ = 5000; /** @private {number} */ this.iterationCount_ = 5; /** @private {string} */ this.animationClass_ = ''; } /** @override */ isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } /** @override */ buildCallback() { this.productAvailable_ = this.element.hasAttribute('product-available'); this.selectedVariantAvailable_ = this.element.hasAttribute('selected-variant-available'); } /** @override */ mountCallback() { this.render_(); } /** @private */ render_() { if (!this.productAvailable_) { return; } this.fetch_().then((data) => { if (!data) { return; } this.data_ = data; this.animationClass_ = `painter-${data.animation_name}-animation`; this.iterationCount_ = data.animation_iteration_count === 'infinite' ? MAX_ITERATION_COUNT : data.animation_iteration_count; const animationDuration = 1; const animationDelay = data.animation_delay || 5; this.delay_ = (animationDuration + animationDelay) * 1000; this.handleButtonEffect_(); }); } /** * @param {JsonObject} data * @return {(null|Object)} * @private */ parseJson_(data) { try { return JSON.parse(data); } catch (e) { return null; } } /** * @return {Promise} * @private */ fetch_() { return this.xhr_.fetchJson(ADD_TO_CART_ANIMATION_SETTING).then((data) => { if (!data || !data.enabled) { return null; } return this.parseJson_(data.detail); }); } /** @private */ getAddToCartButton_() { this.addToCartButton_ = SPZCore.Dom.scopedQuerySelector( document.body, '[data-section-type="product"] [role="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product"] [data-click="addToCart"]' ); } /** @private */ restartAnimation_() { this.addToCartButton_.classList.remove(this.animationClass_); this.addToCartButton_./* OK */ offsetWidth; this.addToCartButton_.classList.add(this.animationClass_); this.animationExecutionCount_++; } /** @private */ clearTimer_() { this.win.clearInterval(this.timerId_); this.timerId_ = null; } /** @private */ setupTimer_() { this.timerId_ = this.win.setInterval(() => { this.restartAnimation_(); if (this.animationExecutionCount_ >= this.iterationCount_) { this.removeAnimationClass_(); this.clearTimer_(); } }, this.delay_); } /** @private */ restartTimer_() { if (this.animationExecutionCount_ >= this.iterationCount_) { this.removeAnimationClass_(); return; } this.setupTimer_(); } /** @private */ listenVariantChange_() { SPZUtils.Event.listen(self.document, 'dj.variantChange', (e) => { const selectedVariant = e.detail && e.detail.selected; if (!selectedVariant) { return; } const {available} = selectedVariant; if (this.selectedVariantAvailable_ !== available) { this.selectedVariantAvailable_ = available; this.clearTimer_(); if (available) { this.restartTimer_(); } } }); } /** @private */ removeAnimationClass_() { this.win.setTimeout(() => { this.addToCartButton_.classList.remove(this.animationClass_); }, 1000); } /** @private */ handleButtonEffect_() { this.getAddToCartButton_(); if (!this.addToCartButton_) { return; } if (this.selectedVariantAvailable_) { ++this.animationExecutionCount_; this.addToCartButton_.classList.add(this.animationClass_); if (this.iterationCount_ === 1) { this.removeAnimationClass_(); return; } this.setupTimer_(); } this.listenVariantChange_(); } } SPZ.defineElement(TAG, SpzCustomPainterButtonAnimation);