Ultralight Body Armor Concealed Tactical Plate Carrier Vest Black

$97.99
Color:  Black
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

I.About the product
This ultralight body armor concealed tactical plate carrier vest adopts elastic waistband design and elastic material, which allows the vest to fit the body when worn, effectively reducing the sense of restraint during exercise. Velcro can be used to adjust the size of the waist and shoulders. It is equipped with bulletproof plates 10x12 inches (25*30cm) on the front and back, which has the dual advantages of concealment and outer wear. The vest is made of 600D Cordura fabric, which is extremely durable and tear-resistant. It is also waterproof and stain-resistant.

  • Name: Ultralight Body Armor Concealed Tactical Plate Carrier Vest
  • Color: Black
  • Weight:0.46lbs
  • Size: One Size (Adjustable, suitable for children and adults from 120 pounds to 270 pounds)
  • Applicable people: Police, military personnel, security personnel or ordinary people who want to protect themselves in outdoor activities can
  • choose this vest

Tip: This product is a plate carrier. Ballistic plates are not included
To purchase ballistic plates, please visit >> Ballistic Plates

II.Product Features

  • 100% Made in the USA
  • 10x12 inches (25*30cm) IIIA, III ,IV ballistic plates can be placed front and back
  • Elastic waistband for a close fit
  • Can be hidden or worn as an outer layer
  • Lightweight and durable
  • Honeycomb vents
  • 600D Cordura fabric
  • Waterproof, stain-resistant, scratch-resistant, tear-resistant
  • Stretchy, not tight
  • No maintenance required