发送到购物车时,产品变体(通过色板选择)不会更新-只要加载页面,它就会采用所选的初始变体。尝试过以下解决方案(除非我完全错过了一些东西):
https://github.com/Shopify/slate/issues/116 https://github.com/Shopify/starter-theme/issues/127 https://github.com/Shopify/starter-theme/blob/master/src/scripts/sections/product.js#L71
产品。液体
<div data-section-id="{{ section.id }}" data-section-type="product" data-enable-history-state="true">
<form action="/cart/add" method="post" enctype="multipart/form-data">
{%- assign current_variant = product.selected_or_first_available_variant -%}
{%- assign featured_image = current_variant.featured_image | default: product.featured_image -%}
{% capture productTitle %}{% include 'product-title' %}{% endcapture %}
{% capture productPrice %}{% include 'product-price' %}{% endcapture %}
{%- capture image_alt_text -%}
{{ productTitle }} - {{ shop.name }}
{%- endcapture -%}
{% if product.images.size > 1 %}
<ul class="productThumbs">
{% for image in product.images %}
<li>
<a href="{{ image.src | img_url: '480x480' }}" data-thumbnail-id="{{ image.id }}" data-product-single-thumbnail>
<img class="product-single__thumbnail-image" src="{{ image.src | img_url: '50x' }}" alt="{{ image_alt_text }}">
</a>
</li>
{% endfor %}
</ul>
{% endif %}
<div class="mobileOnly">
<div class="vendor">{{ product.vendor }}</div>
<h1 class="title">{{ productTitle }}</h1>
</div>
<div class="mainImage">
{% assign counter = 0 %}
{% for image in product.images %}
{% capture wrapper_class %}
{%- unless featured_image == image -%}
hide
{%- endunless -%}
{% endcapture %}
{% capture image_attributes %}
data-product-featured-image data-large="{{ image | img_url: '2048x2048' }}"
{% endcapture %}
{% capture full_resolution_image %}
{{ image.src | img_url: 'master' }}
{% endcapture %}
<div class="{{ wrapper_class }} imageArea">
{% include 'responsive-image' with
image: image,
max_width: 2048,
max_height: 2048,
image_attributes: image_attributes,
image_class: 'cloudzoom',
wrapper_class: wrapper_class,
wrapper_attributes: "data-product-image-wrapper",
image_alt: image_alt_text,
data_cloudzoom_image: full_resolution_image
%}
</div>
{% assign counter = counter | plus: 1 %}
{% endfor %}
<div class="imageInstructions" id="hoverToZoom">Roll over image to zoom in</div>
<div class="imageInstructions visually-hidden" id="clickToExpand">Click image to open expanded view</div>
</div>
<div class="quickInfo">
<h1 class="title desktopOnly">{{ productTitle }}</h1>
<div class="vendor desktopOnly">by {{ product.vendor }}</div>
{{ productPrice }}
<div class="rte">
<div class="description desktopOnly">
{{ product.description }}
</div>
{% include 'product-variants' %}
</div>
</div>
<div class="actionsBoxContainer">
{% if section.settings.show_share_buttons %}
<div class="socialSharingBox desktopOnly">
<span class="shareButtonInstructions">Share</span>
{% include 'social-sharing', share_title: productTitle, share_permalink: product.url, share_image: product %}
</div>
{% endif %}
<div class="actionsBox">
{{ productPrice }}
{% if product.available %}
<div class="stock inStock">In Stock.</div>
{% else %}
<div class="stock noStock">Out of Stock.</div>
{% endif %}
<div class="shipsFrom desktopOnly">
Ships from and sold by {{ shop.name }}.
</div>
<div class="quantity visually-hidden">
<label for="Quantity">{{ 'products.product.quantity' | t }}</label>
<input type="number" id="Quantity" name="quantity" value="1" min="1">
</div>
<button
type="submit"
name="add"
class="button"
data-add-to-cart
{% unless current_variant.available %}disabled="disabled"{% endunless %}
{% unless current_variant.price != 0 %}disabled="disabled"{% endunless %}>
<span data-add-to-cart-text>
{% if current_variant.available %}
<span class="icon">{% include 'icon-cart' %}</span>
<span class="text">{{ 'products.product.add_to_cart' | t }}</span>
{% else %}
<span class="soldOut">{{ 'products.product.sold_out' | t }}</span>
{% endif %}
</span>
</button>
<div class="shipsFrom mobileOnly">
Ships from and sold by {{ shop.name }}.
</div>
{% include 'deliver-to' %}
</div>
<h2 class="about mobileOnly">About this item</h2>
<div class="moreInfo mobileOnly">
<div class="description">{{ product.description }}</div>
{% include 'product-variants' %}
</div>
{% if section.settings.show_share_buttons %}
<div class="socialSharingBox mobileOnly">
<span class="shareButtonInstructions">Share</span>
{% include 'social-sharing', share_title: productTitle, share_permalink: product.url, share_image: product %}
</div>
{% endif %}
{% unless product == empty %}
<script type="application/json" data-product-json>
{{ product | json }}
</script>
{% endunless %}
</form>
</div>
{% schema %}
{
"name": "Product pages",
"settings": [
{
"type": "checkbox",
"id": "show_share_buttons",
"label": "Show social sharing buttons",
"default": true
}
]
}
{% endschema %}
{% javascript %}
$( document ).ready(function() {
$('ul.productThumbs li').on( 'click', function() {
var i = $(this).index();
$('.mainImage > div.imageArea').addClass('hide');
$('.mainImage > div.imageArea').eq(i).removeClass('hide');
});
$('img.cloudzoom').on('cloudzoom_start_zoom', function() {
$('#clickToExpand').removeClass('visually-hidden');
$('#hoverToZoom').addClass('visually-hidden');
});
$('img.cloudzoom').on('cloudzoom_end_zoom', function() {
$('#hoverToZoom').removeClass('visually-hidden');
$('#clickToExpand').addClass('visually-hidden');
});
var productGalleryItems = [];
$('.mainImage img').each(function() {
const cloudZoomData = $(this).data('cloudzoom') + '';
const cloudZoomDataImage = cloudZoomData.split(',')[0];
const fullSizeImgSrc = cloudZoomDataImage.split("zoomImage: '")[1].slice(0,-1);
const thumbImgParts = fullSizeImgSrc.split('/products/');
const thumbImgUrlBase = thumbImgParts[0];
const thumbImgEnd = thumbImgParts[1];
const thumbImgEndParts = thumbImgEnd.split('?v=');
const thumbImgFileExtension = '.' + thumbImgEndParts[0].split('.').pop();
const thumbImgFileName = thumbImgEndParts[0].split(thumbImgFileExtension)[0];
const thumbImgVersion = "?v=" + thumbImgEndParts[1];
const thumbImgSrc = "'" + thumbImgUrlBase + "/products/" + thumbImgFileName + "_medium" + thumbImgFileExtension + thumbImgVersion + "'";
const galleryItemObject = {
src: fullSizeImgSrc,
opts: {
thumb: thumbImgSrc,
}
}
productGalleryItems.push(galleryItemObject);
});
$('img.cloudzoom').on('click',function(){
var cloudZoom = $(this).data('CloudZoom');
cloudZoom.closeZoom();
$.fancybox.open(productGalleryItems);
return false;
});
});
{% endjavascript %}
product.js
/**
* Product Template Script
* ------------------------------------------------------------------------------
* A file that contains scripts highly couple code to the Product template.
*
* @namespace product
*/
import $ from 'jquery';
import Variants from '@shopify/theme-variants';
import {formatMoney} from '@shopify/theme-currency';
import {register} from '@shopify/theme-sections';
const selectors = {
addToCart: '[data-add-to-cart]',
addToCartText: '[data-add-to-cart-text]',
comparePrice: '[data-compare-price]',
comparePriceText: '[data-compare-text]',
originalSelectorId: '[data-product-select]',
priceWrapper: '[data-price-wrapper]',
productImageWrapper: '[data-product-image-wrapper]',
productFeaturedImage: '[data-product-featured-image]',
productJson: '[data-product-json]',
productPrice: '[data-product-price]',
productThumbs: '[data-product-single-thumbnail]',
singleOptionSelector: '[data-single-option-selector]',
};
const cssClasses = {
activeThumbnail: 'active-thumbnail',
hide: 'hide',
};
const keyboardKeys = {
ENTER: 13,
};
/**
* Product section constructor. Runs on page load as well as Theme Editor
* `section:load` events.
* @param {string} container - selector for the section container DOM element
*/
register('product', {
onLoad() {
this.$container = $(this.container);
this.namespace = `.${this.id}`;
// Stop parsing if we don't have the product json script tag when loading
// section in the Theme Editor
if (!$(selectors.productJson, this.$container).html()) {
return;
}
this.productSingleObject = JSON.parse(
$(selectors.productJson, this.$container).html(),
);
const options = {
$container: this.$container,
enableHistoryState: this.$container.data('enable-history-state') || false,
singleOptionSelector: selectors.singleOptionSelector,
originalSelectorId: selectors.originalSelectorId,
product: this.productSingleObject,
};
this.settings = {};
this.variants = new Variants(options);
this.$featuredImage = $(selectors.productFeaturedImage, this.$container);
this.$container.on(
`variantChange${this.namespace}`,
this.updateAddToCartState.bind(this),
);
this.$container.on(
`variantPriceChange${this.namespace}`,
this.updateProductPrices.bind(this),
);
if (this.$featuredImage.length > 0) {
this.$container.on(
`variantImageChange${this.namespace}`,
this.updateImages.bind(this),
);
}
$( ".swatch input.swatch-element" ).click(function() {
// console.log(this);
// $(".swatch input.swatch-element").each(function() {
// $(this).prop('checked', false);
// });
// var checkbox = ".swatch input#" + this.id;
// $(checkbox).prop('checked', !$(checkbox).prop('checked'));
$(".swatch label.selectedOnLoad").each(function() {
$(this).removeClass("selectedOnLoad");
});
});
this.highlightSelectedVariantOnLoad();
this.initImageSwitch();
},
highlightSelectedVariantOnLoad() {
$(".swatch input.swatch-element:checked").each(function() {
$(".swatch label[for='" + this.id + "']").addClass("selectedOnLoad");
});
},
initImageSwitch() {
const $productThumbs = $(selectors.productThumbs, this.$container);
if (!$productThumbs.length) {
return;
}
$productThumbs
.on('click', (evt) => {
evt.preventDefault();
const imageId = $(evt.currentTarget).data('thumbnail-id');
this.switchImage(imageId);
this.setActiveThumbnail(imageId);
})
.on('keyup', this.handleImageFocus.bind(this));
},
handleImageFocus(evt) {
if (evt.keyCode !== keyboardKeys.ENTER) {
return;
}
this.$featuredImage.filter(':visible').focus();
},
setActiveThumbnail(imageId) {
let newImageId = imageId;
// If "imageId" is not defined in the function parameter, find it by the current product image
if (typeof newImageId === 'undefined') {
newImageId = $(
`${selectors.productImageWrapper}:not('.${cssClasses.hide}')`,
).data('image-id');
}
const $thumbnail = $(
`${selectors.productThumbs}[data-thumbnail-id='${newImageId}']`,
);
$(selectors.productThumbs)
.removeClass(cssClasses.activeThumbnail)
.removeAttr('aria-current');
$thumbnail.addClass(cssClasses.activeThumbnail);
$thumbnail.attr('aria-current', true);
},
switchImage(imageId) {
const $newImage = $(
`${selectors.productImageWrapper}[data-image-id='${imageId}']`,
this.$container,
);
const $otherImages = $(
`${selectors.productImageWrapper}:not([data-image-id='${imageId}'])`,
this.$container,
);
$newImage.removeClass(cssClasses.hide);
$otherImages.addClass(cssClasses.hide);
},
/**
* Updates the DOM state of the add to cart button
*
* @param {boolean} enabled - Decides whether cart is enabled or disabled
* @param {string} text - Updates the text notification content of the cart
*/
updateAddToCartState(evt) {
const variant = evt.variant;
if (variant) {
$(selectors.priceWrapper, this.$container).removeClass(cssClasses.hide);
} else {
$(selectors.addToCart, this.$container).prop('disabled', true);
$(selectors.priceWrapper, this.$container).addClass(cssClasses.hide);
return;
}
if (variant.available) {
$(selectors.addToCart, this.$container).prop('disabled', false);
} else {
$(selectors.addToCart, this.$container).prop('disabled', true);
}
if (variant.price != 0) {
$(selectors.addToCart, this.$container).prop('disabled', false);
} else {
$(selectors.addToCart, this.$container).prop('disabled', true);
}
},
updateImages(evt) {
const variant = evt.variant;
const imageId = variant.featured_image.id;
this.switchImage(imageId);
this.setActiveThumbnail(imageId);
},
/**
* Updates the DOM with specified prices
*
* @param {string} productPrice - The current price of the product
* @param {string} comparePrice - The original price of the product
*/
updateProductPrices(evt) {
const variant = evt.variant;
const $comparePrice = $(selectors.comparePrice, this.$container);
const $compareEls = $comparePrice.add(
selectors.comparePriceText,
this.$container,
);
const freeText = $('.freeText').html();
if (variant.price == 0) {
$(selectors.productPrice, this.$container).html(
freeText,
);
} else {
$(selectors.productPrice, this.$container).html(
formatMoney(variant.price, theme.moneyFormat),
);
}
if (variant.compare_at_price > variant.price) {
$comparePrice.html(
formatMoney(variant.compare_at_price, theme.moneyFormat),
);
$compareEls.removeClass(cssClasses.hide);
} else {
$comparePrice.html('');
$compareEls.addClass(cssClasses.hide);
}
},
/**
* Event callback for Theme Editor `section:unload` event
*/
onUnload() {
this.$container.off(this.namespace);
},
});