From 8e4774f44df920792cde20cf9d928e58c52725fa Mon Sep 17 00:00:00 2001 From: chicpro Date: Thu, 26 Dec 2013 16:11:46 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=87=BC?= =?UTF-8?q?=ED=95=91=EB=AA=B0=20=EB=A9=94=EC=9D=B8=20swipe=20=ED=94=8C?= =?UTF-8?q?=EB=9F=AC=EA=B7=B8=EC=9D=B8=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/mobile_shop.css | 15 ++ js/shop.mobile.main.js | 303 ++++++++-------------- js/swipe.js | 570 +++++++++++++++++++++++++++++++++++++++++ mobile/shop/index.php | 60 +++-- 4 files changed, 722 insertions(+), 226 deletions(-) create mode 100644 js/swipe.js diff --git a/css/mobile_shop.css b/css/mobile_shop.css index c7bc49aa0..d0f88c3c9 100644 --- a/css/mobile_shop.css +++ b/css/mobile_shop.css @@ -76,6 +76,21 @@ a.sanchor_on {background:#626870;color:#fff !important;text-decoration:none} #sidx_slide {position:relative;top:0;left:0;width:100%;overflow:hidden} .sidx_slide {position:absolute;top:0;left:0;width:100%} +.swipe { + overflow: hidden; + visibility: hidden; + position: relative; +} +.swipe-wrap { + overflow: hidden; + position: relative; +} +.swipe-wrap > div { + float:left; + width:100%; + position: relative; +} + /* 상품 목록 */ #sct {} .sct_admin {margin:0 0 10px;text-align:right} diff --git a/js/shop.mobile.main.js b/js/shop.mobile.main.js index 2203d74b8..5f4ab89c3 100644 --- a/js/shop.mobile.main.js +++ b/js/shop.mobile.main.js @@ -1,48 +1,52 @@ (function($) { - $.fn.slideSwipe = function(option) + $.fn.swipeSlide = function(option) { var cfg = { - slide_wrap: "sidx_slide", - slide: "section", - slide_tab: "slide_tab", - slide_class: "sidx_slide", - active_class: "slide_active", - tab_active: "tab_active", - duration: 500, - width_increase: 10 + slides: ".swipe-wrap > div", + header: "header h2", + tabWrap: "slide_tab", + tabActive: "tab_active", + tabOffset: 10, + startSlide: 0, + auto: 0, + continuous: true, + disableScroll: false, + stopPropagation: false, + callback: function(index, element) { + tab_change(index); + idx = index; + }, + transitionEnd: function(index, element) { + set_height(index); + } }; if(typeof option == "object") cfg = $.extend( cfg, option ); - var $this = this; - var $wrap = this.find("#"+cfg.slide_wrap); + var $wrap = this; + var $slides = this.find(""+cfg.slides+""); var $tab = null; var $tabs; var $btns; - var $slides = this.find(cfg.slide); + + var idx = cfg.startSlide; var count = $slides.size(); - - if(count < 1) - return; - - $slides.addClass(cfg.slide_class); - - var height; - var next_height; - var width; - var idx = next = 0; + var width, height; var tabw_width = 0; var tab_width = 0; var pos_left = 0; + if(count < 1) + return; + function tab_make() { var subj; var tabs = ""; $slides.each(function() { - subj = $(this).find("header h2").text(); + subj = $(this).find(""+cfg.header+"").text(); if(subj.length < 1) subj = " "; @@ -50,10 +54,10 @@ }); if(tabs != "") { - tabs = ""; + tabs = ""; $wrap.before(tabs); - $tab = $this.find("#"+cfg.slide_tab); + $tab = $("#"+cfg.tabWrap); $tabs = $tab.find("li"); $btns = $tab.find("button"); @@ -63,159 +67,22 @@ .data("width", $(this).width()); }); - $btns.on("click", function() { - tab_click($(this)); - }); + $btns.off("click"); } } - function swipe_init() - { - if($tab == null) - tab_make(); - - idx = $slides.index($slides.filter("."+cfg.active_class)); - if(idx == -1) - idx = 0; - - $slides.eq(idx).addClass(cfg.active_class); - - width = $wrap.width(); - tabw_width = $tab.width(); - height = $slides.eq(idx).height(); - $wrap.height(height); - - $slides.not("."+cfg.active_class).css("left", "-"+width+"px"); - - set_tab_width(idx); - - if(count == 1) { - tab_width = $tabs.eq(0).outerWidth(); - pos_left = parseInt((tabw_width - tab_width) / 2); - $tabs.eq(0).css("left", pos_left).addClass(cfg.tab_active); - } else if(count == 2) { - $tabs.eq(0).css("left", 0).addClass("tab_left"); - $tabs.eq(1).css("right", 0); - $tabs.removeClass(cfg.tab_active); - $tabs.eq(idx).addClass(cfg.tab_active); - } else if(count >= 3) { - tab_position(idx); - - $slides.eq((idx - 1)).css("left", "-"+width+"px"); - $slides.eq((idx + 1) % count).css("left", width+"px"); - } - } - - function swipe_left() - { - if(count < 2) - return; - - if(check_animated()) - return; - - idx = $slides.index($slides.filter("."+cfg.active_class)); - next = (idx + 1) % count; - - height = $wrap.height(); - next_height = $slides.eq(next).height(); - - if(height >= next_height) - $wrap.height(height); - else - $wrap.height(next_height); - - $slides.eq(next).css("left", width+"px"); - $tabs.removeClass(cfg.tab_active); - - set_tab_width(next); - - if(count >= 3) { - tab_position(next); - } else { - $tabs.eq(next).addClass(cfg.tab_active); - } - - $slides.eq(idx).clearQueue().animate( - { left: "-="+width }, cfg.duration, - function() { - $slides.eq(idx).css("left", width+"px"); - } - ); - - $slides.eq(next).clearQueue().animate( - { left: "-="+width }, cfg.duration, - function() { - $wrap.height(next_height); - } - ); - - $slides.eq(idx).removeClass(cfg.active_class); - $slides.eq(next).addClass(cfg.active_class); - } - - function swipe_right() - { - if(count < 2) - return; - - if(check_animated()) - return; - - idx = $slides.index($slides.filter("."+cfg.active_class)); - next = idx - 1; - if(next < 0) - next = count - 1; - - height = $wrap.height(); - next_height = $slides.eq(next).height(); - - if(height >= next_height) - $wrap.height(height); - else - $wrap.height(next_height); - - $slides.eq(next).css("left", "-"+width+"px"); - $tabs.removeClass(cfg.tab_active); - - set_tab_width(next); - - if(count >= 3) { - tab_position(next); - } else { - $tabs.eq(next).addClass(cfg.tab_active); - } - - $slides.eq(idx).clearQueue().animate( - { left: "+="+width }, cfg.duration, - function() { - $slides.eq(idx).css("left", "-"+width+"px"); - } - ); - - $slides.eq(next).clearQueue().animate( - { left: "+="+width }, cfg.duration, - function() { - $wrap.height(next_height); - } - ); - - $slides.eq(idx).removeClass(cfg.active_class); - $slides.eq(next).addClass(cfg.active_class); - } - function set_tab_width(idx) { $tabs.each(function() { $(this).css("width", $(this).data("width")); }); - $tabs.eq(idx).css("width", "+="+cfg.width_increase); + $tabs.eq(idx).css("width", "+="+cfg.tabOffset); } function tab_position(idx) { - $tabs.removeClass(cfg.tab_actie+" tab_listed tab_left").css("left", "-"+tabw_width+"px"); + $tabs.removeClass(""+cfg.tabActive+" tab_listed tab_left").css("left", "-"+tabw_width+"px"); var $tab_l = $tabs.eq(idx - 1); var $tab_c = $tabs.eq(idx); @@ -227,52 +94,88 @@ var pc = parseInt((tabw_width - w_c) / 2); var pr = tabw_width - w_r; - $tab_l.addClass("tab_listed tab_left").css("left", pl); - $tab_c.addClass(cfg.tab_active+" tab_listed").css("left", pc); + $tab_l.addClass("tab_listed").css("left", pl); + $tab_c.addClass(""+cfg.tabActive+" tab_listed").css("left", pc); $tab_r.addClass("tab_listed").css("left", pr); } - function check_animated() + function tab_change(idx) { - if($slides.filter(":animated").size()) - return true; - else - return false; - } - - function tab_click($el) - { - if(check_animated()) + if(count < 2) return; - if($el.parent().hasClass(cfg.tab_active)) - return; + set_height(idx); + set_tab_width(idx); - if($el.parent().hasClass("tab_left")) - swipe_right(); - else - swipe_left(); + if(count == 2) { + $tabs.eq(0).css("left", 0); + $tabs.eq(1).css("right", 0); + $tabs.removeClass(""+cfg.tabActive+""); + $tabs.eq(idx).addClass(""+cfg.tabActive+""); + } else if(count >= 3) { + tab_position(idx); + } } - $(window).on("load resize", function(e) { - swipe_init(); + function set_height(idx) + { + var offset = $wrap.outerHeight() - $wrap.height(); + + height = $slides.eq(idx).height() + offset; + $wrap.height(height); + } + + function init() + { + if($tab == null) + tab_make(); + + width = $wrap.width(); + tabw_width = $tab.width(); + + set_tab_width(idx); + + if(count == 1) { + tab_width = $tabs.eq(0).outerWidth(); + pos_left = parseInt((tabw_width - tab_width) / 2); + $tabs.eq(0).css("left", pos_left).addClass(""+cfg.tabActive+""); + } else if(count == 2) { + $tabs.eq(0).css("left", 0); + $tabs.eq(1).css("right", 0); + $tabs.removeClass(""+cfg.tabActive+""); + $tabs.eq(idx).addClass(""+cfg.tabActive+""); + } else if(count >= 3) { + tab_position(idx); + } + } + + init(); + + window.mySwipe = Swipe(this[0], { + startSlide: cfg.startSlide, + auto: cfg.auto, + continuous: cfg.continuous, + disableScroll: cfg.disableScroll, + stopPropagation: cfg.stopPropagation, + callback: cfg.callback, + transitionEnd: cfg.transitionEnd }); - // swipe event - this.swipe({ - swipe: function(event, direction, duration, fingerCount) { - switch(direction) { - case "left": - swipe_left(); - break; - case "right": - swipe_right(); - break; - } - }, - threshold: 100, - excludedElements:"a, button, input, select, textarea, .noSwipe", - allowPageScroll:"vertical" + $(window).on("resize", function() { + $("#"+cfg.tabWrap).remove(); + $tab = null; + + init(); }); + + if(count > 0 && mySwipe) { + $btns.on("click", function() { + if($(this).parent().hasClass(""+cfg.tabActive+"")) + return false; + + idx = $btns.index($(this)); + mySwipe.slide(idx); + }); + } } }(jQuery)); \ No newline at end of file diff --git a/js/swipe.js b/js/swipe.js new file mode 100644 index 000000000..db4c0cb49 --- /dev/null +++ b/js/swipe.js @@ -0,0 +1,570 @@ +/* + * Swipe 2.0 + * + * Brad Birdsall + * Copyright 2013, MIT License + * +*/ + +function Swipe(container, options) { + + "use strict"; + + // utilities + var noop = function() {}; // simple no operation function + var offloadFn = function(fn) { setTimeout(fn || noop, 0) }; // offload a functions execution + + // check browser capabilities + var browser = { + addEventListener: !!window.addEventListener, + touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch, + transitions: (function(temp) { + var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition']; + for ( var i in props ) if (temp.style[ props[i] ] !== undefined) return true; + return false; + })(document.createElement('swipe')) + }; + + // quit if no root element + if (!container) return; + var element = container.children[0]; + var slides, slidePos, width, length; + options = options || {}; + var index = parseInt(options.startSlide, 10) || 0; + var speed = options.speed || 300; + options.continuous = options.continuous !== undefined ? options.continuous : true; + + function setup() { + + // cache slides + slides = element.children; + length = slides.length; + + // set continuous to false if only one slide + if (slides.length < 2) options.continuous = false; + + //special case if two slides + if (browser.transitions && options.continuous && slides.length < 3) { + element.appendChild(slides[0].cloneNode(true)); + element.appendChild(element.children[1].cloneNode(true)); + slides = element.children; + } + + // create an array to store current positions of each slide + slidePos = new Array(slides.length); + + // determine width of each slide + width = container.getBoundingClientRect().width || container.offsetWidth; + + element.style.width = (slides.length * width) + 'px'; + + // stack elements + var pos = slides.length; + while(pos--) { + + var slide = slides[pos]; + + slide.style.width = width + 'px'; + slide.setAttribute('data-index', pos); + + if (browser.transitions) { + slide.style.left = (pos * -width) + 'px'; + move(pos, index > pos ? -width : (index < pos ? width : 0), 0); + } + + } + + // reposition elements before and after index + if (options.continuous && browser.transitions) { + move(circle(index-1), -width, 0); + move(circle(index+1), width, 0); + } + + if (!browser.transitions) element.style.left = (index * -width) + 'px'; + + container.style.visibility = 'visible'; + + } + + function prev() { + + if (options.continuous) slide(index-1); + else if (index) slide(index-1); + + } + + function next() { + + if (options.continuous) slide(index+1); + else if (index < slides.length - 1) slide(index+1); + + } + + function circle(index) { + + // a simple positive modulo using slides.length + return (slides.length + (index % slides.length)) % slides.length; + + } + + function slide(to, slideSpeed) { + + // do nothing if already on requested slide + if (index == to) return; + + if (browser.transitions) { + + var direction = Math.abs(index-to) / (index-to); // 1: backward, -1: forward + + // get the actual position of the slide + if (options.continuous) { + var natural_direction = direction; + direction = -slidePos[circle(to)] / width; + + // if going forward but to < index, use to = slides.length + to + // if going backward but to > index, use to = -slides.length + to + if (direction !== natural_direction) to = -direction * slides.length + to; + + } + + var diff = Math.abs(index-to) - 1; + + // move all the slides between index and to in the right direction + while (diff--) move( circle((to > index ? to : index) - diff - 1), width * direction, 0); + + to = circle(to); + + move(index, width * direction, slideSpeed || speed); + move(to, 0, slideSpeed || speed); + + if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place + + } else { + + to = circle(to); + animate(index * -width, to * -width, slideSpeed || speed); + //no fallback for a circular continuous if the browser does not accept transitions + } + + index = to; + offloadFn(options.callback && options.callback(index, slides[index])); + } + + function move(index, dist, speed) { + + translate(index, dist, speed); + slidePos[index] = dist; + + } + + function translate(index, dist, speed) { + + var slide = slides[index]; + var style = slide && slide.style; + + if (!style) return; + + style.webkitTransitionDuration = + style.MozTransitionDuration = + style.msTransitionDuration = + style.OTransitionDuration = + style.transitionDuration = speed + 'ms'; + + style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)'; + style.msTransform = + style.MozTransform = + style.OTransform = 'translateX(' + dist + 'px)'; + + } + + function animate(from, to, speed) { + + // if not an animation, just reposition + if (!speed) { + + element.style.left = to + 'px'; + return; + + } + + var start = +new Date; + + var timer = setInterval(function() { + + var timeElap = +new Date - start; + + if (timeElap > speed) { + + element.style.left = to + 'px'; + + if (delay) begin(); + + options.transitionEnd && options.transitionEnd.call(event, index, slides[index]); + + clearInterval(timer); + return; + + } + + element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px'; + + }, 4); + + } + + // setup auto slideshow + var delay = options.auto || 0; + var interval; + + function begin() { + + interval = setTimeout(next, delay); + + } + + function stop() { + + delay = 0; + clearTimeout(interval); + + } + + + // setup initial vars + var start = {}; + var delta = {}; + var isScrolling; + + // setup event capturing + var events = { + + handleEvent: function(event) { + + switch (event.type) { + case 'touchstart': this.start(event); break; + case 'touchmove': this.move(event); break; + case 'touchend': offloadFn(this.end(event)); break; + case 'webkitTransitionEnd': + case 'msTransitionEnd': + case 'oTransitionEnd': + case 'otransitionend': + case 'transitionend': offloadFn(this.transitionEnd(event)); break; + case 'resize': offloadFn(setup); break; + } + + if (options.stopPropagation) event.stopPropagation(); + + }, + start: function(event) { + + var touches = event.touches[0]; + + // measure start values + start = { + + // get initial touch coords + x: touches.pageX, + y: touches.pageY, + + // store time to determine touch duration + time: +new Date + + }; + + // used for testing first move event + isScrolling = undefined; + + // reset delta and end measurements + delta = {}; + + // attach touchmove and touchend listeners + element.addEventListener('touchmove', this, false); + element.addEventListener('touchend', this, false); + + }, + move: function(event) { + + // ensure swiping with one touch and not pinching + if ( event.touches.length > 1 || event.scale && event.scale !== 1) return + + if (options.disableScroll) event.preventDefault(); + + var touches = event.touches[0]; + + // measure change in x and y + delta = { + x: touches.pageX - start.x, + y: touches.pageY - start.y + } + + // determine if scrolling test has run - one time test + if ( typeof isScrolling == 'undefined') { + isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) ); + } + + // if user is not trying to scroll vertically + if (!isScrolling) { + + // prevent native scrolling + event.preventDefault(); + + // stop slideshow + stop(); + + // increase resistance if first or last slide + if (options.continuous) { // we don't add resistance at the end + + translate(circle(index-1), delta.x + slidePos[circle(index-1)], 0); + translate(index, delta.x + slidePos[index], 0); + translate(circle(index+1), delta.x + slidePos[circle(index+1)], 0); + + } else { + + delta.x = + delta.x / + ( (!index && delta.x > 0 // if first slide and sliding left + || index == slides.length - 1 // or if last slide and sliding right + && delta.x < 0 // and if sliding at all + ) ? + ( Math.abs(delta.x) / width + 1 ) // determine resistance level + : 1 ); // no resistance if false + + // translate 1:1 + translate(index-1, delta.x + slidePos[index-1], 0); + translate(index, delta.x + slidePos[index], 0); + translate(index+1, delta.x + slidePos[index+1], 0); + } + + } + + }, + end: function(event) { + + // measure duration + var duration = +new Date - start.time; + + // determine if slide attempt triggers next/prev slide + var isValidSlide = + Number(duration) < 250 // if slide duration is less than 250ms + && Math.abs(delta.x) > 20 // and if slide amt is greater than 20px + || Math.abs(delta.x) > width/2; // or if slide amt is greater than half the width + + // determine if slide attempt is past start and end + var isPastBounds = + !index && delta.x > 0 // if first slide and slide amt is greater than 0 + || index == slides.length - 1 && delta.x < 0; // or if last slide and slide amt is less than 0 + + if (options.continuous) isPastBounds = false; + + // determine direction of swipe (true:right, false:left) + var direction = delta.x < 0; + + // if not scrolling vertically + if (!isScrolling) { + + if (isValidSlide && !isPastBounds) { + + if (direction) { + + if (options.continuous) { // we need to get the next in this direction in place + + move(circle(index-1), -width, 0); + move(circle(index+2), width, 0); + + } else { + move(index-1, -width, 0); + } + + move(index, slidePos[index]-width, speed); + move(circle(index+1), slidePos[circle(index+1)]-width, speed); + index = circle(index+1); + + } else { + if (options.continuous) { // we need to get the next in this direction in place + + move(circle(index+1), width, 0); + move(circle(index-2), -width, 0); + + } else { + move(index+1, width, 0); + } + + move(index, slidePos[index]+width, speed); + move(circle(index-1), slidePos[circle(index-1)]+width, speed); + index = circle(index-1); + + } + + options.callback && options.callback(index, slides[index]); + + } else { + + if (options.continuous) { + + move(circle(index-1), -width, speed); + move(index, 0, speed); + move(circle(index+1), width, speed); + + } else { + + move(index-1, -width, speed); + move(index, 0, speed); + move(index+1, width, speed); + } + + } + + } + + // kill touchmove and touchend event listeners until touchstart called again + element.removeEventListener('touchmove', events, false) + element.removeEventListener('touchend', events, false) + + }, + transitionEnd: function(event) { + + if (parseInt(event.target.getAttribute('data-index'), 10) == index) { + + if (delay) begin(); + + options.transitionEnd && options.transitionEnd.call(event, index, slides[index]); + + } + + } + + } + + // trigger setup + setup(); + + // start auto slideshow if applicable + if (delay) begin(); + + + // add event listeners + if (browser.addEventListener) { + + // set touchstart event on element + if (browser.touch) element.addEventListener('touchstart', events, false); + + if (browser.transitions) { + element.addEventListener('webkitTransitionEnd', events, false); + element.addEventListener('msTransitionEnd', events, false); + element.addEventListener('oTransitionEnd', events, false); + element.addEventListener('otransitionend', events, false); + element.addEventListener('transitionend', events, false); + } + + // set resize event on window + window.addEventListener('resize', events, false); + + } else { + + window.onresize = function () { setup() }; // to play nice with old IE + + } + + // expose the Swipe API + return { + setup: function() { + + setup(); + + }, + slide: function(to, speed) { + + // cancel slideshow + stop(); + + slide(to, speed); + + }, + prev: function() { + + // cancel slideshow + stop(); + + prev(); + + }, + next: function() { + + // cancel slideshow + stop(); + + next(); + + }, + stop: function() { + + // cancel slideshow + stop(); + + }, + getPos: function() { + + // return current index position + return index; + + }, + getNumSlides: function() { + + // return total number of slides + return length; + }, + kill: function() { + + // cancel slideshow + stop(); + + // reset element + element.style.width = ''; + element.style.left = ''; + + // reset slides + var pos = slides.length; + while(pos--) { + + var slide = slides[pos]; + slide.style.width = ''; + slide.style.left = ''; + + if (browser.transitions) translate(pos, 0, 0); + + } + + // removed event listeners + if (browser.addEventListener) { + + // remove current event listeners + element.removeEventListener('touchstart', events, false); + element.removeEventListener('webkitTransitionEnd', events, false); + element.removeEventListener('msTransitionEnd', events, false); + element.removeEventListener('oTransitionEnd', events, false); + element.removeEventListener('otransitionend', events, false); + element.removeEventListener('transitionend', events, false); + window.removeEventListener('resize', events, false); + + } + else { + + window.onresize = null; + + } + + } + } + +} + + +if ( window.jQuery || window.Zepto ) { + (function($) { + $.fn.Swipe = function(params) { + return this.each(function() { + $(this).data('Swipe', new Swipe($(this)[0], params)); + }); + } + })( window.jQuery || window.Zepto ) +} \ No newline at end of file diff --git a/mobile/shop/index.php b/mobile/shop/index.php index 284c7609b..0186a4c9b 100644 --- a/mobile/shop/index.php +++ b/mobile/shop/index.php @@ -6,13 +6,14 @@ define("_INDEX_", TRUE); include_once(G5_MSHOP_PATH.'/shop.head.php'); ?> - + -
+
-
-
+
+ +

최신상품

최신상품 모음

@@ -30,9 +31,11 @@ include_once(G5_MSHOP_PATH.'/shop.head.php'); echo $list->run(); ?> -
+
+ -
+ +

히트상품

히트상품 모음

@@ -50,9 +53,11 @@ include_once(G5_MSHOP_PATH.'/shop.head.php'); echo $list->run(); ?> -
+
+ -
+ +

추천상품

추천상품 모음

@@ -70,9 +75,11 @@ include_once(G5_MSHOP_PATH.'/shop.head.php'); echo $list->run(); ?> -
+
+ -
+ +

인기상품

인기상품 모음

@@ -90,9 +97,11 @@ include_once(G5_MSHOP_PATH.'/shop.head.php'); echo $list->run(); ?> -
+ + -
+ +

할인상품

할인상품 모음

@@ -110,7 +119,8 @@ include_once(G5_MSHOP_PATH.'/shop.head.php'); echo $list->run(); ?> -
+ + -
+

이벤트

이벤트 모음

-
+ @@ -135,17 +145,15 @@ include_once(G5_MSHOP_PATH.'/shop.head.php');