UNPKG

amazeui

Version:

Sleek, intuitive, and powerful front-end framework for faster and easier web development.

412 lines (340 loc) 11.4 kB
'use strict'; var $ = require('jquery'); var UI = require('./core'); var PinchZoom = require('./ui.pinchzoom'); var Hammer = require('./util.hammer'); var animation = UI.support.animation; var transition = UI.support.transition; /** * PureView * @desc Image browser for Mobile * @param element * @param options * @constructor */ var PureView = function(element, options) { this.$element = $(element); this.$body = $(document.body); this.options = $.extend({}, PureView.DEFAULTS, options); this.$pureview = $(this.options.tpl).attr('id', UI.utils.generateGUID('am-pureview')); this.$slides = null; this.transitioning = null; this.scrollbarWidth = 0; this.init(); }; PureView.DEFAULTS = { tpl: '<div class="am-pureview am-pureview-bar-active">' + '<ul class="am-pureview-slider"></ul>' + '<ul class="am-pureview-direction">' + '<li class="am-pureview-prev"><a href=""></a></li>' + '<li class="am-pureview-next"><a href=""></a></li></ul>' + '<ol class="am-pureview-nav"></ol>' + '<div class="am-pureview-bar am-active">' + '<span class="am-pureview-title"></span>' + '<div class="am-pureview-counter"><span class="am-pureview-current"></span> / ' + '<span class="am-pureview-total"></span></div></div>' + '<div class="am-pureview-actions am-active">' + '<a href="javascript: void(0)" class="am-icon-chevron-left" ' + 'data-am-close="pureview"></a></div>' + '</div>', className: { prevSlide: 'am-pureview-slide-prev', nextSlide: 'am-pureview-slide-next', onlyOne: 'am-pureview-only', active: 'am-active', barActive: 'am-pureview-bar-active', activeBody: 'am-pureview-active' }, selector: { slider: '.am-pureview-slider', close: '[data-am-close="pureview"]', total: '.am-pureview-total', current: '.am-pureview-current', title: '.am-pureview-title', actions: '.am-pureview-actions', bar: '.am-pureview-bar', pinchZoom: '.am-pinch-zoom', nav: '.am-pureview-nav' }, shareBtn: false, // press to toggle Toolbar toggleToolbar: true, // 从何处获取图片,img 可以使用 data-rel 指定大图 target: 'img', // 微信 Webview 中调用微信的图片浏览器 // 实现图片保存、分享好友、收藏图片等功能 weChatImagePreview: true }; PureView.prototype.init = function() { var _this = this; var options = this.options; var $element = this.$element; var $pureview = this.$pureview; this.refreshSlides(); $('body').append($pureview); this.$title = $pureview.find(options.selector.title); this.$current = $pureview.find(options.selector.current); this.$bar = $pureview.find(options.selector.bar); this.$actions = $pureview.find(options.selector.actions); if (options.shareBtn) { this.$actions.append('<a href="javascript: void(0)" ' + 'class="am-icon-share-square-o" data-am-toggle="share"></a>'); } this.$element.on('click.pureview.amui', options.target, function(e) { e.preventDefault(); var clicked = _this.$images.index(this); // Invoke WeChat ImagePreview in WeChat // TODO: detect WeChat before init if (options.weChatImagePreview && window.WeixinJSBridge) { window.WeixinJSBridge.invoke('imagePreview', { current: _this.imgUrls[clicked], urls: _this.imgUrls }); } else { _this.open(clicked); } }); $pureview.find('.am-pureview-direction'). on('click.direction.pureview.amui', 'li', function(e) { e.preventDefault(); if ($(this).is('.am-pureview-prev')) { _this.prevSlide(); } else { _this.nextSlide(); } }); // Nav Contorl $pureview.find(options.selector.nav).on('click.nav.pureview.amui', 'li', function() { var index = _this.$navItems.index($(this)); _this.activate(_this.$slides.eq(index)); }); // Close Icon $pureview.find(options.selector.close). on('click.close.pureview.amui', function(e) { e.preventDefault(); _this.close(); }); this.$slider.hammer().on('swipeleft.pureview.amui', function(e) { e.preventDefault(); _this.nextSlide(); }).on('swiperight.pureview.amui', function(e) { e.preventDefault(); _this.prevSlide(); }).on('press.pureview.amui', function(e) { e.preventDefault(); options.toggleToolbar && _this.toggleToolBar(); }); this.$slider.data('hammer').get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.35 }); // Observe DOM $element.DOMObserve({ childList: true, subtree: true }, function(mutations, observer) { // _this.refreshSlides(); // console.log('mutations[0].type); }); // NOTE: // trigger this event manually if MutationObserver not supported // when new images appended, or call refreshSlides() // if (!UI.support.mutationobserver) $element.trigger('changed.dom.amui') $element.on('changed.dom.amui', function(e) { e.stopPropagation(); _this.refreshSlides(); }); $(document).on('keydown.pureview.amui', $.proxy(function(e) { var keyCode = e.keyCode; if (keyCode == 37) { this.prevSlide(); } else if (keyCode == 39) { this.nextSlide(); } else if (keyCode == 27) { this.close(); } }, this)); }; PureView.prototype.refreshSlides = function() { // update images collections this.$images = this.$element.find(this.options.target); var _this = this; var options = this.options; var $pureview = this.$pureview; var $slides = $([]); var $navItems = $([]); var $images = this.$images; var total = $images.length; this.$slider = $pureview.find(options.selector.slider); this.$nav = $pureview.find(options.selector.nav); var viewedFlag = 'data-am-pureviewed'; // for WeChat Image Preview this.imgUrls = this.imgUrls || []; if (!total) { return; } if (total === 1) { $pureview.addClass(options.className.onlyOne); } $images.not('[' + viewedFlag + ']').each(function(i, item) { var src; var title; // get image URI from link's href attribute if (item.nodeName === 'A') { src = item.href; // to absolute path title = item.title || ''; } else { // NOTE: `data-rel` should be a full URL, otherwise, // WeChat images preview will not work src = $(item).data('rel') || item.src; // <img src='' data-rel='' /> src = UI.utils.getAbsoluteUrl(src); title = $(item).attr('alt') || ''; } // add pureviewed flag item.setAttribute(viewedFlag, '1'); // hide bar: wechat_webview_type=1 // http://tmt.io/wechat/ not working? _this.imgUrls.push(src); $slides = $slides.add($('<li data-src="' + src + '" data-title="' + title + '"></li>')); $navItems = $navItems.add($('<li>' + (i + 1) + '</li>')); }); $pureview.find(options.selector.total).text(total); this.$slider.append($slides); this.$nav.append($navItems); this.$navItems = this.$nav.find('li'); this.$slides = this.$slider.find('li'); }; PureView.prototype.loadImage = function($slide, callback) { var appendedFlag = 'image-appended'; if (!$slide.data(appendedFlag)) { var $img = $('<img>', { src: $slide.data('src'), alt: $slide.data('title') }); $slide.html($img).wrapInner('<div class="am-pinch-zoom"></div>').redraw(); var $pinchWrapper = $slide.find(this.options.selector.pinchZoom); $pinchWrapper.data('amui.pinchzoom', new PinchZoom($pinchWrapper[0], {})); $slide.data('image-appended', true); } callback && callback.call(this); }; PureView.prototype.activate = function($slide) { var options = this.options; var $slides = this.$slides; var activeIndex = $slides.index($slide); var title = $slide.data('title') || ''; var active = options.className.active; if ($slides.find('.' + active).is($slide)) { return; } if (this.transitioning) { return; } this.loadImage($slide, function() { UI.utils.imageLoader($slide.find('img'), function(image) { $slide.find('.am-pinch-zoom').addClass('am-pureview-loaded'); $(image).addClass('am-img-loaded'); }); }); this.transitioning = 1; this.$title.text(title); this.$current.text(activeIndex + 1); $slides.removeClass(); $slide.addClass(active); $slides.eq(activeIndex - 1).addClass(options.className.prevSlide); $slides.eq(activeIndex + 1).addClass(options.className.nextSlide); this.$navItems.removeClass(). eq(activeIndex).addClass(options.className.active); if (transition) { $slide.one(transition.end, $.proxy(function() { this.transitioning = 0; }, this)).emulateTransitionEnd(300); } else { this.transitioning = 0; } // TODO: pre-load next image }; PureView.prototype.nextSlide = function() { if (this.$slides.length === 1) { return; } var $slides = this.$slides; var $active = $slides.filter('.am-active'); var activeIndex = $slides.index($active); var rightSpring = 'am-animation-right-spring'; if (activeIndex + 1 >= $slides.length) { // last one animation && $active.addClass(rightSpring).on(animation.end, function() { $active.removeClass(rightSpring); }); } else { this.activate($slides.eq(activeIndex + 1)); } }; PureView.prototype.prevSlide = function() { if (this.$slides.length === 1) { return; } var $slides = this.$slides; var $active = $slides.filter('.am-active'); var activeIndex = this.$slides.index(($active)); var leftSpring = 'am-animation-left-spring'; if (activeIndex === 0) { // first one animation && $active.addClass(leftSpring).on(animation.end, function() { $active.removeClass(leftSpring); }); } else { this.activate($slides.eq(activeIndex - 1)); } }; PureView.prototype.toggleToolBar = function() { this.$pureview.toggleClass(this.options.className.barActive); }; PureView.prototype.open = function(index) { var active = index || 0; this.checkScrollbar(); this.setScrollbar(); this.activate(this.$slides.eq(active)); this.$pureview.show().redraw().addClass(this.options.className.active); this.$body.addClass(this.options.className.activeBody); }; PureView.prototype.close = function() { var options = this.options; this.$pureview.removeClass(options.className.active); this.$slides.removeClass(); function resetBody() { this.$pureview.hide(); this.$body.removeClass(options.className.activeBody); this.resetScrollbar(); } if (transition) { this.$pureview.one(transition.end, $.proxy(resetBody, this)). emulateTransitionEnd(300); } else { resetBody.call(this); } }; PureView.prototype.checkScrollbar = function() { this.scrollbarWidth = UI.utils.measureScrollbar(); }; PureView.prototype.setScrollbar = function() { var bodyPaddingRight = parseInt((this.$body.css('padding-right') || 0), 10); if (this.scrollbarWidth) { this.$body.css('padding-right', bodyPaddingRight + this.scrollbarWidth); } }; PureView.prototype.resetScrollbar = function() { this.$body.css('padding-right', ''); }; UI.plugin('pureview', PureView); // Init code UI.ready(function(context) { $('[data-am-pureview]', context).pureview(); }); module.exports = PureView; // TODO: 1. 动画改进 // 2. 改变图片的时候恢复 Zoom // 3. 选项 // 4. 图片高度问题:由于 PinchZoom 的原因,过高的图片如果设置看了滚动,则放大以后显示不全