提交 892f9f9d authored 作者: 搞事情's avatar 搞事情

1、增加拖动翻页功能

上级 651caf63
import $ from 'jquery'; // turn.js - 翻页库
(function ($) {
'use strict';
var has3d, var has3d,
vendor = '', vendor = '',
...@@ -70,7 +72,7 @@ var has3d, ...@@ -70,7 +72,7 @@ var has3d,
// Size of the active zone of each corner // Size of the active zone of each corner
cornerSize: 200, cornerSize: 50,
// Enables gradients // Enables gradients
...@@ -82,7 +84,19 @@ var has3d, ...@@ -82,7 +84,19 @@ var has3d,
// Enables hardware acceleration // Enables hardware acceleration
acceleration: true acceleration: true,
// Enables non-corner area flipping
enableNonCorner: true,
// Maximum folding distance ratio for non-corner flipping (0.1 - 1.0)
maxFoldingDistance: 0.8,
// Minimum drag distance to trigger non-corner flip
minDragDistance: 30
}, },
// Number of pages in the DOM, minimum value: 6 // Number of pages in the DOM, minimum value: 6
...@@ -1229,6 +1243,128 @@ var has3d, ...@@ -1229,6 +1243,128 @@ var has3d,
}, },
// 检测非corner区域翻页
_nonCornerActivated: function (e) {
if (e.originalEvent === undefined) {
return false;
}
var data = this.data().f;
// 检查是否启用非corner翻页
if (!data.opts.enableNonCorner) {
return false;
}
e = (isTouch) ? e.originalEvent.touches : [e];
var pos = data.parent.offset(),
width = this.width(),
height = this.height(),
point = { x: Math.max(0, e[0].pageX - pos.left), y: Math.max(0, e[0].pageY - pos.top) },
csz = data.opts.cornerSize || 50,
allowedCorners = flipMethods._cAllowed.call(this),
turnData = data.opts.turn ? data.opts.turn.data() : null;
if (point.x <= 0 || point.y <= 0 || point.x >= width || point.y >= height) return false;
// 检查是否在corner区域(如果在corner区域,则不处理)
var inCorner = false;
if (point.y < csz) inCorner = true;
else if (point.y >= height - csz) inCorner = true;
if (inCorner && (point.x <= csz || point.x >= width - csz)) return false;
// 非corner区域翻页逻辑
var virtualCorner = flipMethods._calculateVirtualCorner.call(this, point, allowedCorners, turnData);
return virtualCorner;
},
// 改进的虚拟corner计算逻辑
_calculateVirtualCorner: function (point, allowedCorners, turnData) {
var width = this.width(),
height = this.height(),
data = this.data().f,
virtualCorner = null;
// 双页模式的改进逻辑
if (turnData && turnData.display === 'double') {
// 获取当前页面在双页视图中的位置
var currentView = turnData.view || [data.opts.page];
var isLeftPage = data.opts.page % 2 === 0;
// 改进的双页拖动检测:支持跨页拖动
var dragThreshold = width * 0.3; // 30%的区域作为拖动触发区
if (isLeftPage) {
// 左页:右侧30%区域可以向右翻页,左侧30%区域可以向左翻页
if (point.x > width - dragThreshold) {
// 右侧拖动区域,向右翻页
virtualCorner = (point.y < height / 2) ? 'tr' : 'br';
} else if (point.x < dragThreshold) {
// 左侧拖动区域,向左翻页
virtualCorner = (point.y < height / 2) ? 'tl' : 'bl';
}
} else {
// 右页:左侧30%区域可以向左翻页,右侧30%区域可以向右翻页
if (point.x < dragThreshold) {
// 左侧拖动区域,向左翻页
virtualCorner = (point.y < height / 2) ? 'tl' : 'bl';
} else if (point.x > width - dragThreshold) {
// 右侧拖动区域,向右翻页
virtualCorner = (point.y < height / 2) ? 'tr' : 'br';
}
}
} else {
// 单页模式:保持原有逻辑
var centerX = width / 2;
var centerY = height / 2;
if (point.x < centerX) {
// 左侧点击,向左翻页
virtualCorner = (point.y < centerY) ? 'tl' : 'bl';
} else {
// 右侧点击,向右翻页
virtualCorner = (point.y < centerY) ? 'tr' : 'br';
}
}
// 检查计算出的corner是否被允许
if (virtualCorner && $.inArray(virtualCorner, allowedCorners) !== -1) {
return {
x: point.x,
y: point.y,
corner: virtualCorner,
originalPoint: { x: point.x, y: point.y },
isVirtual: true,
// 添加拖动起始信息,用于改进拖动体验
dragStartX: point.x,
dragStartY: point.y
};
}
return false;
},
// 改进的虚拟corner映射
_mapVirtualToRealCorner: function (virtualPoint) {
if (!virtualPoint.isVirtual) return virtualPoint;
// 获取真实corner的位置
var realCorner = flipMethods._c.call(this, virtualPoint.corner);
return {
corner: virtualPoint.corner,
x: virtualPoint.x,
y: virtualPoint.y,
isVirtual: true,
originalPoint: virtualPoint.originalPoint,
realCorner: realCorner,
dragStartX: virtualPoint.dragStartX,
dragStartY: virtualPoint.dragStartY
};
},
_cornerActivated: function (e) { _cornerActivated: function (e) {
if (e.originalEvent === undefined) { if (e.originalEvent === undefined) {
return false; return false;
...@@ -1258,27 +1394,21 @@ var has3d, ...@@ -1258,27 +1394,21 @@ var has3d,
}, },
_c: function (corner, opts) { // 统一的区域激活检测函数
_areaActivated: function (e) {
opts = opts || 0; // 首先检测corner区域
return ({ var cornerResult = flipMethods._cornerActivated.call(this, e);
tl: point2D(opts, opts), if (cornerResult) {
tr: point2D(this.width() - opts, opts), return cornerResult;
bl: point2D(opts, this.height() - opts), }
br: point2D(this.width() - opts, this.height() - opts)
})[corner];
},
_c2: function (corner) {
return { // 如果不在corner区域,检测非corner区域
tl: point2D(this.width() * 2, 0), var nonCornerResult = flipMethods._nonCornerActivated.call(this, e);
tr: point2D(-this.width(), 0), if (nonCornerResult) {
bl: point2D(this.width() * 2, this.height()), return flipMethods._mapVirtualToRealCorner.call(this, nonCornerResult);
br: point2D(-this.width(), this.height()) }
}[corner];
return false;
}, },
_foldingPage: function (corner) { _foldingPage: function (corner) {
...@@ -1502,7 +1632,6 @@ var has3d, ...@@ -1502,7 +1632,6 @@ var has3d,
gradientOpacity = (far < width) ? far / width : 1; gradientOpacity = (far < width) ? far / width : 1;
if (data.opts.frontGradient) { if (data.opts.frontGradient) {
gradientStartV = gradientSize > 100 ? (gradientSize - 100) / gradientSize : 0; gradientStartV = gradientSize > 100 ? (gradientSize - 100) / gradientSize : 0;
...@@ -1783,7 +1912,7 @@ var has3d, ...@@ -1783,7 +1912,7 @@ var has3d,
var data = this.data().f; var data = this.data().f;
if (!data.disabled && !this.flip('isTurning')) { if (!data.disabled && !this.flip('isTurning')) {
data.corner = flipMethods._cornerActivated.call(this, e); data.corner = flipMethods._areaActivated.call(this, e);
if (data.corner && flipMethods._foldingPage.call(this, data.corner)) { if (data.corner && flipMethods._foldingPage.call(this, data.corner)) {
flipMethods._moveFoldingPage.call(this, true); flipMethods._moveFoldingPage.call(this, true);
this.trigger('pressed', [data.point]); this.trigger('pressed', [data.point]);
...@@ -1802,14 +1931,42 @@ var has3d, ...@@ -1802,14 +1931,42 @@ var has3d,
if (data.corner) { if (data.corner) {
var pos = data.parent.offset(); var pos = data.parent.offset();
var currentMouseX = e[0].pageX - pos.left;
var currentMouseY = e[0].pageY - pos.top;
// 检查是否是虚拟corner(非corner区域拖拽)
if (data.corner.isVirtual) {
// 计算拖动距离
var dragDistance = Math.sqrt(
Math.pow(currentMouseX - data.corner.dragStartX, 2) +
Math.pow(currentMouseY - data.corner.dragStartY, 2)
);
// 最小拖动距离阈值
var minDragDistance = data.opts.minDragDistance || 30;
if (dragDistance < minDragDistance) {
// 拖动距离太小,不执行翻页效果
return;
}
data.corner.x = e[0].pageX - pos.left; // 根据拖动轨迹计算真实的折叠点
data.corner.y = e[0].pageY - pos.top; var foldPoint = flipMethods._calculateNonCornerFoldPoint.call(this,
data.corner.corner, currentMouseX - data.corner.dragStartX, currentMouseY - data.corner.dragStartY,
dragDistance, data.corner.realCorner);
data.corner.x = foldPoint.x;
data.corner.y = foldPoint.y;
} else {
// 传统corner拖拽,直接使用鼠标位置
data.corner.x = currentMouseX;
data.corner.y = currentMouseY;
}
flipMethods._showFoldedPage.call(this, data.corner); flipMethods._showFoldedPage.call(this, data.corner);
} else if (!this.data().effect && this.is(':visible')) { // roll over } else if (!this.data().effect && this.is(':visible')) { // roll over
var corner = flipMethods._cornerActivated.call(this, e[0]); var corner = flipMethods._areaActivated.call(this, e[0]);
if (corner) { if (corner) {
var origin = flipMethods._c.call(this, corner.corner, data.opts.cornerSize / 2); var origin = flipMethods._c.call(this, corner.corner, data.opts.cornerSize / 2);
corner.x = origin.x; corner.x = origin.x;
...@@ -1822,6 +1979,144 @@ var has3d, ...@@ -1822,6 +1979,144 @@ var has3d,
} }
}, },
// 新增:根据拖动轨迹计算真实的折叠点
_calculateNonCornerFoldPoint: function (corner, dragDeltaX, dragDeltaY, dragDistance, realCorner) {
var data = this.data().f;
var width = this.width();
var height = this.height();
var maxFoldingDistance = data.opts.maxFoldingDistance || 0.6;
// 获取起点(拖动开始点)和终点(当前鼠标位置)
var startX = data.corner.dragStartX;
var startY = data.corner.dragStartY;
var endX = startX + dragDeltaX;
var endY = startY + dragDeltaY;
// 获取参考corner的位置
var referenceCorner = flipMethods._c.call(this, corner);
// 计算拖动向量
var dragVectorX = endX - startX;
var dragVectorY = endY - startY;
// 如果拖动距离太小,返回参考corner
if (Math.abs(dragVectorX) < 5 && Math.abs(dragVectorY) < 5) {
return {
x: referenceCorner.x,
y: referenceCorner.y
};
}
// 计算拖动线段的中点
var midX = (startX + endX) / 2;
var midY = (startY + endY) / 2;
// 计算从中点到参考corner的垂直向量
// 如果拖动向量是(dx, dy),那么垂直向量是(-dy, dx)或(dy, -dx)
var perpX = -dragVectorY;
var perpY = dragVectorX;
// 归一化垂直向量
var perpLength = Math.sqrt(perpX * perpX + perpY * perpY);
if (perpLength > 0) {
perpX = perpX / perpLength;
perpY = perpY / perpLength;
}
// 计算从中点到参考corner的向量
var toCornerX = referenceCorner.x - midX;
var toCornerY = referenceCorner.y - midY;
// 计算参考corner在垂直线上的投影点(折叠轴上的点)
var projectionOnPerp = toCornerX * perpX + toCornerY * perpY;
var axisPointX = midX + projectionOnPerp * perpX;
var axisPointY = midY + projectionOnPerp * perpY;
// 计算参考corner关于折叠轴的对称点
var symmetricX = 2 * axisPointX - referenceCorner.x;
var symmetricY = 2 * axisPointY - referenceCorner.y;
// 计算折叠强度(基于拖动距离)
var foldIntensity = Math.min(dragDistance / (Math.min(width, height) * 0.4), 1);
// 应用最大折叠距离限制
var maxDistance = Math.min(width, height) * maxFoldingDistance;
var symmetricDistance = Math.sqrt(
Math.pow(symmetricX - referenceCorner.x, 2) +
Math.pow(symmetricY - referenceCorner.y, 2)
);
var foldX, foldY;
if (symmetricDistance > maxDistance && symmetricDistance > 0) {
// 限制折叠距离
var scale = maxDistance / symmetricDistance;
foldX = referenceCorner.x + (symmetricX - referenceCorner.x) * scale * foldIntensity;
foldY = referenceCorner.y + (symmetricY - referenceCorner.y) * scale * foldIntensity;
} else {
// 应用折叠强度
foldX = referenceCorner.x + (symmetricX - referenceCorner.x) * foldIntensity;
foldY = referenceCorner.y + (symmetricY - referenceCorner.y) * foldIntensity;
}
// 根据corner类型应用边界限制(这很重要,确保_fold函数能正常工作)
switch (corner) {
case 'tl':
foldX = Math.max(foldX, 1);
foldY = Math.max(foldY, 1);
break;
case 'tr':
foldX = Math.min(foldX, width - 1);
foldY = Math.max(foldY, 1);
break;
case 'bl':
foldX = Math.max(foldX, 1);
foldY = Math.min(foldY, height - 1);
break;
case 'br':
foldX = Math.min(foldX, width - 1);
foldY = Math.min(foldY, height - 1);
break;
}
// 最终边界检查
foldX = Math.max(0, Math.min(width, foldX));
foldY = Math.max(0, Math.min(height, foldY));
return {
x: foldX,
y: foldY
};
},
disable: function (disable) {
flipMethods.setData.call(this, { 'disabled': disable });
return this;
},
_c: function (corner, opts) {
opts = opts || 0;
return ({
tl: point2D(opts, opts),
tr: point2D(this.width() - opts, opts),
bl: point2D(opts, this.height() - opts),
br: point2D(this.width() - opts, this.height() - opts)
})[corner];
},
_c2: function (corner) {
return {
tl: point2D(this.width() * 2, 0),
tr: point2D(-this.width(), 0),
bl: point2D(this.width() * 2, this.height()),
br: point2D(-this.width(), this.height())
}[corner];
},
_eventEnd: function () { _eventEnd: function () {
var data = this.data().f; var data = this.data().f;
...@@ -1835,13 +2130,6 @@ var has3d, ...@@ -1835,13 +2130,6 @@ var has3d,
data.corner = null; data.corner = null;
},
disable: function (disable) {
flipMethods.setData.call(this, { 'disabled': disable });
return this;
} }
}, },
...@@ -1855,7 +2143,7 @@ var has3d, ...@@ -1855,7 +2143,7 @@ var has3d,
throw args[0] + ' is an invalid value'; throw args[0] + ' is an invalid value';
}; };
$.extend($.fn, { $.extend($.fn, {
flip: function (req, opts) { flip: function (req, opts) {
return cla(this, flipMethods, arguments); return cla(this, flipMethods, arguments);
...@@ -1925,10 +2213,9 @@ $.extend($.fn, { ...@@ -1925,10 +2213,9 @@ $.extend($.fn, {
delete data['effect']; delete data['effect'];
} }
} }
}); });
$.isTouch = isTouch;
$.isTouch = isTouch;
export default $; })(jQuery);
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
<script setup> <script setup>
import $ from "jquery"; import $ from "jquery";
import turn from "@/assets/js/turn.js"; import "@/assets/js/turn.js"; // 直接导入执行,扩展 jQuery 对象
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from "vue"; import { ref, onMounted, onUnmounted, watch, nextTick, computed } from "vue";
import VueEasyLightbox from "vue-easy-lightbox"; import VueEasyLightbox from "vue-easy-lightbox";
import GuideMobile from "../GuideMobile/index.vue"; import GuideMobile from "../GuideMobile/index.vue";
...@@ -395,6 +395,12 @@ const initBook = async () => { ...@@ -395,6 +395,12 @@ const initBook = async () => {
height: pageHeight, height: pageHeight,
display: isMobile.value ? "single" : "double", display: isMobile.value ? "single" : "double",
acceleration: true, acceleration: true,
// 启用非corner区域翻页
enableNonCorner: true,
// 最大折叠距离比例 (0.1 - 1.0)
maxFoldingDistance: 0.6,
// 最小拖拽距离触发翻页
minDragDistance: 30,
gradients: true, gradients: true,
elevation: 80, elevation: 80,
duration: isMobile.value ? 200 : 600, duration: isMobile.value ? 200 : 600,
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论