Skip to content

Commit

Permalink
lucky-card v1
Browse files Browse the repository at this point in the history
  • Loading branch information
feifanli committed Sep 14, 2015
1 parent 6387e32 commit ab5399e
Show file tree
Hide file tree
Showing 11 changed files with 692 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
130 changes: 130 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# PageSlider #

PageSlider 是一个基于zepto.js用于实现H5单页面跟随手指上下滑动切换的组件,支持通过transform3D启动GPU加速,目前仅支持移动端touch设备。

## DEMO ##

请用手机扫描以下二维码,在打开的页面上下滑动查看效果
#![github](http://franslee.github.io/pageSlider/qr-code.png "pageSlider DEMO")

## 用法 ##

HTML结构

```html
<!DOCTYPE html>
<html>
<head>
<!-- styles, scripts, etc -->
</head>
<body>
<div class="section sec1"></div>
<div class="section sec2"></div>
<div class="section sec3"></div>
<div class="section sec4"></div>
</body>
</html>
```

在页面中引入组件所需样式表文件pageSlider.css

```html
<link rel="stylesheet" href="../dist/pageSlider.css">
```

本组件基于zepto,需要在页面中引入zepto.js文件

```html
<script src='http://cdn.bootcss.com/zepto/1.1.4/zepto.min.js'></script>
```

引入pageSlider.js/pageSlider.min.js文件

```html
<script src='../dist/pageSlider.js'></script>
```

在页面DOM加载完毕之后,初始化组件

```js
$(function() {
var pageSlider = PageSlider.case();
});
```

## 设置 settings ##

初始化PageSlider组件时,支持传入一个参数,用于配置组件功能

```js
PageSlider.case(optOrIndex);
```

* 参数optOrIndex可以是一个数字(number),用于设置初始显示的页码
* 参数optOrIndex也可以是一个json对象,允许的keys见下表

<table>
<tr>
<th>key</th>
<th>类型</th>
<th>默认值</th>
<th>描述</th>
</tr>
<tr>
<td>startPage</td>
<td>number</td>
<td>1</td>
<td>初始化时显示页面的页码</td>
</tr>
<tr>
<td>range</td>
<td>number</td>
<td>70</td>
<td>页面回弹的最大距离(像素),小于该值页面回弹,超过该值页面将切换</td>
</tr>
<tr>
<td>duration</td>
<td>number</td>
<td>200</td>
<td>页面回弹动画持续的时间(毫秒)</td>
</tr>
<tr>
<td>loop</td>
<td>boolean</td>
<td>false</td>
<td>是否循环切换</td>
</tr>
<tr>
<td>elastic</td>
<td>boolean</td>
<td>true</td>
<td>位于顶部(底部)时,是否依然可以向上(向下)拉动</td>
</tr>
<tr>
<td>translate3d</td>
<td>boolean</td>
<td>true</td>
<td>是否使用translate3d(在支持translate3d的设备上),使用translate3d会使一些设备开启GPU加速,滑动更流畅</td>
</tr>
<tr>
<td>callback</td>
<td>object</td>
<td>{}</td>
<td>页面切换回调函数集合。该json对象每个键为一个数值,对应一个页码,值为一个function,滑动到该页面时触发。如:{2:function(){alert('滑动到了第二页');},4:function(){alert('滑动到了第四页');}} 滑动到第二和第四页时将触发对应的回调函数</td>
</tr>
</table>

```js
PageSlider.case({loop:true});
```

## 切换到指定页面 ##

在页面初始化后,可调用组件的go方法跳转到指定页面。

```js
//PageSlider初始化
var pageSlider = PageSlider.case();
//跳转到第3页
pageSlider.go(3);
```
53 changes: 53 additions & 0 deletions demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<title>lucky-card.js demo</title>
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, width=device-width">
<style>
html,
body {
margin: 0;
padding: 0;
}

body {
background: #FFFFFF;
}

#card {
height: 100%;
font-weight: bold;
font-size: 36px;
line-height: 100px;
text-align: center;
background: #FAFAFA;
}

#scratch {
width: 300px;
height: 100px;
margin: 50px auto 0;
border: 1px solid #ccc;
}
</style>
<link rel="stylesheet" href="./dist/lucky-card.css">
<script src="./dist/lucky-card.min.js"></script>
</head>

<body>
<div id="scratch">
<div id="card">¥1000.00万</div>
</div>
<script>
LuckyCard.case({
ratio: .6
}, function() {
alert('至于你信不信,我反正不信!');
this.clearCover();
});
</script>
</body>

</html>
Binary file added demo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions dist/lucky-card.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#scratch{ position: relative;}
#cover{ position: absolute; top:0; left:0;}
#card{ -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; user-select:none;}
206 changes: 206 additions & 0 deletions dist/lucky-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* lucky-card.js - Scratch CARDS based on HTML5 Canvas
*
* Copyright (c) 2015 Frans Lee dmon@foxmail.com
*
* https://github.com/Franslee/lucky-card
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* Version: 1.0
*
*/
;
(function(window, document, undefined) {
'use strict';

/**
* Instantiate parameters
*
* @constructor
*/
function LuckyCard(settings, callback) {
this.cover = null;
this.ctx = null;
this.scratchDiv = null;
this.cardDiv = null;
this.cHeight = 0;
this.cWidth = 0;
this.supportTouch = false;
this.events = [];
this.startEventHandler = null;
this.moveEventHandler = null;
this.endEventHandler = null;

this.opt = {
coverColor: '#C5C5C5',
coverImg: '',
ratio: .8,
callback: null
};

this.init(settings, callback);
};

function _calcArea(ctx, callback, ratio) {
var pixels = ctx.getImageData(0, 0, 300, 100);
var transPixels = [];
_forEach(pixels.data, function(item, i) {
var pixel = pixels.data[i + 3];
if (pixel === 0) {
transPixels.push(pixel);
}
});

if (transPixels.length / pixels.data.length > ratio) {
callback && typeof callback === 'function' && callback();
}
}

function _forEach(items, callback) {
return Array.prototype.forEach.call(items, function(item, idx) {
callback(item, idx);
});
}

/**
* touchstart/mousedown event handler
*/
function _startEventHandler(event) {
this.moveEventHandler = _moveEventHandler.bind(this);
this.cover.addEventListener(this.events[1],this.moveEventHandler,false);
this.endEventHandler = _endEventHandler.bind(this);
document.addEventListener(this.events[2],this.endEventHandler,false);
event.preventDefault();
};

/**
* touchmove/mousemove event handler
*/
function _moveEventHandler(event) {
var evt = this.supportTouch?event.touches[0]:event;
var coverPos = this.cover.getBoundingClientRect();
var mouseX = evt.pageX - coverPos.left;
var mouseY = evt.pageY - coverPos.top;

this.ctx.beginPath();
this.ctx.fillStyle = '#FFFFFF';
this.ctx.globalCompositeOperation = "destination-out";
this.ctx.arc(mouseX, mouseY, 10, 0, 2 * Math.PI);
this.ctx.fill();

event.preventDefault();
};

/**
* touchend/mouseup event handler
*/
function _endEventHandler(event) {
if (this.opt.callback && typeof this.opt.callback === 'function') _calcArea(this.ctx, this.opt.callback, this.opt.ratio);
this.cover.removeEventListener(this.events[1],this.moveEventHandler,false);
document.removeEventListener(this.events[2],this.endEventHandler,false);
event.preventDefault();
};

/**
* Create Canvas element
*/
LuckyCard.prototype.createCanvas = function() {
this.cover = document.createElement('canvas');
this.cover.id = 'cover';
this.cover.height = this.cHeight;
this.cover.width = this.cWidth;
this.ctx = this.cover.getContext('2d');
if (this.opt.coverImg) {
var _this = this;
var coverImg = new Image();
coverImg.src = this.opt.coverImg;
coverImg.onload = function() {
_this.ctx.drawImage(coverImg, 0, 0, _this.cover.width, _this.cover.height);
}
} else {
this.ctx.fillStyle = this.opt.coverColor;
this.ctx.fillRect(0, 0, this.cover.width, this.cover.height);
}
this.scratchDiv.appendChild(this.cover);
}

/**
* To detect whether support touch events
*/
LuckyCard.prototype.eventDetect = function() {
if('ontouchstart' in window) this.supportTouch = true;
this.events = this.supportTouch ? ['touchstart', 'touchmove', 'touchend'] : ['mousedown', 'mousemove', 'mouseup'];
this.addEvent();
};

/**
* Add touchstart/mousedown event listener
*/
LuckyCard.prototype.addEvent = function() {
this.startEventHandler = _startEventHandler.bind(this);
this.cover.addEventListener(this.events[0],this.startEventHandler,false);
};

/**
* Clear pixels of canvas
*/
LuckyCard.prototype.clearCover = function() {
this.ctx.clearRect(0, 0, this.cover.width, this.cover.height);
};


/**
* LuckyCard initializer
*
* @param {Object} settings Settings for LuckyCard
* @param {function} callback callback function
*/
LuckyCard.prototype.init = function(settings, callback) {
var _this = this;
_forEach(arguments, function(item) {
if (typeof item === "object") {
for (var k in item) {
if (k === 'callback' && typeof item[k] === 'function') {
_this.opt.callback = item[k].bind(_this);
} else {
_this.opt[k] && (_this.opt[k] = item[k]);
}
}
} else if (typeof item === "function") {
_this.opt.callback = item.bind(_this);
}
});
this.scratchDiv = document.getElementById('scratch');
this.cardDiv = document.getElementById('card');
if (!this.scratchDiv || !this.cardDiv) return;
this.cHeight = this.cardDiv.clientHeight;
this.cWidth = this.cardDiv.clientWidth;
this.createCanvas();
this.eventDetect();
};

/**
* To generate an instance of object
*
* @param {Object} settings Settings for LuckyCard
* @param {function} callback callback function
*/
LuckyCard.case = function(settings, callback) {
return new LuckyCard(settings, callback);
};


if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
define(function() {
return LuckyCard;
});
} else if (typeof module !== 'undefined' && module.exports) {
module.exports = LuckyCard.case;
module.exports.LuckyCard = LuckyCard;
} else {
window.LuckyCard = LuckyCard;
}

})(window, document);
Loading

0 comments on commit ab5399e

Please sign in to comment.