以下是 html5分步式商品定制购物结算代码 的示例演示效果:
部分效果截图1:
部分效果截图2:
HTML代码(index.html):
<!DOCTYPE html>
<html lang="zh" class="no-js">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>html5分步式商品定制购物结算代码</title>
<link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/demo.css">
<link rel="stylesheet" href="css/style.css"> <!-- Resource style -->
</head>
<body>
<div class="cd-product-builder">
<header class="main-header"><br>
<nav class="cd-builder-main-nav disabled">
<ul>
<li class="active"><a href="#models">Models</a></li>
<li><a href="#colors">Colors</a></li>
<li><a href="#accessories">Accessories</a></li>
<li><a href="#summary">Summary</a></li>
</ul>
</nav>
</header>
<div class="cd-builder-steps">
<ul>
<li data-selection="models" class="active builder-step">
<section class="cd-step-content">
<header>
<h1>Select Model</h1>
<span class="steps-indicator">Step <b>1</b> of 4</span>
</header>
<a href="#" class="cd-nugget-info hide-on-desktop">返回下载页</a>
<ul class="models-list options-list cd-col-2">
<li class="js-option js-radio" data-price="42400" data-model="product-01">
<span class="name">BMW i3</span>
<img src="img/product01_col01.jpg" alt="BMW i3">
<span class="price">from $42.400</span>
<div class="radio"></div>
</li>
<li class="js-option js-radio" data-price="140700" data-model="product-02">
<span class="name">BMW i8</span>
<img src="img/product02_col01.jpg" alt="BMW i8">
<span class="price">from $140.700</span>
<div class="radio"></div>
</li>
</ul>
</section>
</li>
<!-- additional content will be inserted using ajax -->
</ul>
</div>
<footer class="cd-builder-footer disabled step-1">
<div class="selected-product">
<img src="img/product01_col01.jpg" alt="Product preview">
<div class="tot-price">
<span>Total</span>
<span class="total">$<b>0</b></span>
</div>
</div>
<nav class="cd-builder-secondary-nav">
<ul>
<li class="next nav-item">
<ul>
<li class="visible"><a href="#0">Colors</a></li>
<li><a href="#0">Accessories</a></li>
<li><a href="#0">Summary</a></li>
<li class="buy"><a href="#0">Buy Now</a></li>
</ul>
</li>
<li class="prev nav-item">
<ul>
<li class="visible"><a href="#0">Models</a></li>
<li><a href="#0">Models</a></li>
<li><a href="#0">Colors</a></li>
<li><a href="#0">Accessories</a></li>
</ul>
</li>
</ul>
</nav>
<span class="alert">Please, select a model first!</span>
</footer>
</div>
<script type="text/javascript" src="js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="js/main.js"></script> <!-- Resource jQuery -->
</body>
</html>
JS代码(main.js):
jQuery(document).ready(function($){
function ProductBuilder( element ){
this.element = element;
this.stepsWrapper = this.element.children('.cd-builder-steps');
this.steps = this.element.find('.builder-step');
//store some specific bulider stepsthis.models = this.element.find('[data-selection="models"]');
this.summary;
this.optionsLists = this.element.find('.options-list');
//bottom summarythis.fixedSummary = this.element.find('.cd-builder-footer');
this.modelPreview = this.element.find('.selected-product').find('img');
this.totPriceWrapper = this.element.find('.tot-price').find('b');
//builder navigationsthis.mainNavigation = this.element.find('.cd-builder-main-nav');
this.secondaryNavigation = this.element.find('.cd-builder-secondary-nav');
//used to check if the builder content has been loaded properlythis.loaded = true;
// bind builder eventsthis.bindEvents();
}
ProductBuilder.prototype.bindEvents = function(){
var self = this;
//detect click on the left navigationthis.mainNavigation.on('click','li:not(.active)',function(event){
event.preventDefault();
self.loaded && self.newContentSelected($(this).index());
}
);
//detect click on bottom fixed navigationthis.secondaryNavigation.on('click','.nav-item li:not(.buy)',function(event){
event.preventDefault();
var stepNumber = ( $(this).parents('.next').length > 0 ) ? $(this).index() + 1:$(this).index() - 1;
self.loaded && self.newContentSelected(stepNumber);
}
);
//detect click on one element in an options list (e.g,models,accessories)this.optionsLists.on('click','.js-option',function(event){
self.updateListOptions($(this));
}
);
//detect clicks on customizer controls (e.g.,colors ...)this.stepsWrapper.on('click','.cd-product-customizer a',function(event){
event.preventDefault();
self.customizeModel($(this));
}
);
}
;
ProductBuilder.prototype.newContentSelected = function(nextStep){
//first - check if a model has been selected - user can navigate through the builderif( this.fixedSummary.hasClass('disabled') ){
//no model has been selected - show alertthis.fixedSummary.addClass('show-alert');
}
else{
//model has been selected so show new content//first check if the color step has been completed - in this case update the product bottom previewif( this.steps.filter('.active').is('[data-selection="colors"]') ){
//in this case,color has been changed - update the preview imagevar imageSelected = this.steps.filter('.active').find('.cd-product-previews').children('.selected').children('img').attr('src');
this.modelPreview.attr('src',imageSelected);
}
//if Summary is the selected step (new step to be revealed) -> update summary contentif( nextStep + 1 >= this.steps.length ){
this.createSummary();
}
this.showNewContent(nextStep);
this.updatePrimaryNav(nextStep);
this.updateSecondaryNav(nextStep);
}
}
ProductBuilder.prototype.showNewContent = function(nextStep){
var actualStep = this.steps.filter('.active').index() + 1;
if( actualStep < nextStep + 1 ){
//go to next sectionthis.steps.eq(actualStep-1).removeClass('active back').addClass('move-left');
this.steps.eq(nextStep).addClass('active').removeClass('move-left back');
}
else{
//go to previous sectionthis.steps.eq(actualStep-1).removeClass('active back move-left');
this.steps.eq(nextStep).addClass('active back').removeClass('move-left');
}
}
ProductBuilder.prototype.updatePrimaryNav = function(nextStep){
this.mainNavigation.find('li').eq(nextStep).addClass('active').siblings('.active').removeClass('active');
}
ProductBuilder.prototype.updateSecondaryNav = function(nextStep){
( nextStep == 0 ) ? this.fixedSummary.addClass('step-1'):this.fixedSummary.removeClass('step-1');
this.secondaryNavigation.find('.nav-item.next').find('li').eq(nextStep).addClass('visible').removeClass('visited').prevAll().removeClass('visited').addClass('visited').end().nextAll().removeClass('visible visited');
this.secondaryNavigation.find('.nav-item.prev').find('li').eq(nextStep).addClass('visible').removeClass('visited').prevAll().removeClass('visited').addClass('visited').end().nextAll().removeClass('visible visited');
}
ProductBuilder.prototype.createSummary = function(){
var self = this;
this.steps.each(function(){
//this function may need to be updated according to your builder steps and summaryvar step = $(this);
if( $(this).data('selection') == 'colors' ){
//create the Color summaryvar colorSelected = $(this).find('.cd-product-customizer').find('.selected'),color = colorSelected.children('a').data('color'),colorName = colorSelected.data('content'),imageSelected = $(this).find('.cd-product-previews').find('.selected img').attr('src');
self.summary.find('.summary-color').find('.color-label').text(colorName).siblings('.color-swatch').attr('data-color',color);
self.summary.find('.product-preview').attr('src',imageSelected);
}
else if( $(this).data('selection') == 'accessories' ){
var selectedOptions = $(this).find('.js-option.selected'),optionsContent = '';
if( selectedOptions.length == 0 ){
optionsContent = '<li><p>No Accessories selected;
</p></li>';
}
else{
selectedOptions.each(function(){
optionsContent +='<li><p>'+$(this).find('p').text()+'</p></li>';
}
);
}
self.summary.find('.summary-accessories').children('li').remove().end().append($(optionsContent));
}
}
);
}
ProductBuilder.prototype.updateListOptions = function(listItem){
var self = this;
if( listItem.hasClass('js-radio') ){
//this means only one option can be selected (e.g.,models) - so check if there's another option selected and deselect itvar alreadySelectedOption = listItem.siblings('.selected'),price = (alreadySelectedOption.length > 0 ) ? -Number(alreadySelectedOption.data('price')):0;
//if the option was already selected and you are deselecting it - price is the price of the option just clicked( listItem.hasClass('selected') )? price = -Number(listItem.data('price')):price = Number(listItem.data('price')) + price;
//now deselect all the other optionsalreadySelectedOption.removeClass('selected');
//toggle the option just selectedlistItem.toggleClass('selected');
//update totalPrice - only if the step is not the Models step(listItem.parents('[data-selection="models"]').length == 0) && self.updatePrice(price);
}
else{
//more than one options can be selected - just need to add/remove the one just clickedvar price = ( listItem.hasClass('selected') ) ? -Number(listItem.data('price')):Number(listItem.data('price'));
//toggle the option just selectedlistItem.toggleClass('selected');
//update totalPriceself.updatePrice(price);
}
if( listItem.parents('[data-selection="models"]').length > 0 ){
//since a model has been selected/deselected,you need to update the builder contentself.updateModelContent(listItem);
}
}
;
ProductBuilder.prototype.updateModelContent = function(model){
var self = this;
if( model.hasClass('selected') ){
var modelType = model.data('model'),modelImage = model.find('img').attr('src');
//need to update the product image in the bottom fixed navigationthis.modelPreview.attr('src',modelImage);
//need to update the content of the builder according to the selected product//first - remove the contet which refers to a different modelthis.models.siblings('li').remove();
//second - load the new content$.ajax({
type:"GET",dataType:"html",url:modelType+".html",beforeSend:function(){
self.loaded = false;
model.siblings().removeClass('loaded');
}
,success:function(data){
self.models.after(data);
self.loaded = true;
model.addClass('loaded');
//activate top and bottom navigationsself.fixedSummary.add(self.mainNavigation).removeClass('disabled show-alert');
//update properties of the objectself.steps = self.element.find('.builder-step');
self.summary = self.element.find('[data-selection="summary"]');
//detect click on one element in an options listself.optionsLists.off('click','.js-option');
self.optionsLists = self.element.find('.options-list');
self.optionsLists.on('click','.js-option',function(event){
self.updateListOptions($(this));
}
);
//this is used not to load the animation the first time new content is loadedself.element.find('.first-load').removeClass('first-load');
}
,error:function(jqXHR,textStatus,errorThrown){
//you may want to show an error message here}
}
);
//update price (no adding/removing)this.totPriceWrapper.text(model.data('price'));
}
else{
//no model has been selectedthis.fixedSummary.add(this.mainNavigation).addClass('disabled');
//update pricethis.totPriceWrapper.text('0');
this.models.find('.loaded').removeClass('loaded');
}
}
;
ProductBuilder.prototype.customizeModel = function(target){
var parent = target.parent('li')index = parent.index();
//update final pricevar price = ( parent.hasClass('selected') )? 0:Number(parent.data('price')) - parent.siblings('.selected').data('price');
this.updatePrice(price);
target.parent('li').addClass('selected').siblings().removeClass('selected').parents('.cd-product-customizer').siblings('.cd-product-previews').children('.selected').removeClass('selected').end().children('li').eq(index).addClass('selected');
}
;
ProductBuilder.prototype.updatePrice = function(price){
var actualPrice = Number(this.totPriceWrapper.text()) + price;
this.totPriceWrapper.text(actualPrice);
}
;
if( $('.cd-product-builder').length > 0 ){
$('.cd-product-builder').each(function(){
//create a productBuilder object for each .cd-product-buildernew ProductBuilder($(this));
}
);
}
}
);
CSS代码(demo.css):
body,html{font-size:100%;padding:0;margin:0;}
/* Reset */
*,*:after,*:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
/* Clearfix hack by Nicolas Gallagher:http://nicolasgallagher.com/micro-clearfix-hack/ */
.clearfix:before,.clearfix:after{content:" ";display:table;}
.clearfix:after{clear:both;}
body{background:#494A5F;color:#D5D6E2;font-weight:500;font-size:1.05em;font-family:"Microsoft YaHei","宋体","Segoe UI","Lucida Grande",Helvetica,Arial,sans-serif,FreeSans,Arimo;}
.htmleaf-container{margin:0 auto;}
h1.title{font-size:1.5em;font-family:"Microsoft YaHei";}