Touch.js是移動設備上的手勢識別與事件庫, 由百度雲Clouda團隊維護,也是在百度內部廣泛使用的開發工具.
Touch.js的代碼已托管於github並開源,希望能幫助國內更多的開發者學習和開發出優秀的App產品.
Touch.js手勢庫專為移動設備設計, 請在Webkit內核瀏覽器中使用.
Examples
//swipe example touch.on('.target', 'swipeleft swiperight', function(ev){ console.log("you have done", ev.type); });
http://www.cnblogs.com/lukunlin/p/4514253.html?utm_source=tuicool&utm_medium=referral
今天,隨便搜搜看到了一個新的手勢庫,也許能讓我為現在使用者的hammer.js的手勢庫帶來的煩惱而消除。
它是百度團隊開發的,現在由百度雲Clouda進行維護。
在我上一篇文章里有提到怎么去使用hammer.js的框架,他有個比較讓人煩躁的缺點,就是事件綁定,每次只能綁定一個DOM元素,而且每次都需要去NEW 一個函數,大家都知道,每new一次都會在內存開辟一個新的空間,也就是他比較占用內存。
如:
var obj = new Hammer( document.getElementById('element') ); obj.on('tap',function);
如果是這樣,會給我們造成比較多的麻煩。
所以今天就簡單說說touch.js這個框架給我們開發帶來的便利。
我們看看它是如何給一個DOM快速選擇並且綁定事件的。
代碼:
touch.on(".div","tap",function);
就這樣簡單就能選擇到所有class為div的DOM元素加了一個點擊事件。
並且事件里面的this指向了發生事件的原生DOM的元素。
event對象是我們做手勢里用處比較多的一個對象,如發生的距離的X/Y,發生的type等。
http://cloudajs.org/formerIndex
百度touch.js API教程 http://blog.csdn.net/libin_1/article/details/50534611
下載:http://download.csdn.net/detail/cometwo/9407914
<!DOCTYPE html> <html> <head> <link href="img/favicon.ico" rel="shortcut icon" type="images/x-icon"> <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"> <meta content="initial-scale=1.0,maximum-scale=1.0,width=device-width" name="viewport"> <meta name="apple-touch-fullscreen" content="YES"> <meta name="format-detection" content="telephone=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta http-equiv="expires" content="0"> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <title>百度touch.js API教程[UC瀏覽器測試通過]</title> <script type="text/javascript" src="js/touch.min.js"></script> <script type="text/javascript" src="js/jquery-2.1.4.min.js"></script> <script type="text/javascript" src="js/hijs.js"></script> <style type="text/css"> *, html, body { padding: 0px; margin: 0px; left: 0px; top: 0px; } #main { padding: 5px; } #play { background: black; width: 100%; height: 800px; border: 1px solid red; position: relative; overflow: hidden; } img { position: absolute; width: 200px; height: 200px; display: block; left: 50%; top: 50%; margin-left: -100px; margin-top: -100px; border-radius: 50%; border: 1px solid red; } img:hover { cursor: pointer; } .div1 { margin-top: 10px; width: 100%; height: 50px; color: blue; font-size: 25px; line-height: 50px; background: green; text-align: center; } </style> <script type="text/javascript"> /*******************************旋轉程序****************************************/ /* $(function() { //旋轉程序 // runhijs(); //官方程序不知為什么要加,貌似不加也可以 var angle = 0; touch.on('#target', 'touchstart', function(ev) { ev.startRotate(); ev.preventDefault(); }); touch.on('#target', 'rotate', function(ev) { var totalAngle = angle + ev.rotation; if (ev.fingerStatus === 'end') { //這一句很重要 angle = angle + ev.rotation; $('.div1').text("本次旋轉角度為:" + ev.rotation + "度, 方向:" + ev.direction + "."); } this.style.webkitTransform = 'rotate(' + totalAngle + 'deg)'; }); }); */ /*******************************放大縮小****************************************/ // $(function() { //放大縮小 // var target = document.getElementById("target"); // target.style.webkitTransition = 'all ease 0.05s'; // touch.on('#target', 'touchstart', function(ev) { // ev.preventDefault(); // }); // var initialScale = 1; // var currentScale; // touch.on('#target', 'pinchend', function(ev) { // currentScale = ev.scale - 1; // currentScale = initialScale + currentScale; // currentScale = currentScale > 5 ? 5 : currentScale; //自己調節可以放大的最大倍數 // currentScale = currentScale < 0.1 ? 0.1 : currentScale; //自己調節可以縮小的最小倍數 // this.style.webkitTransform = 'scale(' + currentScale + ')'; // $('.div1').text("當前縮放比例為:" + currentScale + "倍."); // }); // touch.on('#target', 'pinchend', function(ev) { // initialScale = currentScale; // }); // }); /*******************************識別tap[單擊], doubletap[雙擊]和hold[長按]事件****************************************/ // $(function() { //識別tap[單擊], doubletap[雙擊]和hold[長按]事件 // $('.div1').text("識別tap[單擊], doubletap[雙擊]和hold[長按]事件."); // // touch.on('#target', 'touchstart', function(ev){ // // ev.preventDefault(); // // }); // touch.on('#target', 'hold tap doubletap', function(ev) { // $('.div1').text("當前事件為: " + ev.type); // var _this = this; // this.classList.add("bounce"); // touch.on(this, "webkitAnimationEnd", function() { // _this.classList.remove("bounce"); // }); // }); // }); /*******************************向左向右滑動****************************************/ // $(function() { // var w = 205; // var tw = play.offsetWidth; // var lf = document.getElementById("target").offsetLeft; // var rt = tw - w - lf; // $('.div1').text("向左, 向右swipe滑動"); // touch.on('#target', 'touchstart', function(ev) { // ev.preventDefault(); // }); // var target = document.getElementById("target"); // target.style.webkitTransition = 'all ease 0.2s'; // touch.on(target, 'swiperight', function(ev) { // this.style.webkitTransform = "translate3d(" + rt + "px,0,0)"; // $('.div1').text("向右滑動."); // }); // touch.on(target, 'swipeleft', function(ev) { // $('.div1').text("向左滑動."); // this.style.webkitTransform = "translate3d(-" + this.offsetLeft + "px,0,0)"; // }); // }); /*******************************抓取並拖拽目標元素****************************************/ $(function() { $('.div1').text("抓取並拖拽目標元素"); touch.on('#target', 'touchstart', function(ev) { ev.preventDefault(); }); var target = document.getElementById("target"); var dx, dy; touch.on('#target', 'drag', function(ev) { dx = dx || 0; dy = dy || 0; var offx = dx + ev.x + "px"; var offy = dy + ev.y + "px"; this.style.webkitTransform = "translate3d(" + offx + "," + offy + ",0)"; }); touch.on('#target', 'dragend', function(ev) { dx += ev.x; dy += ev.y; $('.div1').text("當前x值為:" + dx + ", 當前y值為:" + dy + "."); }); }); /*******************************抓取並拖拽目標元素****************************************/ // $(function() { // $('.div1').text("識別原生事件"); // touch.on('#target', 'touchstart', function(ev) { // ev.preventDefault(); // }); // touch.on('#target', 'touchstart touchmove touchend', function(ev) { // var _this = this; // if (!this.classList.contains("bounce")) { // if (ev.type === "mousedown" || ev.type === "touchstart") { // this.classList.add("bounce"); // touch.on(this, "webkitAnimationEnd", function() { // _this.classList.remove("bounce"); // }); // } // } // $('.div1').text("當前為原生事件: " + ev.type); // }); // }); </script> </head> <body> <div id="main"> <h1 style="color: red;text-align: center;">使用哪個只需要打開相應的注釋即可</h1> <div id="play"> <img id="target" draggable="false" src="img/cloud.png" /> </div> <div class="div1">"touch.js demo記錄每一次操作"</div> </div> </body> </html>
原文:http://mobile.51cto.com/news-414811_all.htm
¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
Touch
在開發移動端的應用中會使用到很多的手勢操作,例如一指拖動、兩指旋轉等等,為了方便開放者快速集成這些手勢,在Clouda中內置了事件和手勢庫Library.touch,下面將詳細的介紹如何使用Library.touch。
touch.config
語法: touch.config(config)
對手勢事件庫進行全局配置。
參數描述:
config為一個對象
{
tap: true, //tap類事件開關, 默認為true
doubleTap: true, //doubleTap事件開關, 默認為true
hold: true, //hold事件開關, 默認為true
holdTime: 650, //hold時間長度
swipe: true, //swipe事件開關
swipeTime: 300, //觸發swipe事件的最大時長
swipeMinDistance: 18, //swipe移動最小距離
swipeFactor: 5, //加速因子, 值越大變化速率越快
drag: true, //drag事件開關
pinch: true, //pinch類事件開關
}
touch.on
語法:touch.on(element, types, options, callback)
綁定指定元素的事件。
參數描述:
element: 元素對象或選擇器。
types: 事件的類型, 可接受多個事件以空格分開,支持原生事件的透傳, 支持的一些事件類型有:
pinchstart 雙指縮放動作開始
pinchend 雙指縮放動作結束
pinch 雙指縮放事件
pinchin 雙指向里縮小
pinchout 雙指向外放大
rotateleft 向左旋轉
rotateright 向右旋轉
rotate 旋轉事件
swipestart 單指滑動動作開始
swiping 單指滑動事件
swipeend 單指滑動動作結束
swipeleft 單指向左滑動
swiperight 單指向右滑動事件
swipeup 單指向上滑動
swipedown 單指向下滑動
swipe 單指滑動事件
drag 單指向左右拖動
hold 單指按住不放事件
tap 單指點擊
doubletap 單指雙擊
例如旋轉實例如下:
var angle = 30;
touch.on(‘#rotation .target’, ‘touchstart’, function(ev){
ev.startRotate();
ev.originEvent.preventDefault();
ev.originEvent.stopPropagation();
});
touch.on(‘#rotation .target’, ‘rotate’, {interval: 10}, function(ev){
var totalAngle = angle + ev.rotation;
if(ev.fingerStatus === ‘end’){
angle = angle + ev.rotation;
}
this.style.webkitTransform = ‘rotate(’ + totalAngle + ‘deg)’;
});
更多使用實例請查看http://code.baidu.com/
options(可選): 目前可配置的參數為:
{
//采樣頻率
interval: 10,//性能參數,值越小,實時性越好, 但性能可能略差, 值越大, 性能越好。遇到性能問題時,可以將值設大調優,建議值設置為10。
//swipe加速度因子(swipe事件專用)
swipeFactor: 5 //(int: 1-10)值越大,速率更快。
}
callback: 事件處理函數, 該函數接受的參數為一個gesture event object, 可訪問的屬性有:
originEvent //觸發某事件的原生對象
type //事件的名稱
rotation //旋轉角度
scale //縮放比例
direction //操作的方向屬性
fingersCount //操作的手勢數量
position //相關位置信息, 不同的操作產生不同的位置信息。
distance //swipe類兩點之間的位移
distanceX //swipe類事件x方向的位移
distanceY //swipe類事件y方向的位移
angle //swipe類事件觸發時偏移角度
factor //swipe事件加速度因子
startRotate //啟動單指旋轉方法,在某個元素的touchstart觸發時調用。
touch.live
語法:touch.live(selector, types, options, callback)
使用方法基本上與on相同,live的第一個參數只接受css3選擇器。通過live()方法附加的事件處理程序適用於匹配選擇器的當前及未來的元素(比如由腳本創建的新元素)
touch.off
語法:touch.off(element,types,callback)
解除某元素上的事件綁定。
參數描述:
element:元素對象或選擇器
types:事件的類型
callback:時間處理函數
Publish/Subscribe
subscribe
訂閱被發布的數據,與pubilsh配合使用
不帶參數 env.subscribe(publishName, function(collection){});
env.subscribe(“pub-allStudents”, function(studentCollection){
});
pulishName
所定義的Publish的唯一名稱,在一個App內全局唯一,該參數與sumeru.publish(modelName, publishName,function(callback))中的publishName名稱需要保持一致。
function(Collection){}
Subscribe成功獲得數據時,被調用的響應方法。
帶參數 env.subscribe(publishName,arg1,arg2, … , function(collection){});
env.subscribe(“pub-StudentsWithGender”, “male”, function(msgCollection){
});
subscribeByPage
分頁訂閱數據
不帶參數 env.subscribeByPage(publishName, options, function(collection){});
var pageOption{
pagesize : 1,
page : 2,
uniqueField : ‘time’
};
env.subscribeByPage(“pub-allStudents”, pageOption, function(studentCollection){
});
options
分頁設置
pageSize
每頁數據的數量
page
頁碼
uniqueField
排序的唯一字段名
帶參數 env.subscribeByPage(publishName, options, arg1,arg2, … , function(collection){});
env.subscribeByPage(“pub-StudentsWithGender”, pageOption, “male”, function(msgCollection){
});
prioritySubscribe
在斷線重新連接的情況下,使用prioritySubscribe方法訂閱數據優先被調用,使用方式與subscribe相同。
publish
發布數據的方法,其運行在Server上。
不帶參數 sumeru.publish(modelName,pubName,function(callback){},options)
modelName
被發布數據所屬的Model名稱
pubName
所定義的Publish的唯一名稱,在一個App內全局唯一,該參數與Controller中subscribe()成對使用。
function(callback)
描述數據發布規則的自定義函數,在這里定義被發布數據所需要符合的條件。
options
可在此添加以下六種事件
beforeInsert
在實際插入數據到數據庫前的事件
beforeInsert : function(serverCollection, structData, userinfo, callback){
callback(structData);
}
structData
需要插入到數據庫的數據,我們可以對該數據進行操作,然后將數據插入到數據庫中,如果對數據沒有修改,則將原數據添加到數據庫中。
callback
before系列的事件中如果不添加 callback(),將阻止數據對數據庫的影響。
callback(structData)
如果需要對原數據進行修改,可以傳入參數structData
afterInsert
在實際插入數據到數據庫后的事件
afterInsert : function(serverCollection, structData){
}
beforeUpdate
在實際更新數據庫數據前的事件
beforeUpdate : function(serverCollection, structData, userinfo, callback){
callback();
}
afterUpdate
在實際更新數據庫數據后的事件
afterUpdate : function(serverCollection, structData){
}
beforeDelete
在實際刪除數據庫數據前的事件
beforeDelete : function(serverCollection, structData, userinfo, callback){
callback();
}
afterDelete
在實際刪除數據庫數據后的事件
afterDelete : function(serverCollection, structData){
}
實例:
module.exports = function(sumeru){
sumeru.publish(‘student’, ‘pub-allStudents’, function(callback){
var collection = this;
collection.find({}, function(err, items){
callback(items);
});
});
}
帶參數 sumeru.publish(modelName,pubName,function(arg1, …, callback){},options)
實例:
module.exports = function(sumeru){
sumeru.publish(‘student’, ‘pub-allStudents’, function(gender,callback){
var collection = this;
collection.find({'gender':gender}, function(err, items){
callback(items);
});
});
}
publishByPage
分頁發布數據
sumeru.publishByPage(modelName,pubName,function(arg1,arg2,…,pageOptions, callback){},options)
options
分頁設置,有Controller中subscribeByPage()傳入。
實例:
sumeru.publishByPage(‘student’, ‘pub-allStudents’, function(gender,options,callback){
var collection = this;
collection.find({ sort :{‘time’:-1},
limit : options.pagesize,
skip : (options.page-1)*options.pagesize,
“gender”: gender
}, function(err, items){
callback(items);
});
});
sort
排序
limit
每頁顯示的個數
skip
當前頁與起始頁間隔的個數
詳細的使用情況請查看《Example》文檔中的實例。
publishPlain
用於發布簡單對象,而非Collection。
sumeru.publishPlain(modelName,pubName,function(callback){},options)
實例:
如果需要發布Collection中數據的總數量,可使用下面方法:
fw.publishPlain(‘student’, ‘pub-allStudents’, function(callback){
var collection = this;
collection.count({},function(err, count){
callback(count);
});
});
下面的三種方法是包含權限中心的身份驗證的Publish。
securePublish
在身份驗證成功的情況下發布數據
sumeru.publish(modelName,pubName,function(userinfo, callback){},options)
securePublishByPage
在身份驗證成功的情況下分頁發布數據
sumeru.securePublishByPage(modelName,pubName,function(pageOptions,userinfo, callback){},options)
securePublishPlain
在身份驗證成功的情況下發布簡單對象
sumeru.securePublishPlain(modelName,pubName,function(userinfo, callback){},options)
external
實現了三方數據同步的方法,用來滿足從三方網站/三方接口獲取和同步數據的需求。
extfind(pubName,callback)
在publish文件中發布第三方數據
fw.publish(‘news’,’pubnews’,function(callback){
var collection = this;
collection.extfind('pubnews',callback);
});
使用該方法需要在publish下添加一個如何獲取第三方數據的配置文件
config[pubname]
pubname
與publish中collection.extfind(pubname,callback)方法pubname一致,全局唯一
uniqueColumn
uniqueColumn為三方數據唯一標識,類型為String
uniqueColumn : “name”,
fetchUrl: function((/* arg1, arg2, arg3 /)){}
指定抓取的URL。arg1,arg2為傳遞的參數
fetchUrl : function(/* arg1, arg2, arg3 /){
return ‘http://some.host.com‘;
}
resolve : function(originData){}
resolve方法作用是將抓取回來的原始數據(originData)轉化成為符合Model定義的數據(resolved)
resolve : function(originData){
var j = JSON.parse(originData);
var resolved = j;
return resolved;
}
fetchInterval
fetchInterval為可選參數,用來指定抓取時間間隔,單位為ms
buffer
buffer為可選參數,值為true時表示獲取原始Buffer,否則獲取原始數據字符串
type
聲明此模塊為歸屬為’external’
return {
type : ‘external’,
config : config
}
實例如下:
/**
* 獲取三方數據信息,由開發者自定義
*/
function runnable(){
//{Object} config是所有三方publish配置的容器
var config = {};
config['pubext'] = {
//{String} uniqueColumn為三方數據唯一標識
uniqueColumn : "name",
//{Function} fetchUrl的參數就是訂閱時發起的參數,返回值為pubext所抓取的url地址
fetchUrl : function(/** arg1, arg2, arg3 */){
return 'http://some.host.com';
},
//{Function} resolve方法作用是將抓取回來的原始數據(originData)轉化成為符合Model定義的數據(resolved)
resolve : function(originData){
var j = JSON.parse(originData);
var resolved = j;
return resolved;
},
//{Number} fetchInterval為可選參數,用來指定抓取時間間隔,單位為ms
fetchInterval : 60 * 1000,
//{Boolean} buffer為可選參數,值為true時表示獲取原始Buffer,否則獲取原始數據字符串
buffer : false
}
//最后需要聲明此模塊為歸屬為'external'
return {
type : 'external',
config : config
}
}
module.exports = runnable;
指定三方增/刪/改接口以及數據
當數據發生變化時,如何使用Clouda達到三方數據同步的效果,具體實現方法如下:
較為緊湊的聲明方式
postUrl
postUrl方法用來指定三方post接口的地址信息, 參數type為增量類型,增量類型為’insert’,’update’,’delete’三者之一;
prepare
prepare方法用來將增量數據轉化成為符合三方POST接口要求的post數據,參數type同為增量類型,參數data為增量的實際數據。
實例如下:
/**
* 三方數據POST請求信息,由開發者自定義
*/
function runnable(){
var config = {}
config['pubext'] = {
/**
* 聲明三方POST接口地址
* {String} type為'delete', 'insert', 'update'其中之一
* 如果subscribe時帶參數,參數會按照subscribe順序接在postUrl的參數中
*/
postUrl : function(type /** arg1, arg2, arg3... */){
var options = {
host : 'some.host.com',
path : '/' + type ,
headers: {
//在此自定義header內容,clouda默認的 'Content-Type': 'application/x-www-form-urlencoded'
'Content-Type': ...
}
}
return options;
},
/**
* prepare方法將增量數據轉化為符合三方要求的post數據。
* {String} type為增量操作,值為'delete', 'insert', 'update'其一;
* {Object} data為增量數據,如:{ name : 'user1', age : 26 }。
*/
prepare : function(type, data){
var prepareData = {}; //prepareData為三方post所需的data
if(type === "delete"){
prepareData.name = data.name;
}else if(type === "insert"){
prepareData.name = data.name;
prepareData.age = data.age;
}else{
prepareData.name = data.name;
prepareData.age = data.age;
}
return prepareData;
}
}
return {
type : 'external',
config : config
}
}
module.exports = runnable;
較為工整的聲明方式
deleteUrl,insertUrl,updateUrl
三個方法作用等同於postUrl,返回不同操作下三方接口url信息
onDelete,onInsert,onUpdate
三個方法作用等同於prepare方法, 返回經過處理,傳給三方接口的post數據
實例如下:
function runnable(){
var config = {};
config['pubext'] = {
//arg1, arg2, arg3是subscribe時輸入的參數
deleteUrl : function(/** arg1, arg2, arg3... */){
return {
host : 'some.host.com',
path : '/delete'
}
},
insertUrl : function(/** arg1, arg2, arg3... */){
return {
host : 'some.host.com',
path : '/insert'
}
},
updateUrl : function(/** arg1, arg2, arg3... */){
return {
host : 'some.host.com',
path : '/update'
}
},
onInsert : function(data){
var prepareData = {};
prepareData.name = data.name;
prepareData.age = data.age;
return prepareData;
},
onUpdate : function(data){
var prepareData = {};
prepareData.name = data.name;
prepareData.age = data.age;
return prepareData;
},
onDelete : function(data){
var prepareData = {}
prepareData.name = data.name;
return prepareData;
}
}
return {
type : 'external',
config : config
}
}
module.exports = runnable;
sumeru.external.get
向第三方發送get請求
var url = “http://some.host.com“;
var getCallback = function(data){
console.log(data);
}
sumeru.external.get(url, getCallback);
sumeru.external.post
向第三方發送post請求
var options = {
host : “some.host.com”,
path : “/insert”
}
var postData = {
name : sumeru.utils.randomStr(8),
age : parseInt( 100 * Math.random())
}
var postCallback = function(data){
console.log(data);
}
sumeru.external.post(options, postData, postCallback);
具體使用請查看《Example》文檔中的SpiderNews實例。