当前位置: 首页 > news >正文

超级小的web手势库AlloyFinger

针对多点触控设备编程的Web手势组件,快速帮助你的web程序增加手势支持,也不用再担心click 300ms的延迟了。拥有两个版本,无依赖的独立版和react版本。除了Dom对象,也可监听Canvas内元素的手势(需要Canvas引擎内置对象支持addEventListener绑定touch相关事件)。

据不完全统计,目前AlloyFinger服务于:兴趣部落、QQ群、QQ动漫、腾讯学院、TEDxTencent、 AlloyTeam、腾讯CDC等多个部门、团队和项目。

功能清单

极小的文件大小

简洁的API设计

优秀的性能

丰富的手势支持

双版本(react和独立版)

支持pinch缩放

支持rotate旋转

支持pressMove拖拽

支持doubleTap双击

支持swipe滑动

支持longTap长按

支持tap按

支持singleTap单击

快速上手

独立版使用方式:

//element为需要监听手势的dom对象
new AlloyFinger(element, {
    pointStart: function () {
        //手指触摸屏幕触发
    },
    multipointStart: function () {
        //一个手指以上触摸屏幕触发
    },
    rotate: function (evt) {
        //evt.angle代表两个手指旋转的角度
        console.log(evt.angle);
    },
    pinch: function (evt) {
        //evt.scale代表两个手指缩放的比例
        console.log(evt.scale);
    },
    multipointEnd: function () {
        //当手指离开,屏幕只剩一个手指或零个手指触发
    },
    pressMove: function (evt) {
        //evt.deltaX和evt.deltaY代表在屏幕上移动的距离
        console.log(evt.deltaX);
        console.log(evt.deltaY);
    },
    tap: function (evt) {
        //点按触发
    },
    doubleTap: function (evt) {
        //双击屏幕触发
    },
    longTap: function (evt) {
        //长按屏幕750ms触发
    },
    swipe: function (evt) {
        //evt.direction代表滑动的方向
        console.log("swipe" + evt.direction);
    },
    singleTap: function (evt) {
        //单击
    }
});

官网DEMO

http://alloyteam.github.io/AlloyFinger/

1.必须跟transformjs一起用吗?

不必须。也可以在事件回调里根据evt携带的信息使用js去操作CSS3。但是一起用,会让代码更简洁。

2.pinch、rotate事件怎么在chrome浏览器调试的?

一般用真机调试,但是也可以使用chrome浏览器,传送门 http://www.html5rocks.com/en/mobile/touch/#toc-touchdev

3.缩放的origin点设置,这里是想手在图片哪个区域操作就设置哪里为origin进行缩放?

自己去计算就是两个手指的连线的中点的坐标,

比如中点X:

  pinch: function (evt) { 
        console.log((evt.touch[0].pageX+evt.touch[1].pageX)/2);
    },

 

然后根据这个坐标和图片的坐标计算图片缩放的origin

4.拖拽位置、缩放大小是否可以限制(始终在屏幕内显示,避免出现缩到很小看不到的情况)

这个不应该有 AlloyFinger 控制。而应该由你的逻辑去控制

https://github.com/AlloyTeam/AlloyFinger

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>AlloyFinger</title>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <link rel="stylesheet" href="style/reset.css">
    <link rel="stylesheet" href="style/main.css">
    <script type="text/javascript" src="script/jquery-1.9.1.min.js"></script>
    <style>
    html, body{width:100%;height:100%;}
    .view_page{width:100%;height:100%;max-width:640px;position:relative;margin:0 auto;}
    .small_map_box{width:100%;}
    .small_map_box img{width:100%;display:block;}
    .big_map_box{position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(0, 0, 0, 1);max-width:640px;z-index:100;display:none;
        -webkit-transform-origin:50% 20%;transform-origin:50% 20%;}
    .big_map_box.active{
        -webkit-animation:globalSca 0.4s ease both;
        -moz-animation:globalSca 0.4s ease both;
        -ms-animation:globalSca 0.4s ease both;
        animation:globalSca 0.4s ease both;
    }
    @-webkit-keyframes globalSca{
        0%{-webkit-transform:scale(0);background:rgba(0, 0, 0, 0);}
        100%{-webkit-transform:scale(1);background:rgba(0, 0, 0, 1);}
    }
    @-moz-keyframes globalSca{
        0%{-moz-transform:scale(0);background:rgba(0, 0, 0, 0);}
        100%{-moz-transform:scale(1);background:rgba(0, 0, 0, 1);}
    }
    @-ms-keyframes globalSca{
        0%{-ms-transform:scale(0);background:rgba(0, 0, 0, 0);}
        100%{-ms-transform:scale(1);background:rgba(0, 0, 0, 1);}
    }
    @keyframes globalSca{
        0%{transform:scale(0);background:rgba(0, 0, 0, 0);}
        100%{transform:scale(1);background:rgba(0, 0, 0, 1);}
    }
    .big_map_box.active2{
        -webkit-animation:globalScatoZero 0.4s ease both;
        -moz-animation:globalScatoZero 0.4s ease both;
        -ms-animation:globalScatoZero 0.4s ease both;
        animation:globalScatoZero 0.4s ease both;
    }
    @-webkit-keyframes globalScatoZero{
        0%{-webkit-transform:scale(1)}
        100%{-webkit-transform:scale(1);opacity:0;}
    }
    @-moz-keyframes globalScatoZero{
        0%{-moz-transform:scale(1)}
        100%{-moz-transform:scale(1);opacity:0;}
    }
    @-ms-keyframes globalScatoZero{
        0%{-ms-transform:scale(1)}
        100%{-ms-transform:scale(1);opacity:0;}
    }
    @keyframes globalScatoZero{
        0%{transform:scale(1)}
        100%{transform:scale(1);opacity:0;}
    }
    /*@-webkit-keyframes mymove{
        0%   {-webkit-transform:scale(0);}
        100%   {-webkit-transform:scale(1);}
    }

    @keyframes mymove{
        0%   {transform:scale(0);}
        100%   {transform:scale(1);}
    }*/

    .big_map_box img{position:absolute;width:100%;left:0;top:50%;}
    #result{position:absolute;left:0;top:0;color:#fff;}
    </style>
</head>
<body>
    <div class="view_page">
        <div class="small_map_box" id="small_map_box">
            <img src="images/map_small.jpg" class="small_map" id="small_map" alt="">
        </div>
        <div class="big_map_box">
            <div id="result">fewfew</div>
            <img src="images/map_big.jpg" class="big_map" id="big_map" alt="">
        </div> 
    </div>
</body>
</html>
<script type="text/javascript" src="AlloyFinger-master/alloy_finger.js"></script>
<script type="text/javascript" src="AlloyFinger-master/asset/transform.js"></script>
<!-- <script type="text/javascript" src="AlloyFinger-master/asset/image_loaded.js"></script> -->
<script type="text/javascript" src="AlloyFinger-master/asset/to.js"></script>
<script type="text/javascript">
!(function(){
    var winW = window.innerWidth;
    var smallmap = document.getElementById("small_map_box");
    var bigmap = document.getElementById("big_map");
    smallmap.addEventListener("touchstart", function(){
        smallmap.addEventListener("touchend", touchEnd, false);
    }, false);

    smallmap.addEventListener("touchmove", function(){
        smallmap.removeEventListener("touchend", touchEnd, false);
    }, false);

    smallmap.addEventListener("touchend", touchEnd, false);

    function touchEnd(){
        $(".big_map_box").css({"display": "block"}).removeClass("active2").addClass("active");
        bigmap.style.marginTop = -Math.round((winW * 1.0533333333))/ 2 + "px";
        bigmap.style.transform = "perspective(500px) matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)";
        bigmap.style.webkitTransform = "perspective(500px) matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)";
    }
    Transform(bigmap);
    var initScale = 1;
    var handlerMap = new AlloyFinger(bigmap, {
        //一个手指以上触摸屏幕触发
        multipointStart: function () {
            initScale = this.scaleX;
        },

        //当手指离开,屏幕只剩一个手指或零个手指触发
        multipointEnd: function (evt) {
            // bigmap.onclick = function(){
            //     $(".big_map_box").removeClass("active");
            // }

            // 缩放小于1的动画
            if(this.scaleX < 1){
                new To(this, "scaleX", 1, 300);         // 绽放归位
                new To(this, "scaleY", 1, 300);         // 绽放归位
                new To(this, "translateX", 0, 300);     // 位移归位
                new To(this, "translateY", 0, 300);     // 位移归位
                new To(this, "rotateZ", 0, 300);        // 旋转归位
                // 自己写的动画
                // var that = this;
                // this.scaleX = this.scaleY = 1;
                // this.translateX = 0;
                // this.translateY = 0;
                // this.style.transition = "all 0.3s";
                // setTimeout(function(){
                //     this.style.transition = "0ms";
                // }.bind(this), 300);
            }
            // 限制最大的尺寸
            if(this.scaleX > 3){
                // this.scaleX = this.scaleY = 3;
                new To(this, "scaleX", 3, 200);         // 绽放归位
                new To(this, "scaleY", 3, 200);         // 绽放归位
            }
        },

        // 旋转
        // rotate: function (evt) {
        //     evt.preventDefault();
        //     //evt.angle代表两个手指旋转的角度
        //     this.rotateZ += evt.angle;
        // },

        // 双指缩放
        pinch: function (evt) {
            handlerMap.isDoubleTap = true;
            this.scaleX = this.scaleY = initScale * evt.zoom;
            evt.preventDefault();

        },
        // 双击放大
        // doubleTap: function () {
        //     handlerMap.isDoubleTap = true;
        //     if(this.scaleX === 1){
        //         new To(this, "scaleX", 3, 300);
        //         new To(this, "scaleY", 3, 300);
        //     }else if(this.scaleX === 3){
        //         new To(this, "scaleX", 1, 300);
        //         new To(this, "scaleY", 1, 300);
        //         new To(this, "translateX", 0, 300);     // 位移归位
        //         new To(this, "translateY", 0, 300);     // 位移归位
        //     }
        //     /*else if(this.scaleX > 2){
        //         new To(this, "scaleX", 2, 300);
        //         new To(this, "scaleY", 2, 300);
        //     }*/
        // },
        singleTap: function (evt) {
            if(!handlerMap.isDoubleTap){
                $(".big_map_box").removeClass("active").addClass("active2");
                setTimeout(function(){
                    $(".big_map_box").css({"display":"none"});
                },400)
            }
        },

        // 移动
        pressMove: function (evt) {
            // 取消单击事件

            handlerMap.isDoubleTap = true;
            this.translateX += evt.deltaX;
            this.translateY += evt.deltaY;

            // 边界判断. 不让划出屏幕内
            if(this.scaleX === 1){
                if(this.translateX !== 0){
                    // this.scaleX = this.scaleY = 3;
                    new To(this, "translateX", 0, 200);         // 绽放归位
                }
                this.translateY = 0;
            }
            evt.preventDefault();
        }
    })    
  

}());

function classList(e){
    //CSSClassList是一个模拟DOMTokenList的javascript类
    function CSSClassList(e){        
        //系统偷偷替我们做了:
        //var this = new Object();
        this.e = e;
    }   

    //contains方法
    CSSClassList.prototype.contains = function(c){

        //权威指南的方法
        //检查c是否是合法的类名
        if(c.length === 0 || c.indexOf(" ") != -1){
            throw new Error("invalid class name:'" + c + "'");
        }
        //首先是常规检查
        var classes = this.e.className;
        if(!classes) return false;          //e不含有类名
        if(classes === c) return true;      //e有一个完全匹配的类名

        //否则,把c自身看做一个单词,利用正则表达式搜索c
        //\b是单词的边界
        return classes.search("\\b" + c + "\\b") != -1;


        //网上正则方法
        /*var classname = this.e.className, reg = new RegExp("\\b" + c + "\\b");
        return reg.test(classname);*/
        
    }

    //add()方法
    CSSClassList.prototype.add = function(c){
        if(this.contains(c)) return;            //如果存在,则不添加
        var classes = this.e.className;

        //判断存在class与class类里最后一个类名没有空白格
        if(classes && classes[classes.length-1] != " "){
            c = " " + c;        
            this.e.className += c;          //将c添加到className中
        }
    }

    //remove()方法
    CSSClassList.prototype.remove = function(c){
        //检查c是否是合法的类名
        if(c.length === 0 || c.indexOf(" ") != -1){
            throw new Error("invalid class name:'" + c + "'");
        }
        //将所有作为单词的c和多余的尾随空格全部删除
        var pattern = new RegExp("\\b" + c + "\\b\\s*","g");
        this.e.className = this.e.className.replace(pattern,"")
    }

    //toggle()方法,添加返回true,删除返回false
    CSSClassList.prototype.toggle = function(c){
        if(this.contains(c)){       //如果e.className包含c
            this.remove(c);         //删除它
            return false;
        }else{
            this.add(c);            //否则,添加它
            return true;
        }
    }

    //返回e.className本身
    CSSClassList.prototype.toString = function(){
        return this.e.className;
    };

    /*//返回在e.className中的类名 (CSSClassList原生中没有toArray方法)
    CSSClassList.prototype.toArray = function(){
        return this.e.className.match(/\b\w+\b/g) || {};
    }*/

    if(e.classList){
        return e.classList;             //如果classList存在,则返回它
    }else{
        return new CSSClassList(e);     //否则就创建一个
    }
}
</script>

  

有几个问题没有解决

1.IOS图片scale放大模糊问题

2.doubleTap与pinch触摸问题, 事件冲突

3.禁止双指放大doubleTap事件, 和在pinch上"handlerMap.isDoubleTap = true;" 来阻止singleTap事件区分开来

转载于:https://www.cnblogs.com/alantao/p/7867169.html

相关文章:

  • java中的字符串二
  • [转]Ubuntu安装rabbitMq
  • 如何下载中文语言包让Eclipse汉化?
  • 20171121_Python学习六周二次课(11月21日)
  • Git reset到某一次commit
  • 电商抢购并发
  • 二叉树与多叉树的遍历
  • 矩阵优化总结
  • CentOS源码安装Python3.6
  • js 判断各种数据类型 typeof 几种类型值
  • 如何下载最新版本和旧版本的eclipse?
  • LVS_DR 安装后无法转发真实服务器,但是配置其他方面都检查的没有问题了。就剩在realserver这边没有在lo口上绑定VIP了...
  • 各种排序算法思想复杂度及其java程序实现
  • 14章 变宽度网页布局剖析于制作
  • 实训之压缩软件
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 【前端学习】-粗谈选择器
  • 〔开发系列〕一次关于小程序开发的深度总结
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • create-react-app做的留言板
  • export和import的用法总结
  • iOS | NSProxy
  • js如何打印object对象
  • 模型微调
  • 前端面试总结(at, md)
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 什么是Javascript函数节流?
  • 王永庆:技术创新改变教育未来
  • 写代码的正确姿势
  • 自制字幕遮挡器
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (二)linux使用docker容器运行mysql
  • (南京观海微电子)——COF介绍
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)Linq学习笔记
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .gitignore
  • .NET 4.0中的泛型协变和反变
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET Standard 的管理策略
  • .Net 垃圾回收机制原理(二)
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .net反编译工具
  • .Net面试题4
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • .NET下的多线程编程—1-线程机制概述
  • @media screen 针对不同移动设备
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • @Service注解让spring找到你的Service bean
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [AIGC] 如何建立和优化你的工作流?