h5移动端局部放大效果
首先添加zoom.js
(function (root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if (typeof define === 'function' && define.amd)
define([], factory);
else if (typeof exports === 'object')
exports["Zoom"] = factory();
else
root["Zoom"] = factory();
})(this, function () {
/**
* 简洁的元素缩放功能。
* @param {[type]} el 要缩放的元素
* @param {[type]} option {windth:元素宽度(必须),height:元素高度(必须),minScale:最小缩放比例,maxScale:最大缩放比例,top:原始位置,left:原始位置}
*/
function Zoom(el, option) {
if (!option || !option.width || !option.height) {
throw "dom的尺寸参数错误";
}
option = Object.assign({
minScale: 1,
maxScale: 3,
top: 0,
left: 0
}, option);
this.el = el;
this.lastSapce = 0;
this.touchState = 0;
this.lastPoint = null
this.targetPoint = null;
//放大缩小的倍数 当前缩放倍数
this.minScale = option.minScale || 1;
this.maxScale = option.maxScale || 10;
//dom的尺寸参数
this.width = option.width;
this.height = option.height;
this.top = option.top;
this.left = option.left;
this.scale = 1;
//初始位置 以及 初始宽高
this.originTop = option.top;
this.originLeft = option.left;
this.originW = this.width;
this.originH = this.height;
//图片中心点
this.centerX = this.left + this.originW / 2;
this.centerY = this.top + this.originH / 2;
this.el.style.position = 'absolute';
this.init();
return this;
}
Zoom.prototype.getTouches = function (event) {
let touches = event.touches;
if (!touches) {
touches = event.originalEvent.touches;
}
return touches;
}
Zoom.prototype.getTouchsDistance = function (t1, t2) {
let dx = parseInt(t1.pageX - t2.pageX);
let dy = parseInt(t1.pageY - t2.pageY);
let d = Math.pow((dx * dx + dy * dy), 0.5);
return d.toFixed(5);
}
Zoom.prototype.restView = function () {
this.el.style.width = this.width + 'px';
this.el.style.height = this.height + 'px';
this.el.style.top = this.top + 'px';
this.el.style.left = this.left + 'px';
}
Zoom.prototype.init = function () {
this.el.addEventListener('touchmove', this.touchmoveHandler);
this.el.addEventListener('touchstart', this.touchmoveHandler);
this.el.addEventListener('touchend', this.touchEndHandler);
this.el.addEventListener('touchcancel', this.touchEndHandler);
this.el.addEventListener('touchstart', this.dbclickHandler);
this.el.zoom = this;
}
Zoom.prototype.dbclickHandler = function (event) {
event.stopPropagation();
event.preventDefault();
let el = event.currentTarget;
let zoom = el.zoom;
let time = new Date(event.timeStamp).getTime();
let touchs = zoom.getTouches(event);
if (touchs.length == 1) {
if (!el.lastClickTime) {
el.lastClickTime = time;
} else {
if (time - el.lastClickTime < 300) {
el.lastClickTime = 0;
if (zoom.scale != 1) {
zoom.setScale(1);
} else if (zoom.scale == 1) {
zoom.setScale(2);
}
} else {
el.lastClickTime = time;
}
}
}
zoom.touchStartTime = new Date().getTime();
return false;
},
Zoom.prototype.drage = function (touch) {
if (this.lastPoint == null) {
this.lastPoint = {
x: touch.pageX,
y: touch.pageY,
}
} else {
let dx = parseInt(touch.pageX - this.lastPoint.x);
let dy = parseInt(touch.pageY - this.lastPoint.y);
this.lastPoint.x = touch.pageX;
this.lastPoint.y = touch.pageY;
this.left += dx;
this.top += dy;
this.setTransform(false);
}
}
Zoom.prototype.zoom = function (touchs) {
this.lastPoint = null;
let t1 = touchs[0];
let t2 = touchs[1];
let x1 = t1.pageX;
let x2 = t2.pageX;
let y1 = t1.pageY;
let y2 = t2.pageY;
let d = this.getTouchsDistance(t1, t2);
if (this.touchState == 0) {
this.lastSapce = d;
this.touchState = 1;
this.pointX = (x2 + (x1 - x2) / 2 - this.left) / this.scale;
this.pointY = (y2 + (y1 - y2) / 2 - this.top) / this.scale;
} else if (this.touchState == 1) {
let scaleChange = ((d / this.lastSapce) - 1) * 2;
let scale = this.scale + scaleChange / 2;
this.setScale(scale, this.pointX, this.pointY);
this.lastSapce = d;
}
}
Zoom.prototype.touchmoveHandler = function (event) {
event.stopPropagation();
event.preventDefault();
let el = event.currentTarget;
let zoom = el.zoom;
let touchs = zoom.getTouches(event);
if (touchs.length == 1) {
zoom.drage(touchs[0]);//拖动处理
} else if (touchs.length >= 2) {
zoom.lastPoint = null;//终止拖动事件
zoom.zoom(touchs);//缩放处理
}
return false;
}
Zoom.prototype.touchEndHandler = function (event) {
let zoom = event.currentTarget.zoom;
zoom.touchState = 0;
zoom.lastPoint = null;
zoom.lastSapce = 0;
let minSpace = 20;
let parentWidth = zoom.el.parentElement.offsetWidth;
let parentHight = zoom.el.parentElement.offsetHeight;
let scale = zoom.scale;
if (scale < zoom.minScale) {
scale = zoom.minScale;
}
if (scale > zoom.maxScale) {
scale = zoom.maxScale;
}
if (scale != zoom.scale) {
zoom.preSetScale(scale, zoom.lastPointX, zoom.lastPointY);
}
if ((zoom.left + zoom.width) < minSpace) {
zoom.left = - zoom.width + minSpace;
}
if (zoom.left >= (parentWidth - minSpace)) {
zoom.left = parentWidth - minSpace;
}
if ((zoom.top + zoom.height) < minSpace) {
zoom.top = - zoom.height + minSpace;
}
if (zoom.top >= (parentHight - minSpace)) {
zoom.top = parentHight - minSpace;
}
zoom.setTransform(true);
return;
}
Zoom.prototype.setTransform = function (needAnimation, originX, originY) {
let distanceX = this.left - this.originLeft;
let distanceY = this.top - this.originTop;
let scale = this.scale;
originX = originX == undefined ? (this.originTop + 'px') : originX;
originY = originY == undefined ? (this.originLeft + 'px') : originY;
this.el.style.transformOrigin = 'left top';
this.el.style.transform = 'matrix(' + scale + ',0,0,' + scale + ',' + distanceX + ',' + distanceY + ')';
if (needAnimation == true) {
this.el.style.transition = 'all .3s ease-in-out 0s'
} else {
this.el.style.transition = ''
}
}
Zoom.prototype.destroy = function () {
this.el.removeEventListener('touchmove', this.touchmoveHandler);
this.el.removeEventListener('touchstart', this.touchmoveHandler);
this.el.removeEventListener('touchend', this.touchEndHandler);
this.el.removeEventListener('touchcancel', this.touchEndHandler);
this.el.zoom = null;
}
//初始化放大倍数
Zoom.prototype.setScale = function (scale, pointX, pointY) {
this.preSetScale(scale, pointX, pointY);
this.setTransform(false);
}
Zoom.prototype.preSetScale = function (scale, pointX, pointY) {
if (scale < 0.1) {
scale = 0.1;
}
if (pointX == undefined) {
this.left = this.centerX - this.originW / 2 - this.originW / 2 * (scale - 1);
this.top = this.centerY - this.originH / 2 - this.originH / 2 * (scale - 1);
this.width = scale * this.originW;
this.height = scale * this.originH;
this.scale = scale;
} else {
this.width = scale * this.originW;
this.height = scale * this.originH;
this.left = this.left - pointX * (scale - this.scale);
this.top = this.top - pointY * (scale - this.scale);
this.lastPointX = pointX;
this.lastPointY = pointY;
this.scale = scale;
}
}
return Zoom;
});
下面是参考模板
<style>
#paper {
width: 100%;
height: 3100px;
overflow: hidden;
position: relative; /*重点*/
}
#detailBody {
position: absolute; /*重点*/
width: 100%;
height: 100%;
left: 0px;
top: 0px;
}
</style>
<script type="text/javascript">
$(function () {
var zoomEl = document.getElementById('detailBody');
var zoom = new Zoom(zoomEl, { 'top': 0, 'left': 0, 'width': $("#detailBody").width(), 'height': $("#detailBody").height() });
zoom.setScale(1);
});
</script>
<div id="paper" style="margin-top: 30px;">
<div class="layui-card-body" style="padding: 10px;" id="detailBody">
</div>
</div>
h5移动端局部放大效果的更多相关文章
- 基于SwiperJs的H5/移动端下拉刷新上拉加载更多的效果
最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...
- 10天学会phpWeChat——第七天:创建一个自适应PC网站+H5移动端的模块
本教程基于phpWeChat核心框架1.1.0+版本.下载地址:http://s.phpwechat.com/app_38026ed22fc1a91d92b5d2ef93540f20 通过前面六讲的系 ...
- H5移动端知识点总结
H5移动端知识点总结 阅读目录 移动开发基本知识点 calc基本用法 box-sizing的理解及使用 理解display:box的布局 理解flex布局 Flex布局兼容知识点总结 回到顶部 移动开 ...
- 基于SwiperJs的H5/移动端下拉刷新上拉加载更多
最早时,公司的H5项目中曾用过点击一个"加载更多"的DOM元素来实现分页的功能,后来又用过网上有人写的一个上拉加载更多的插件,那个插件是页面将要滚动到底部时就自动请求数据并插入到页 ...
- H5移动端手势密码组件
项目简介 最近参加了2017年360前端星计划,完成了一个有趣的UI组件开发大作业,借机和大家分享一下移动端开发的技术啦~~ 本项目采用原生JS和Canvas实现移动端手势密码组件,支持手势密码设置和 ...
- 玩转 H5 下拉上滑动效果
在APP中我们经常会在页面下拉时看到一些动效,例如下拉图片跟随放大.下拉刷新出现loading动画等,这个交互细节在各个主流APP以及手机原生系统中随处可见,能为APP增添个性亮点. 一.背景 在我们 ...
- 旅行app(游记、攻略、私人定制) | 顺便游旅行H5移动端实例
<顺便游旅行>是一款H5移动端旅行app,提供目的地(国内.国外.周边)搜索.旅游攻略查询.游记分享.私人定制4大模块,类似携程.同程.去哪儿.马蜂窝移动端,只不过顺便游app界面更为简洁 ...
- H5移动端项目案例、web手机微商城实战开发
自微信生态圈一步步强大后,关于移动端购物的趋势,逐渐成为大众关心的内容,目前市场上关于移动商城的制定就有大量版本,比如.微商城.移动商城.移动webAPP.微信商城各等各种定义层出不穷,这就对于移动端 ...
- js实现图片局部放大效果
图片局部放大效果结合的知识点主要是DOM的操作,以及事件的应用,所以首先要对DOM的操作有一定了解,其次能对事件的应用有一定的累积. 如上图,可以看到,这是放大镜的基本效果,主要分成左右两个部分.左边 ...
随机推荐
- SSD接口详解,再也不会买错固态硬盘了
http://stor.51cto.com/art/201808/582349.htm 硬盘知识科普中,我们提到了SSD的发展史虽短,但是种类和协议比HDD不知道多到哪里去了.因此,本期小编就通过接口 ...
- sql的分页
public static string GetPageSql(string sql, int start, int end) { return string.Fo ...
- 学习.net的步骤
第一步 学习HTML与CSS 这并不需要去学一大堆的诸如Dreamweaver,Firework之类的各种网页设计工具,关键是理解HTML网页嵌套的block结构与CSS的box模型.许多ASP.NE ...
- [CSP-S模拟测试]:蛋糕(区间DP)
题目传送门(内部题34) 输入格式 第一行,一个正整数$n$.第二行,$n$个正整数$a_i$,保证$a_i$互不相等. 输出格式 一行一个整数表示间宫卓司得到的蛋糕大小总和的最大值. 样例 样例输入 ...
- Java方式bean的注入以及自动配置
Java配置 Java配置的本质上,就是使用一个Java类去代替xml配置,这种配置方式在目前最主流的Spring Boot中得到了广泛的使用.1.引入相关Spring相关依赖 2.创建Java配置类 ...
- Source Insight下载及注册码
下载地址:http://www.sourceinsight.com/down35.html 注册码: SI3US-205035-36448 SI3US-466908-65897 SI3US-36893 ...
- JSP 虚拟路径设置
编辑server.xml 在Host标签内加 :path为虚拟路径 docBase为绝对路径 <Context path="/icon" docBase="C ...
- Eclipse转idea改设置
1 自动导包:画圈的打钩,实现自动导包,去除无用包.导入的类名相同时需要自己手动导包-> alt+enter. 2:修改快捷键 左移光标,右移同理. 上移光标:下移同理 光标移至行首,行末为e ...
- mac下jmeter的安装
1.下载jmeter for jmeter 自行网络下载,也可以在我提供的网盘中下载 jmeter3.3链接:https://pan.baidu.com/s/1AVhZjKmN9s7AOxfyONeB ...
- Linux NIO 系列(03) 非阻塞式 IO
目录 一.非阻塞式 IO 附:非阻塞式 IO 编程 Linux NIO 系列(03) 非阻塞式 IO Netty 系列目录(https://www.cnblogs.com/binarylei/p/10 ...