1000D encrypted Oxford Cloth Tactical Body Armor Molle Quick-Release Plate Carrier

$179.99
Sold 9
Color:  CP Green
Quantity
Share the love
Free worldwide shipping
Free returns
Secure payments
10 year warranty
const TAG = 'spz-custom-revue-util'; const DEFAULT_DELAY_TIME = 100; class SpzCustomRevueUtil extends SPZ.BaseElement { constructor(element) { super(element); this.templates_ = SPZServices.templatesForDoc(); } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); } static deferredMount() { return false; } mountCallback() { } debounceRender(el, thisEl, containerStr) { return this.smoothRender_(el, thisEl, containerStr).then(() => this.attemptToFit_(thisEl)); } smoothRender_(newEl, thisEl, containerStr) { const that = this; that.appendAsUnvisibleContainer_(newEl, thisEl); const components = newEl.querySelectorAll('[layout]'); return Promise.race([ Promise.all( Array.prototype.map.call(components, (e) => SPZ.whenDefined(e).then(() => e.whenBuilt()) ) ), SPZServices.timerFor(that.win).promise(DEFAULT_DELAY_TIME), ]).then(() => { return containerStr !== 'form_' ? thisEl.mutateElement(() => that.quickReplace(thisEl, newEl)) : thisEl.mutateElement(() => that.quickReplaceForm(thisEl, newEl)); }); } quickReplace(thisEl, newEl) { thisEl.container_ && this.toggleVisible_(thisEl.container_); this.toggleVisible_(newEl, true); thisEl.container_ && SPZCore.Dom.removeElement(thisEl.container_); thisEl.container_ = newEl; }; quickReplaceForm(thisEl, newEl) { thisEl.form_ && this.toggleVisible_(thisEl.form_); this.toggleVisible_(newEl, true); const children = thisEl.form_.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.toggleVisible_(thisEl.form_, true); thisEl.form_.appendChild(newEl); }; appendAsUnvisibleContainer_(el, thisEl) { this.toggleVisible_(el); thisEl.element.appendChild(el); } attemptToFit_(thisEl) { const fitFunc = () => { thisEl.mutateElement(this.setElementHeight_.bind(thisEl)); }; const container = thisEl.container_ || thisEl.form_; if (container) { const children = container.querySelectorAll('*:not(template)'); const spzChildren = Array.prototype.filter .call(children, SPZUtils.isSpzElement) .filter((e) => !(e.isMount && e.isMount())); spzChildren .map((e) => SPZ.whenDefined(e).then(() => e.whenMounted())) .forEach((p) => p.then(() => fitFunc())); } return fitFunc(); } setElementHeight_() { const targetHeight = (this.container_ || this.form_)?./*OK*/ scrollHeight; const height = this.element./*OK*/ offsetHeight; if (height !== targetHeight) { SPZCore.Dom.setStyles(this.element, { height: `${targetHeight}px`, }); } } toggleVisible_(el, visible = false) { if (!visible) { el.classList.add('i-spzhtml-layout-fill'); SPZCore.Dom.setStyles(el, { 'z-index': -100000, 'opacity': 0, }); } else { el.classList.remove('i-spzhtml-layout-fill'); SPZCore.Dom.setStyles(el, { 'z-index': 'auto', 'opacity': 1, }); } } setMinWidth_() { const targetWidth = this.container_?./*OK*/ scrollWidth; const width = this.element./*OK*/ offsetWidth; if (width !== targetWidth) { SPZCore.Dom.setStyles(this.element, { 'min-width': `${targetWidth}px`, }); } } triggerEvent_ = (name, data) => { const event = SPZUtils.Event.create(this.win, `${TAG}.${name}`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SpzCustomRevueUtil); const TAG = 'spz-custom-revue-star'; class SPZCustomRevueStar extends SPZ.BaseElement { constructor(element) { super(element); } static deferredMount() { return false; } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.starNum = this.element.getAttribute('starNum'); this.starTotal = this.element.getAttribute('starTotal'); this.showStarText = this.element.getAttribute('showStarText'); this.starColor = this.element.getAttribute('color'); this.interact = this.element.getAttribute('interact'); this.starSize = this.element.getAttribute('starSize') || 14; } mountCallback = () => { this.doRender_({ starTotal: this.starTotal, totalArray: Array.from({ length: Number(this.starTotal) }, (v, k) => k + 1), starNum: this.starNum, showStarText: this.showStarText, starColor: this.starColor, starSize: this.starSize }).then(() => { if (this.interact) { this.addEventListeners_(); } }); } addEventListeners_ = () => { const stars = document.querySelectorAll('.revue-star__star'); stars.forEach(star => { star.addEventListener('click', event => { const starEl = star.closest('.revue-star__star'); const starIndex = Number(starEl.dataset.index); let isHalf = event.offsetX < star.offsetWidth / 2; // rtl if (document.documentElement.getAttribute('dir') === 'rtl') { isHalf = event.offsetX > star.offsetWidth / 2; } const starValue = isHalf ? starIndex - 0.5 : starIndex; this.starClickHandler_({ value: starValue }); }); }); } renderStar = () => { const isRtl = document.documentElement.getAttribute('dir') === 'rtl'; const stars = this.element.querySelectorAll('.revue-star__star'); stars.forEach((star, i) => { const starIndex = i + 1; const starEl = star.querySelector('svg:nth-child(2)'); const isHalf = this.starNum % 1 > 0 && Math.ceil(this.starNum) === starIndex; const isSolid = starIndex <= Math.ceil(this.starNum); starEl.style.display = isSolid ? 'block' : 'none'; if (isHalf) { if (isRtl) { // RTL布局下,如果是半星,显示星星的右半边 starEl.style.clipPath = `polygon(50% 0, 100% 0, 100% 100%, 50% 100%)`; } else { // LTR布局下,如果是半星,显示星星的左半边 starEl.style.clipPath = `polygon(0 0, 50% 0, 50% 100%, 0 100%)`; } } else { starEl.style.clipPath = `polygon(0 0, 100% 0, 100% 100%, 0 100%)` } }); const showCountEle = this.element.querySelector('#revue-star-show-count'); showCountEle && SPZ.whenApiDefined(showCountEle).then((api) => { api.render({ starNum: this.starNum, starTotal: this.starTotal }); }); } doRender_ = (data) => { return this.templates_ .findAndRenderTemplate(this.element, { starSize: this.starSize, ...data }, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }) .then(() => { this.starNum = data.starNum; this.renderStar(); }); } starClickHandler_ = (event) => { this.starNum = event.value; this.renderStar(); this.triggerEvent_('change', { value: event.value }); } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SPZCustomRevueStar) const TAG = 'spz-custom-revue-like'; class SPZCustomRevueLike extends SPZ.BaseElement { constructor(element) { super(element); } static deferredMount() { return false; } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); this.grayColor = this.element.getAttribute('gray_color') || "#BDBDBD"; this.likedColor = this.element.getAttribute('like_color') || "#FFCB44"; this.color = this.grayColor; this.count = this.element.getAttribute('count'); this.revueId = this.element.getAttribute('revue-id'); this.location = this.element.getAttribute('location'); } mountCallback = () => { const likes = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : []; const like = likes.find(item => item.id === this.revueId); if (like) { this.color = like.like_status === 1 ? this.likedColor : this.grayColor; } // 如果location是modal,则找到相同revue-id的list的元素,拿到其count,存在list count变了,但是modal的count没变的情况 if (this.location === 'modal') { const listElement = document.querySelector(`spz-custom-revue-like[revue-id="${this.revueId}"] .revue-like-count`); if (listElement) { this.count = listElement.getAttribute('data-real-count'); } } this.doRender_({ color: this.color, count: this.count }).then(() => { this.addEventListeners_(); if(this.location === 'list') { // modal数量变更,list同步变更 document.addEventListener('like-clicked', (e) => { if (e.detail.location !== this.location && e.detail.id === this.revueId) { this.color = e.detail.like_status === 1 ? this.likedColor : this.grayColor; this.count = e.detail.count; this.element.querySelector('.revue-like__icon').querySelector('svg').setAttribute('fill', this.color); this.element.querySelector('.revue-like__icon').querySelector('svg').querySelector('path').setAttribute('fill', this.color); this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count; this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count); if(this.count > 0){ this.element.querySelector('.revue-like-count').classList.remove('hidden'); }else{ this.element.querySelector('.revue-like-count').classList.add('hidden'); } } }); } }); } addEventListeners_ = () => { const icon = this.element.querySelector('.revue-like__icon'); icon.addEventListener('click', (e) => { e.stopPropagation(); const likeStatus = this.color === this.likedColor ? 0 : 1; this.color = this.color === this.likedColor ? this.grayColor : this.likedColor; this.count = likeStatus === 1 ? parseInt(this.count) + 1 : parseInt(this.count) - 1; icon.querySelector('svg').setAttribute('fill', this.color); icon.querySelector('svg').querySelector('path').setAttribute('fill', this.color); this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count; this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count); if(this.count > 0){ this.element.querySelector('.revue-like-count').classList.remove('hidden'); }else{ this.element.querySelector('.revue-like-count').classList.add('hidden'); } this.postLike(likeStatus); if (this.location === 'modal') { const clickedEvent = new CustomEvent('like-clicked', { detail: { id: this.revueId, like_status: likeStatus, count: this.count, location: this.location } }); document.dispatchEvent(clickedEvent); } }); } setLikeToStorage = (likeToStore) => { if (typeof (Storage) !== 'function') return; const likesInStore = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : []; const reviewIndex = likesInStore.findIndex(item => item.id === likeToStore.id); if (reviewIndex !== -1) { likesInStore[reviewIndex].like_status = likeToStore.like_status; likesInStore[reviewIndex].count = likeToStore.count; } else { likesInStore.push(likeToStore); } sessionStorage.setItem('likes', JSON.stringify(likesInStore)); } doRender_ = (data) => { return this.templates_ .findAndRenderTemplate(this.element, data, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }); } postLike = (likeStatus) => { fetch('/api/comment/like', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ id: this.revueId, status: likeStatus }) }).then((res) => { if (res.status === 200) { this.setLikeToStorage({ id: this.revueId, like_status: likeStatus, count: this.count }); } }); } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SPZCustomRevueLike) const TAG = 'spz-custom-review-media'; class SPZCustomReviewMedia extends SPZ.BaseElement { constructor(element) { super(element); } static deferredMount() { return false; } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.xhr_ = SPZServices.xhrFor(this.win); // data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1 const images = this.element.getAttribute('data-images').split(',') || []; const parsedImages = images.map(image => { return this.mediaParse_(image); }); this.images = parsedImages; this.isPC = window.innerWidth > 960; } mountCallback = () => { this.doRender_({ images: this.images, isPC: this.isPC }).then(() => { }); } doRender_ = (data) => { return this.templates_ .findAndRenderTemplate(this.element, data, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }); } mediaParse_ = function (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, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SPZCustomReviewMedia) const TAG = 'spz-custom-revue-carousel'; class SpzCustomRevueCarourel extends SPZ.BaseElement { constructor(element) { super(element); this.debouncedCartChangeHandler = null; } static deferredMount() { return false; } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.setupAction_(); this.reviewsList = [] this.isPC = window.innerWidth > (window.breakpoint || 960); this.blockIndex = this.element.getAttribute('data-block-index'); this.blockSectionId = this.element.getAttribute('data-section-id'); this.commentConfig = window.globaCarouselSettings[this.blockIndex] const { star_least, only_complex, only_show_selected } = this.commentConfig; this.params = { star_least: Number(star_least) || 1, only_media: !!only_complex, show_reply: true, limit: 20, offset: 0, filter_type: 'product', show_product: true, only_featured: !!only_show_selected, } this.debouncedCartChangeHandler = this.debounce_(this.renderReviewsByCartProducts_.bind(this), 500); } mountCallback = () => { const { isNeedFill, min } = this.getIfFillReviews_(); if (this.blockSectionId == 'cart_drawer') { this.product_ids = this.commentConfig.cart_products_id; } else { this.product_ids = window.SHOPLAZZA.meta.page.resource_id; }; this.params = { ...this.params, product_ids: this.product_ids || '', ...isNeedFill ? { fill_strategy: 'store', fill_min_threshold: min } : {} }; this.fetchConfigReviewsCarousel_(); if (this.blockSectionId == 'cart_drawer') { document.removeEventListener('dj.cartChange', this.debouncedCartChangeHandler); document.addEventListener('dj.cartChange', this.debouncedCartChangeHandler); } } unmountCallback() { document.removeEventListener('dj.cartChange', this.debouncedCartChangeHandler); } setupAction_ = () => { this.registerAction('renderProductCommentModal', async(invocation) => { const { current } = invocation.args; const currentReview = this.reviewsList.find(_data => _data.id == current); const imgArr = currentReview.img.map(image => { const width = this.getUrlKey_('width', image); const height = this.getUrlKey_('height', image); return { width, height, rate: (height/width).toFixed(2)*100, url: image }; }); const modalEle = document.querySelector(`#revueDetailModal-${this.blockSectionId}`); if (modalEle) { SPZ.whenApiDefined(modalEle).then((api) => { api.renderModalFn({ data: { ...currentReview, img: imgArr }, ...this.blockSectionId == 'cart_drawer' ? { mimic_mobile_style: true } : {}, closeCB: () => { const carouselEl = document.querySelector(`#reviews-carousel-${this.blockSectionId}-${this.blockIndex}`); if(carouselEl){ carouselEl.removeAttribute('pause'); } }, commentConfig: this.commentConfig, // 评论配置 layout: '', // 布局 level_type: this.commentConfig.star_least, // 最低星级 show_number: 1 // 显示数量 }); }) const carouselEl = document.querySelector(`#reviews-carousel-${this.blockSectionId}-${this.blockIndex}`); if(carouselEl){ carouselEl.setAttribute('pause', ''); } } }); } getUrlKey_ = (name, url) => { return ( decodeURIComponent( (new RegExp("[?|&]" + name + "=" + "([^&;]+?)(&|#|;|$)").exec( url ) || [, ""])[1].replace(/\+/g, "%20") ) || null ); } getIfFillReviews_ = () => { const { comment_handle_type, review_type, min_comments_count } = this.commentConfig; const min = Number(min_comments_count); const isExistFillType = comment_handle_type !== 'no_carousel_card'; return { isNeedFill: isExistFillType, min: review_type == 'less than' ? min : 1 }; } debounce_ = (func, delay) => { let timeoutId; return (...args) => { // 使用箭头函数保留实例上下文 clearTimeout(timeoutId); timeoutId = setTimeout(() => { func(...args); }, delay); }; } fetchCommentConfig_ = async () => { const response = await fetch('/api/comment-config'); return response.json(); } fetchCommentList_ = async(data) => { const response = await fetch('/api/v1/comments', { method: 'POST', body: JSON.stringify(data) }); return response.json(); } fetchCartList_ = async() => { const response = await fetch(`/api/cart`); return response.json(); } renderReviewsByCartProducts_ = async () => { try { const data = await this.fetchCartList_(); this.product_ids = data?.cart?.line_items.map(item => item.product_id).join(','); if (this.product_ids) { this.params = { ...this.params, product_ids: this.product_ids, }; const commentsRes = await this.fetchCommentList_(this.params); const { isNeedFill, min } = this.getIfFillReviews_(); const isBlank = !isNeedFill && Number(commentsRes.data.count) < min; this.renderReviewsList_({ list: isBlank ? { list: [] } : commentsRes.data, config: this.commentConfig }); } } catch (err) { this.renderEmptyReviewCarousel_(); } } fetchConfigReviewsCarousel_ = ()=> { Promise.all([this.fetchCommentConfig_(), this.fetchCommentList_(this.params)]) .then(([configRes, commentsRes]) => { const rawColor = this.commentConfig.carousel_accent_color const star_color = !rawColor ? configRes.data.star_color : rawColor; this.commentConfig = { ...this.commentConfig, ...configRes.data, star_color, }; const { isNeedFill, min } = this.getIfFillReviews_(); const isBlank = !isNeedFill && Number(commentsRes.data.count) < min; this.renderReviewsList_({ list: isBlank ? { list: [] } : commentsRes.data, config: this.commentConfig }); }) .catch(error => { this.renderEmptyReviewCarousel_(); }); } renderEmptyReviewCarousel_ = () => { const emptyEle = document.querySelector(`#revue_empty-${this.blockSectionId}-${this.blockIndex}`); const isInB = window.top != window.self; if (emptyEle && isInB) { emptyEle.classList.remove('hidden'); } const carouselEle = document.querySelector(`#revue-carousel-box-${this.blockSectionId}-${this.blockIndex}`); if (carouselEle) { carouselEle.classList.add('hidden'); } } renderReviewsList_ = (data) => { const listEle = document.querySelector(`#revue-carousel-box-${this.blockSectionId}-${this.blockIndex}`); const emptyEle = document.querySelector(`#revue_empty-${this.blockSectionId}-${this.blockIndex}`); if (listEle) { if (data.list.list.length == 0) { this.renderEmptyReviewCarousel_(); } else { listEle.classList.remove('hidden'); if (emptyEle) { emptyEle.classList.add('hidden'); } SPZ.whenApiDefined(listEle).then((api) => { api.render({ ...data, list: data.list.list, star_color: this.commentConfig.star_color, isPC: this.isPC, }, true); }) .catch((error) => { console.log(error); }); }; } this.reviewsList = data.list.list } triggerEvent_(name, data) { const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SpzCustomRevueCarourel) const TAG = 'spz-custom-revue-modal'; class SPZCustomRevueModal extends SPZ.BaseElement { constructor(element) { super(element); this.renderedId = ''; this.closeCB = null; this.sectionId = this.element.getAttribute('section-id'); } static deferredMount() { return false; } buildCallback = () => { this.setupAction_(); } mountCallback = () => { } setupAction_ = () => { this.registerAction('renderModal', this.renderModalFn) this.registerAction('closeFn',() => { this?.closeCB?.() }) } mediaParse_ = function (url) { var result = {}; try { url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) { try { result[key] = decodeURIComponent(value); } catch (e) { result[key] = value; } }); result.src = url.split('?')[0]; } catch (e) {}; return result; } impFunc = function (selector, cb) { // 添加自动曝光 const el = document.querySelector(selector); const onImpress = () => { cb(); }; // 元素未曝光时添加曝光事件监听,已曝光则可以立刻触发处理器 if (el && !el.getAttribute('imprsd')) { el.addEventListener('impress', onImpress); } else if (el) { onImpress(); } }; addModalImpression = function (selector, params) { this.impFunc(selector, () => { window.sa && window.sa.track('plugin_reviews_modal_pv', { ...params, plugin_timestamp: new Date().valueOf().toString(), }); }); }; renderModalFn(receivedData){ if(!receivedData) return; const { data:current, commentConfig, layout, level_type, show_number, closeCB, mimic_mobile_style, props } = receivedData; try{ if(closeCB){ this.closeCB = () => { closeCB() }; } }catch(e){ console.log(e); }; const commentModalEl = document.querySelector(`#revue-product-comment-modal-${this.sectionId}`); const modalRenderEl = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`); if (!!mimic_mobile_style) { if (commentModalEl) { commentModalEl.classList.add('mobile-wrap'); } if (modalRenderEl) { modalRenderEl.classList.add('w-h-full-h5'); } }; const parsedImages = current?.img?.map(image => { return this.mediaParse_(`${image.url}?width=${image.width}&height=${image.height}`); }); const modalEle = document.querySelector(`#revue_flow_modal_render-${this.sectionId}`); if (modalEle) { SPZ.whenApiDefined(modalEle).then((api) => { api.render({ ...current, img: parsedImages, config: commentConfig, shop_name: window.SHOPLAZZA.shop.shop_name, mimic_mobile_style }, true).then(() => { this.addModalImpression('.revue_modal_container', { id: current.id, username: current.username, content: current.content, star: current.star, is_verified: current.is_verified, is_featured: current.is_featured, anonymous: current.anonymous, iso_code_3: current.iso_code_3, like_count: current.like, layout_type: layout, level_type: level_type, show_number: show_number, }); }).then(()=>{ this.renderedId = current.id }); }); } } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement('spz-custom-revue-modal', SPZCustomRevueModal) const TAG = 'spz-custom-revue-selector'; class SpzCustomRevueSelector extends SPZ.BaseElement { constructor(element) { super(element); } buildCallback = () => { this.action_ = SPZServices.actionServiceForDoc(this.element); this.templates_ = SPZServices.templatesForDoc(this.element); this.total = this.element.getAttribute('total'); this.blockIndex = this.element.getAttribute('blockIndex'); this.setupAction_(); } setupAction_ = () => { this.registerAction('toggleChangeSelector', async (invocation) => { const { option } = invocation.args; const total = Number(this.total); this.updateDots_(option, total); }); } updateDots_ = (currentIndex, totalDots) => { const dots = this.element.querySelectorAll('.dot'); if (totalDots < 2 || dots?.length < 1) return; const maxVisibleDots = 5; // 重置所有点 dots?.forEach(dot => { dot.classList.remove('active', 'scaled'); }); // 设置当前激活点 if (dots[currentIndex]) { dots[currentIndex].classList.add('active'); } // 计算显示的点和缩放效果 let startIndex = 0; let endIndex = totalDots - 1; let visibleRange = [0, totalDots - 1]; let translateX = 0; if (totalDots > maxVisibleDots) { // 计算可见范围 if (currentIndex < maxVisibleDots - 1) { // 前 maxVisibleDots-1 个点 startIndex = 0; endIndex = maxVisibleDots - 1; translateX = 0; } else if (currentIndex >= totalDots - (maxVisibleDots - 1)) { // 最后 maxVisibleDots-1 个点 startIndex = totalDots - maxVisibleDots; endIndex = totalDots - 1; translateX = -(totalDots - maxVisibleDots) * 8; } else { // 中间点 startIndex = currentIndex - Math.floor(maxVisibleDots / 2); endIndex = currentIndex + Math.floor(maxVisibleDots / 2); // 调整边界情况 if (startIndex < 0) { endIndex -= startIndex; startIndex = 0; } if (endIndex >= totalDots) { startIndex -= (endIndex - totalDots + 1); endIndex = totalDots - 1; } translateX = -startIndex * 8; } // 设置可见范围 visibleRange = [startIndex, endIndex]; // 设置点的缩放效果 // 最左边的点(除了第一个) if (startIndex > 0) { dots[startIndex].classList.add('scaled'); } // 最右边的点(除了最后一个) if (endIndex < totalDots - 1) { dots[endIndex].classList.add('scaled'); } // 特殊处理第一个和最后一个点 if (currentIndex === 0) { dots[0].classList.remove('scaled'); } if (currentIndex === totalDots - 1) { dots[totalDots - 1].classList.remove('scaled'); } } // 设置dotsWrap的位置 const dotsWrap = this.element.querySelector('#dotsWrap'); if (dotsWrap) { dotsWrap.style.transform = `translateX(${translateX}px)`; } } mountCallback() { this.doRender_({ total: this.total, blockIndex: this.blockIndex }); } doRender_ = (data) => { return this.templates_ .findAndRenderTemplate(this.element, data, null) .then((el) => { const children = this.element.querySelector('*:not(template)'); children && SPZCore.Dom.removeElement(children); this.element.appendChild(el); }) } triggerEvent_ = (name, data) => { const event = SPZUtils.Event.create(this.win, `${TAG}.${name}`, data || {}); this.action_.trigger(this.element, name, event); } isLayoutSupported(layout) { return layout == SPZCore.Layout.CONTAINER; } } SPZ.defineElement(TAG, SpzCustomRevueSelector);
Description

Product descriptions:

Name:1000D encrypted Oxford Cloth Tactical Body Armor Molle Quick-Release Tactical Vest

The outer layer of the vest is made of encrypted Oxford cloth, which is wear-resistant and tear-resistant, and can withstand the test of various harsh environments. The shoulder and waist sizes are adjustable and suitable for all adults weighing 120 pounds to 270 pounds.The overall quick-release version has multiple detachable utility bags that are detachable, reinstallable, and pluggable.

  • Weight: 4.41lbs(2kg)
  • Color: Black、Tan、Green、CP Green
  • Size: One size (Adjustable size suitable for all adults weighing 120 Ibs to 270 Ibs)
  • Fabric: encrypted Oxford cloth
  • Accessories: Fully removable
  • Style: Multifunctional vest
  • Waist circumference can be extended to: 34-55.5 inch

This product does not contain bulletproof plates
To purchase bulletproof plates, please visit >> Bulletproof plates

Product Features:

  • Can place 10x12 inch bulletproof plates on the front and back
  • Made of encrypted Oxford fabric, which has excellent wear resistance, tear resistance and impact resistance. This fabric not only ensures the protective effect, but also has a high degree of comfort, allowing you to wear it with peace of mind. 
  • Adopts a detachable and reconfigurable design, making maintenance and replacement more convenient. When the bulletproof plate is damaged or needs to be replaced, there is no need to replace the entire vest, just You only need to remove the damaged part and replace it with a new bulletproof plate. In addition, this design also allows you to flexibly combine and match according to actual conditions to meet different protection needs.
  • This The bulletproof vest is designed with a one-size-fits-all design to accommodate wearers of different body shapes. The Velcro design on the shoulders and waist allows the wearer to adjust the vest according to their body shape, ensuring that the vest fits the body closely and provides the best protection. The size that suits you.
  • This bulletproof vest adopts a unique metal snake buckle quick release design, which is characterized by convenient wearing and taking off process and stable fixing effect. The design of the snake buckle quick release ensures The equipment can be quickly removed while ensuring the safety of the wearer. Its structure is stable and not easy to fall off, and it can withstand a certain impact force, ensuring rapid response in emergency situations.
  • Proudly MADE IN USA