first commit
This commit is contained in:
parent
66fdc587f3
commit
81c2b70d0c
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"env",
|
||||||
|
{
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stage-2"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"transform-runtime"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
.*
|
||||||
|
*.md
|
||||||
|
*.yml
|
||||||
|
build/
|
||||||
|
node_modules/
|
||||||
|
src/
|
||||||
|
test/
|
||||||
|
gulpfile.js
|
|
@ -0,0 +1,41 @@
|
||||||
|
# vue-flip-page
|
||||||
|
vue翻页组件
|
||||||
|
|
||||||
|
方法
|
||||||
|
change (改变页面)
|
||||||
|
tap (点击)
|
||||||
|
turning (正在翻页)
|
||||||
|
prev (前一页)
|
||||||
|
next (后一页)
|
||||||
|
翻到指定页面:
|
||||||
|
|
||||||
|
handleSwitchManual(index) {
|
||||||
|
if (index === this.currentIndex) return;
|
||||||
|
this.$refs["turn"].toPage(index);
|
||||||
|
this.currentIndex = index;
|
||||||
|
this.goods_id = this.manuals[this.currentIndex].goods_id;
|
||||||
|
this.show = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
传入参数:
|
||||||
|
|
||||||
|
| 参数 | type | example | describe |
|
||||||
|
| ------ | ---- | -------- | ---------- |
|
||||||
|
| width | number | 375 | 宽度 |
|
||||||
|
| height | number | 667 | 高度 |
|
||||||
|
| data | Array | [ { "picture_image": "https://dev8.yunzmall.com/static/upload/image/8a2b418254cf521ff3e668fa33ac07ee.png", }, { "picture_image": "https://dev8.yunzmall.com/static/upload/image/e7cf7880531ff9cbb91902630c808359.png", }] |传入的数据 |
|
||||||
|
|
||||||
|
|
||||||
|
npm包 npm install vue-calendar-l
|
||||||
|
|
||||||
|
在需要用到的页面中(注意 一个页面目前只能引入一次)
|
||||||
|
|
||||||
|
import flipPage from "vue-flip-page";
|
||||||
|
|
||||||
|
components: { flipPage }
|
||||||
|
|
||||||
|
例子:
|
||||||
|
|
||||||
|
|
||||||
|
效果:
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "vue-flip-page",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "vue翻页效果插件",
|
||||||
|
"main": "dist/flip.min.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"start": "webpack-dev-server --hot --inline",
|
||||||
|
"build": "webpack --display-error-details --config webpack.config.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/harrietjia/vue-flip-page.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue",
|
||||||
|
"flip-page",
|
||||||
|
"vue-flip-page"
|
||||||
|
],
|
||||||
|
"author": "harrietjia",
|
||||||
|
"Email": "1317499207@qq.com",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/harrietjia/vue-flip-page/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/harrietjia/vue-flip-page#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.26.0",
|
||||||
|
"babel-loader": "^7.1.2",
|
||||||
|
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||||
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
|
"babel-preset-es2015": "^6.24.1",
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
|
"es6-promise": "^4.1.1",
|
||||||
|
"node-sass": "^4.11.0",
|
||||||
|
"sass-loader": "^6.0.7",
|
||||||
|
"style-loader": "^0.19.0",
|
||||||
|
"url-loader": "^0.6.2",
|
||||||
|
"vue": "^2.5.9",
|
||||||
|
"vue-hot-reload-api": "^2.2.4",
|
||||||
|
"vue-html-loader": "^1.2.4",
|
||||||
|
"vue-loader": "^13.5.0",
|
||||||
|
"vue-router": "^3.0.1",
|
||||||
|
"vue-style-loader": "^3.0.3",
|
||||||
|
"vue-template-compiler": "^2.5.9",
|
||||||
|
"vuex": "^3.0.1",
|
||||||
|
"webpack": "^3.9.1",
|
||||||
|
"webpack-dev-server": "^2.9.5"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
<template>
|
||||||
|
<div class="turn" ref="turn" :style="{width: width+'px', height: height+'px'}">
|
||||||
|
<template v-for="(item,index) in data">
|
||||||
|
<turn-page v-if="index == backPage || index == turnPage" :index="index" :width="width" :item="item" :height="height" :length="data.length"
|
||||||
|
:active="index == turnPage && turnActive" :styles="index === turnPage ? styles : defaultStyles">
|
||||||
|
</turn-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="turn-right-border" :style="{width: (((Math.min(data.length, 10) / data.length * (data.length - backPage))) + 'px')}"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import turn_controller from "./turn_controller";
|
||||||
|
|
||||||
|
export default turn_controller;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
|
.turn {
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
-webkit-box-shadow: 0 0 0.06rem 0 rgba(0, 0, 0, 0.60);
|
||||||
|
box-shadow: 0 0 0.06rem 0 rgba(0, 0, 0, 0.60);
|
||||||
|
-webkit-transition: all ease 0.35s;
|
||||||
|
transition: all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-item {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
-webkit-transition: all ease 0.35s;
|
||||||
|
transition: all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page.loading {
|
||||||
|
background: url(/article-h5/static/img/loading.95eeac7.gif) no-repeat center center !important;
|
||||||
|
background-size: 60px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo {
|
||||||
|
position: relative;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transition: opacity ease 0.2s;
|
||||||
|
transition: opacity ease 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page.loading .page-photo {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.2)), color-stop(6%, rgba(255, 255, 255, 0.15)), to(rgba(255, 255, 255, 0.15)));
|
||||||
|
background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.2) 0%, rgba(255, 255, 255, 0.15) 6%, rgba(255, 255, 255, 0.15) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo img {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-right-border {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 99;;
|
||||||
|
-webkit-transform: translate(100%);;
|
||||||
|
transform: translate(100%);
|
||||||
|
width: 10px;
|
||||||
|
-webkit-perspective: 500px;
|
||||||
|
perspective: 500px;
|
||||||
|
-webkit-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-right-border::after {
|
||||||
|
position: relative;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff url(/article-h5/static/img/book-border.3ca9453.png) repeat-y center center;
|
||||||
|
-webkit-transform: rotateY(35deg);
|
||||||
|
transform: rotateY(35deg);
|
||||||
|
-webkit-transform-origin: left center;
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preload {
|
||||||
|
position: fixed;
|
||||||
|
z-index: -999;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0.96rem;
|
||||||
|
padding: 0.46rem 0.14rem 0;
|
||||||
|
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.92)), to(rgba(0, 0, 0, 0.00)));
|
||||||
|
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.92) 0%, rgba(0, 0, 0, 0.00) 100%);
|
||||||
|
pointer-events: none;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content-type-1 {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content-type-2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .desc {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
width: calc(65% - 0.14rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .name {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 0.16rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .price {
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .buy-button {
|
||||||
|
width: 35%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .buy-button button {
|
||||||
|
display: inline-block;
|
||||||
|
height: 0.34rem;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: none;
|
||||||
|
padding: 0 0.16rem;
|
||||||
|
background: #FF8D00;
|
||||||
|
-webkit-box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
border-radius: 0.02rem;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .form-button {
|
||||||
|
height: 0.34rem;
|
||||||
|
border: none;
|
||||||
|
padding: 0 0.16rem;
|
||||||
|
background: #FFFFFF;
|
||||||
|
-webkit-box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
border-radius: 0.02rem;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: #0084BF;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,2 @@
|
||||||
|
import flipPage from './App.vue'
|
||||||
|
export default flipPage;
|
|
@ -0,0 +1,708 @@
|
||||||
|
import TurnPage from "./turn_page.vue";
|
||||||
|
|
||||||
|
const PI = Math.PI;
|
||||||
|
const A90 = PI / 2;
|
||||||
|
|
||||||
|
function bezier(p1, p2, p3, p4, t) {
|
||||||
|
const a = 1 - t;
|
||||||
|
const b = a * a * a;
|
||||||
|
const c = t * t * t;
|
||||||
|
return point2D(Math.round(b * p1.x + 3 * t * a * a * p2.x + 3 * t * t * a * p3.x + c * p4.x), Math.round(b * p1.y + 3 * t * a * a * p2.y + 3 * t * t * a * p3.y + c * p4.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
function point2D(x, y) {
|
||||||
|
return { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
function peelingPoint(a, b, c) {
|
||||||
|
return {
|
||||||
|
corner: a,
|
||||||
|
x: b,
|
||||||
|
y: c
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _startPoint(corner, width, height, opts) {
|
||||||
|
opts = opts || 0;
|
||||||
|
|
||||||
|
switch (corner) {
|
||||||
|
case "tl":
|
||||||
|
return point2D(opts, opts);
|
||||||
|
case "tr":
|
||||||
|
return point2D(width - opts, opts);
|
||||||
|
case "bl":
|
||||||
|
return point2D(opts, height - opts);
|
||||||
|
case "br":
|
||||||
|
return point2D(width - opts, height - opts);
|
||||||
|
case "l":
|
||||||
|
return point2D(opts, 0);
|
||||||
|
case "r":
|
||||||
|
return point2D(width - opts, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _endPoint(corner, width, height) {
|
||||||
|
switch (corner) {
|
||||||
|
case "tl":
|
||||||
|
return point2D(width * 2, 0);
|
||||||
|
case "tr":
|
||||||
|
return point2D(-width, 0);
|
||||||
|
case "bl":
|
||||||
|
return point2D(width * 2, height);
|
||||||
|
case "br":
|
||||||
|
return point2D(-width, height);
|
||||||
|
case "l":
|
||||||
|
return point2D(width * 2, 0);
|
||||||
|
case "r":
|
||||||
|
return point2D(-width, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _translate(x, y) {
|
||||||
|
return " translate3d(" + x + "px," + y + "px, 0px) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
function _rotate(degrees) {
|
||||||
|
return " rotate(" + degrees + "deg) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
function _scale(a, b) {
|
||||||
|
return " scale3d(" + a + "," + b + ", 1) ";
|
||||||
|
}
|
||||||
|
|
||||||
|
function _deg(radians) {
|
||||||
|
return radians / PI * 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _transform(transform, origin) {
|
||||||
|
const properties = {};
|
||||||
|
|
||||||
|
if (origin) properties["transform-origin"] = origin;
|
||||||
|
|
||||||
|
properties["transform"] = transform;
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fold(point, width, height, startPoint) {
|
||||||
|
let c, d, e, px, gradientSize, h, far, j, k, l, m, n, q;
|
||||||
|
let w = 0;
|
||||||
|
let mv = point2D(0, 0);
|
||||||
|
let df = point2D(0, 0);
|
||||||
|
let tr = point2D(0, 0);
|
||||||
|
const B = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2), 2);
|
||||||
|
const compute = function() {
|
||||||
|
c = _startPoint(point.corner, width, height);
|
||||||
|
const k = width - c.x - point.x;
|
||||||
|
const l = c.y - point.y;
|
||||||
|
let alpha = Math.atan2(l, k);
|
||||||
|
let distance = Math.sqrt(k * k + l * l);
|
||||||
|
const q = point2D(width - c.x - Math.cos(alpha) * width, c.y - Math.sin(alpha) * width);
|
||||||
|
if (distance > width) {
|
||||||
|
point.x = q.x;
|
||||||
|
point.y = q.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rel = point2D(0, 0);
|
||||||
|
const middle = point2D(0, 0);
|
||||||
|
|
||||||
|
rel.x = c.x ? c.x - point.x : point.x;
|
||||||
|
rel.y = c.y ? c.y - point.y : point.y;
|
||||||
|
|
||||||
|
middle.x = e ? width - rel.x / 2 : point.x + rel.x / 2;
|
||||||
|
middle.y = rel.y / 2;
|
||||||
|
|
||||||
|
alpha = A90 - Math.atan2(rel.y, rel.x);
|
||||||
|
const gamma = alpha - Math.atan2(middle.y, middle.x);
|
||||||
|
distance = Math.sin(gamma) * Math.sqrt(middle.x * middle.x + middle.y * middle.y);
|
||||||
|
|
||||||
|
tr = point2D(distance * Math.sin(alpha), distance * Math.cos(alpha));
|
||||||
|
|
||||||
|
if (alpha > A90) {
|
||||||
|
tr.x = tr.x + Math.abs(tr.y * rel.y / rel.x);
|
||||||
|
tr.y = 0;
|
||||||
|
if (Math.round(tr.x * Math.tan(PI - alpha)) < height) {
|
||||||
|
point.y = Math.sqrt(Math.pow(height, 2) + 2 * middle.x * rel.x);
|
||||||
|
if (d) point.y = height - point.y;
|
||||||
|
return compute();
|
||||||
|
}
|
||||||
|
const D = PI - alpha;
|
||||||
|
const E = B - height / Math.sin(D);
|
||||||
|
mv = point2D(Math.round(E * Math.cos(D)), Math.round(E * Math.sin(D)));
|
||||||
|
if (e) mv.x = -mv.x;
|
||||||
|
if (d) mv.y = -mv.y;
|
||||||
|
}
|
||||||
|
w = Math.round(100 * _deg(alpha)) / 100;
|
||||||
|
px = Math.round(tr.y / Math.tan(alpha) + tr.x);
|
||||||
|
const side = width - px;
|
||||||
|
let G = Math.min(height, side * Math.tan(alpha));
|
||||||
|
if (G < 0) G = height;
|
||||||
|
const sideX = side * Math.cos(2 * alpha);
|
||||||
|
const sideY = side * Math.sin(2 * alpha);
|
||||||
|
df = point2D(Math.round(e ? side - sideX : px + sideX), Math.round(d ? sideY : height - sideY));
|
||||||
|
const endingPoint = _endPoint(point.corner, width, height);
|
||||||
|
far = Math.sqrt(Math.pow(endingPoint.x - point.x, 2) + Math.pow(endingPoint.y - point.y, 2)) / width;
|
||||||
|
gradientSize = Math.min(100, side * Math.sin(alpha));
|
||||||
|
h = 1.3 * Math.min(side, G);
|
||||||
|
tr.x = Math.round(tr.x);
|
||||||
|
tr.y = Math.round(tr.y);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
const transform = function(tr, c, x, a) {
|
||||||
|
const l = ["0", "auto"];
|
||||||
|
const mvW = (width - B) * x[0] / 100;
|
||||||
|
const mvH = (height - B) * x[1] / 100;
|
||||||
|
const cssA = {
|
||||||
|
left: l[c[0]],
|
||||||
|
top: l[c[1]],
|
||||||
|
right: l[c[2]],
|
||||||
|
bottom: l[c[3]]
|
||||||
|
};
|
||||||
|
const aliasingFk = a !== 90 && a !== -90 ? e ? -1 : 1 : 0;
|
||||||
|
const origin = x[0] + "% " + x[1] + "%";
|
||||||
|
const styles = [];
|
||||||
|
|
||||||
|
styles.push({ ...cssA, ..._transform(_rotate(a) + _translate(tr.x + aliasingFk, tr.y), origin) });
|
||||||
|
styles.push({ ...cssA, ..._transform(_rotate(a) + _translate(tr.x + df.x - mv.x - width * x[0] / 100, tr.y + df.y - mv.y - height * x[1] / 100) + _rotate(Math.round(100 * (180 / a - 2) * a) / 100), origin) });
|
||||||
|
styles.push(_transform(_translate(-tr.x + mvW - aliasingFk, -tr.y + mvH) + _rotate(-a), origin));
|
||||||
|
styles.push(_transform(_translate(width - tr.x + mv.x + mvW, -tr.y + mv.y + mvH) + _rotate(-a), origin));
|
||||||
|
|
||||||
|
let z, C, D;
|
||||||
|
if (d) {
|
||||||
|
if (e) {
|
||||||
|
C = a - 90;
|
||||||
|
D = px - 50;
|
||||||
|
gradientSize = -gradientSize;
|
||||||
|
z = "50% 25%";
|
||||||
|
} else {
|
||||||
|
C = a - 270;
|
||||||
|
D = width - px - 50;
|
||||||
|
z = "50% 25%";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (e) {
|
||||||
|
D = px - 50;
|
||||||
|
C = a - 270;
|
||||||
|
gradientSize = -gradientSize;
|
||||||
|
z = "50% 75%";
|
||||||
|
} else {
|
||||||
|
D = width - px - 50;
|
||||||
|
C = a - 90;
|
||||||
|
z = "50% 75%";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let E = Math.max(0.5, 2 - far);
|
||||||
|
if (E > 1) E = E >= 1.7 ? (2 - E) / 0.3 : 1;
|
||||||
|
styles.push({ opacity: Math.round(100 * E) / 100, ..._transform(_translate(D, 0) + _rotate(C) + _scale(gradientSize / 100, 1), z) });
|
||||||
|
if (d) {
|
||||||
|
if (e) {
|
||||||
|
C = -270 - a;
|
||||||
|
h = -h;
|
||||||
|
D = width - px - 20;
|
||||||
|
z = "20% 25%";
|
||||||
|
} else {
|
||||||
|
C = -90 - a;
|
||||||
|
D = px - 20;
|
||||||
|
z = "20% 25%";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (e) {
|
||||||
|
C = -90 - a;
|
||||||
|
D = width - px - 20;
|
||||||
|
h = -h;
|
||||||
|
z = "20% 75%";
|
||||||
|
} else {
|
||||||
|
C = 90 - a;
|
||||||
|
D = px - 20;
|
||||||
|
z = "20% 75%";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
E = far < 0.3 ? far / 0.3 : 1;
|
||||||
|
styles.push({ opacity: Math.round(100 * E) / 100, ..._transform(_translate(D, 0) + _rotate(C) + _scale(-h / 100, 1), z) });
|
||||||
|
return styles;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (point.corner) {
|
||||||
|
case "l":
|
||||||
|
m = point.y - startPoint.y;
|
||||||
|
n = point.x;
|
||||||
|
q = Math.atan2(m, n);
|
||||||
|
if (q > 0) {
|
||||||
|
j = startPoint.y;
|
||||||
|
k = Math.sqrt(n * n + m * m);
|
||||||
|
l = 2 * j * Math.sin(q) + k;
|
||||||
|
point.x = l * Math.cos(q);
|
||||||
|
point.y = l * Math.sin(q);
|
||||||
|
point.corner = "tl";
|
||||||
|
e = true;
|
||||||
|
d = true;
|
||||||
|
compute();
|
||||||
|
return transform(tr, [1, 0, 0, 1], [100, 0], w);
|
||||||
|
} else {
|
||||||
|
q = -q;
|
||||||
|
j = height - startPoint.y;
|
||||||
|
k = Math.sqrt(n * n + m * m);
|
||||||
|
l = 2 * j * Math.cos(A90 - q) + k;
|
||||||
|
point.x = l * Math.cos(q);
|
||||||
|
point.y = height - l * Math.sin(q);
|
||||||
|
point.corner = "bl";
|
||||||
|
e = true;
|
||||||
|
compute();
|
||||||
|
return transform(point2D(tr.x, -tr.y), [1, 1, 0, 0], [100, 100], -w);
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
m = startPoint.y - point.y;
|
||||||
|
n = width - point.x;
|
||||||
|
q = Math.atan2(m, n);
|
||||||
|
if (q < 0) {
|
||||||
|
j = startPoint.y;
|
||||||
|
q = -q;
|
||||||
|
k = Math.sqrt(n * n + m * m);
|
||||||
|
l = 2 * j * Math.sin(q) + k;
|
||||||
|
point.x = width - l * Math.cos(q);
|
||||||
|
point.y = l * Math.sin(q);
|
||||||
|
point.corner = "tr";
|
||||||
|
d = true;
|
||||||
|
compute();
|
||||||
|
return transform(point2D(-tr.x, tr.y), [0, 0, 0, 1], [0, 0], -w);
|
||||||
|
} else {
|
||||||
|
j = height - startPoint.y;
|
||||||
|
k = Math.sqrt(n * n + m * m);
|
||||||
|
l = 2 * j * Math.cos(A90 - q) + k;
|
||||||
|
point.x = width - l * Math.cos(q);
|
||||||
|
point.y = height - l * Math.sin(q);
|
||||||
|
point.corner = "br";
|
||||||
|
compute();
|
||||||
|
return transform(point2D(-tr.x, -tr.y), [0, 1, 1, 0], [0, 100], w);
|
||||||
|
}
|
||||||
|
case "tl":
|
||||||
|
d = true;
|
||||||
|
e = true;
|
||||||
|
point.x = Math.max(point.x, 1);
|
||||||
|
c = _startPoint("tl", width, height);
|
||||||
|
compute();
|
||||||
|
return transform(tr, [1, 0, 0, 1], [100, 0], w);
|
||||||
|
case "tr":
|
||||||
|
d = true;
|
||||||
|
point.x = Math.min(point.x, width - 1);
|
||||||
|
compute();
|
||||||
|
return transform(point2D(-tr.x, tr.y), [0, 0, 0, 1], [0, 0], -w);
|
||||||
|
case "bl":
|
||||||
|
e = true;
|
||||||
|
point.x = Math.max(point.x, 1);
|
||||||
|
compute();
|
||||||
|
return transform(point2D(tr.x, -tr.y), [1, 1, 0, 0], [100, 100], -w);
|
||||||
|
case "br":
|
||||||
|
point.x = Math.min(point.x, width - 1);
|
||||||
|
compute();
|
||||||
|
return transform(point2D(-tr.x, -tr.y), [0, 1, 1, 0], [0, 100], w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function animatef(point) {
|
||||||
|
if (!point.to.length) point.to = [point.to];
|
||||||
|
if (!point.from.length) point.from = [point.from];
|
||||||
|
|
||||||
|
const diff = [];
|
||||||
|
const len = point.to.length;
|
||||||
|
const time = Date.now();
|
||||||
|
|
||||||
|
const frame = function() {
|
||||||
|
const v = [];
|
||||||
|
const timeDiff = Math.min(point.duration, Date.now() - time);
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) v.push(easing(1, timeDiff, point.from[i], diff[i], point.duration));
|
||||||
|
|
||||||
|
point.frame(len === 1 ? v[0] : v);
|
||||||
|
|
||||||
|
if (timeDiff === point.duration) {
|
||||||
|
if (point.complete) point.complete();
|
||||||
|
} else {
|
||||||
|
requestAnimationFrameId = requestAnimationFrame(frame);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < len; i++) diff.push(point.to[i] - point.from[i]);
|
||||||
|
|
||||||
|
const easing = function(x, t, b, c, data) {
|
||||||
|
return c * Math.sqrt(1 - (t = t / data - 1) * t) + b;
|
||||||
|
};
|
||||||
|
|
||||||
|
let requestAnimationFrameId;
|
||||||
|
|
||||||
|
frame();
|
||||||
|
|
||||||
|
return {
|
||||||
|
stop() {
|
||||||
|
if (point.complete) point.complete();
|
||||||
|
cancelAnimationFrame(requestAnimationFrameId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function turnPage(p1, duration, width, height, frame, complete) {
|
||||||
|
const p4 = _endPoint(p1.corner, width, height);
|
||||||
|
return animatef({
|
||||||
|
from: 0,
|
||||||
|
to: 1,
|
||||||
|
frame: function(v) {
|
||||||
|
const np = bezier(p1, p1, p4, p4, v);
|
||||||
|
frame({ x: np.x, y: np.y, corner: p1.corner });
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
complete();
|
||||||
|
},
|
||||||
|
duration: duration
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideFoldedPage(p1, width, height, frame, complete) {
|
||||||
|
const p4 = _startPoint(p1.corner, width, height);
|
||||||
|
const top = p1.corner.substr(0, 1) === "t";
|
||||||
|
const delta = top ? Math.min(0, p1.y - p4.y) / 2 : Math.max(0, p1.y - p4.y) / 2;
|
||||||
|
const p2 = point2D(p1.x, p1.y + delta);
|
||||||
|
const p3 = point2D(p4.x, p4.y - delta);
|
||||||
|
return animatef({
|
||||||
|
from: 0,
|
||||||
|
to: 1,
|
||||||
|
frame: function(v) {
|
||||||
|
const np = bezier(p1, p2, p3, p4, v);
|
||||||
|
frame({ x: np.x, y: np.y, corner: p1.corner });
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
complete();
|
||||||
|
},
|
||||||
|
duration: 600
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFoldedPage(to, width, height, frame, complete) {
|
||||||
|
const point = _startPoint(to.corner, width, height, 1);
|
||||||
|
|
||||||
|
return animatef({
|
||||||
|
from: [point.x, point.y],
|
||||||
|
to: [to.x, to.y],
|
||||||
|
duration: 300,
|
||||||
|
frame: function(v) {
|
||||||
|
const x = Math.round(v[0]);
|
||||||
|
const y = Math.round(v[1]);
|
||||||
|
frame({ x, y, corner: to.corner });
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { TurnPage },
|
||||||
|
props: {
|
||||||
|
data: Array,
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultStyles: [{}, {}, {}, {}, {}, {}],
|
||||||
|
startPoint: null,
|
||||||
|
relPoint: null,
|
||||||
|
invalidTouch: false,
|
||||||
|
action: null,
|
||||||
|
runAnimation: null,
|
||||||
|
viewIndex: 0,
|
||||||
|
turnPage: null,
|
||||||
|
backPage: 0,
|
||||||
|
turnActive: false,
|
||||||
|
showLastCoverPage: false,
|
||||||
|
touchTimeline: [],
|
||||||
|
styles: [{}, {}, {}, {}, {}, {}],
|
||||||
|
isStart: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.TouchMove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deactivated() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.TouchMoveOut();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
TouchMove() {
|
||||||
|
if (this.fun.getPhoneEnv() == 3) {
|
||||||
|
this.$refs.turn.addEventListener("mousemove", this.handleManualTouchMove, false);
|
||||||
|
this.$refs.turn.addEventListener("mousedown", this.handleManualTouchStart, false);
|
||||||
|
this.$refs.turn.addEventListener("mouseup", this.handleManualTouchEnd, false);
|
||||||
|
} else {
|
||||||
|
this.$refs.turn.addEventListener("touchmove", this.handleManualTouchMove, false);
|
||||||
|
this.$refs.turn.addEventListener("touchstart", this.handleManualTouchStart, false);
|
||||||
|
this.$refs.turn.addEventListener("touchend", this.handleManualTouchEnd, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TouchMoveOut() {
|
||||||
|
if (this.fun.getPhoneEnv() == 3) {
|
||||||
|
this.$refs.turn.removeEventListener("mousemove", this.handleManualTouchMove, false);
|
||||||
|
this.$refs.turn.removeEventListener("mousedown", this.handleManualTouchStart, false);
|
||||||
|
this.$refs.turn.removeEventListener("mouseup", this.handleManualTouchEnd, false);
|
||||||
|
} else {
|
||||||
|
this.$refs.turn.removeEventListener("touchmove", this.handleManualTouchMove, false);
|
||||||
|
this.$refs.turn.removeEventListener("touchstart", this.handleManualTouchStart, false);
|
||||||
|
this.$refs.turn.removeEventListener("touchend", this.handleManualTouchEnd, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleManualTouchStart(e) {
|
||||||
|
this.isStart = true;
|
||||||
|
let x = "";
|
||||||
|
let y = "";
|
||||||
|
if (this.runAnimation) {
|
||||||
|
this.runAnimation.stop();
|
||||||
|
this.updateTurn();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { width, height, viewIndex } = this;
|
||||||
|
if (this.fun.getPhoneEnv() == 3) {
|
||||||
|
x = e.clientX - (window.innerWidth - width) / 2;
|
||||||
|
y = e.clientY - (window.innerHeight - height) / 2;
|
||||||
|
} else {
|
||||||
|
x = e.touches[0].clientX - (window.innerWidth - width) / 2;
|
||||||
|
y = e.touches[0].clientY - (window.innerHeight - height) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startPoint = peelingPoint("r", x, y);
|
||||||
|
this.touchTimeline = [{ t: Date.now(), x }];
|
||||||
|
|
||||||
|
if (x < width / 2) {
|
||||||
|
this.action = "backward";
|
||||||
|
if (viewIndex <= 0) {
|
||||||
|
this.invalidTouch = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.turnPage = viewIndex - 1;
|
||||||
|
this.backPage = viewIndex;
|
||||||
|
} else {
|
||||||
|
this.action = "forward";
|
||||||
|
if (viewIndex >= this.data.length - 1) {
|
||||||
|
this.invalidTouch = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.turnPage = viewIndex;
|
||||||
|
this.backPage = viewIndex + 1;
|
||||||
|
}
|
||||||
|
// console.log(x,this.touchTimeline)
|
||||||
|
this.readyTurn();
|
||||||
|
},
|
||||||
|
handleManualTouchMove(e) {
|
||||||
|
let x = "";
|
||||||
|
let y = "";
|
||||||
|
if (this.isStart) {
|
||||||
|
const { width, height } = this;
|
||||||
|
if (this.fun.getPhoneEnv() == 3) {
|
||||||
|
x = e.clientX - (window.innerWidth - width) / 2;
|
||||||
|
y = e.clientY - (window.innerHeight - height) / 2;
|
||||||
|
} else {
|
||||||
|
x = e.touches[0].clientX - (window.innerWidth - width) / 2;
|
||||||
|
y = e.touches[0].clientY - (window.innerHeight - height) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const corner = this.startPoint.corner;
|
||||||
|
if (this.action === "forward" && this.startPoint.x < x) return;
|
||||||
|
if (this.action === "backward" && this.startPoint.x > x) return;
|
||||||
|
|
||||||
|
this.touchTimeline.push({ t: Date.now(), x });
|
||||||
|
const point = peelingPoint(corner, x, y);
|
||||||
|
|
||||||
|
if (this.invalidTouch) return;
|
||||||
|
|
||||||
|
this.updateTurn(fold(point, width, height, this.startPoint));
|
||||||
|
this.relPoint = point;
|
||||||
|
this.turnActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
handleManualTouchEnd() {
|
||||||
|
this.isStart = false;
|
||||||
|
const action = this.action;
|
||||||
|
|
||||||
|
if (this.touchTimeline.length < 2) {
|
||||||
|
if (this.touchTimeline.length) {
|
||||||
|
this.handleManualTaped();
|
||||||
|
} else {
|
||||||
|
this.turnPage = null;
|
||||||
|
this.backPage = this.viewIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.invalidTouch = false;
|
||||||
|
this.touchTimeline = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.invalidTouch) {
|
||||||
|
if (action === "forward" && this.isSwipe(action)) {
|
||||||
|
// this.showLastCoverPage = true
|
||||||
|
this.$emit("next", { to: this.viewIndex + 1, from: this.viewIndex });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "backward" && this.isSwipe(action)) {
|
||||||
|
this.$emit("prev", { to: this.viewIndex - 1, from: this.viewIndex });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (action === "forward") {
|
||||||
|
if (this.isSwipe(action)) {
|
||||||
|
this.toPage(this.viewIndex + 1, this.relPoint);
|
||||||
|
} else {
|
||||||
|
this.hideFolded(this.relPoint, () => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === "backward") {
|
||||||
|
if (this.isSwipe(action)) {
|
||||||
|
this.toPage(this.viewIndex - 1, this.relPoint);
|
||||||
|
} else {
|
||||||
|
this.turn(this.relPoint, () => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.invalidTouch = false;
|
||||||
|
this.touchTimeline = [];
|
||||||
|
},
|
||||||
|
handleManualTaped() {
|
||||||
|
const { width } = this;
|
||||||
|
const x = this.touchTimeline[0].x;
|
||||||
|
|
||||||
|
this.action = null;
|
||||||
|
if (x < width / 4) return this.toPage(this.viewIndex - 1);
|
||||||
|
if (x > width / 4 * 3) return this.toPage(this.viewIndex + 1);
|
||||||
|
|
||||||
|
this.$emit("tap");
|
||||||
|
},
|
||||||
|
readyTurn() {
|
||||||
|
const { width, height } = this;
|
||||||
|
const point = this.action === "forward" ? { x: width, y: 0 } : { x: -width, y: 0 };
|
||||||
|
const fromPoint = peelingPoint("tr", point.x, point.y);
|
||||||
|
// console.log(fromPoint,"fromPoint");
|
||||||
|
this.updateTurn(fold(fromPoint, width, height));
|
||||||
|
},
|
||||||
|
updateTurn(style = [{}, {}, {}, {}, {}, {}]) {
|
||||||
|
this.styles = style;
|
||||||
|
},
|
||||||
|
isSwipe(action) {
|
||||||
|
const first = this.touchTimeline[0];
|
||||||
|
const last = this.touchTimeline[this.touchTimeline.length - 1];
|
||||||
|
const swipeTime = Date.now() - first.t;
|
||||||
|
const minTime = 200;
|
||||||
|
const minDistance = 20;
|
||||||
|
|
||||||
|
if (action === "forward") return first.x - last.x > 50 || (first.x - last.x > minDistance && swipeTime < minTime);
|
||||||
|
if (action === "backward") return last.x - first.x > 50 || (last.x - first.x > minDistance && swipeTime < minTime);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
toPage(toPage, startPoint) {
|
||||||
|
const fromPage = this.viewIndex;
|
||||||
|
|
||||||
|
if (toPage > fromPage) this.$emit("next", { to: toPage, from: fromPage });
|
||||||
|
if (toPage < fromPage) this.$emit("prev", { to: toPage, from: fromPage });
|
||||||
|
|
||||||
|
if (toPage === fromPage || toPage < 0 || toPage > this.data.length - 1) return;
|
||||||
|
|
||||||
|
if (this.runAnimation) {
|
||||||
|
this.runAnimation.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const { width, height } = this;
|
||||||
|
const point = toPage > fromPage ? { x: width, y: height - 45 } : { x: -width, y: 45 };
|
||||||
|
const fromPoint = peelingPoint("br", point.x, point.y);
|
||||||
|
|
||||||
|
if (toPage > fromPage) {
|
||||||
|
if (!this.action) {
|
||||||
|
this.action = "forward";
|
||||||
|
this.turnPage = fromPage;
|
||||||
|
this.backPage = toPage;
|
||||||
|
this.turnActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.turn(startPoint || fromPoint, () => {
|
||||||
|
this.viewIndex = toPage;
|
||||||
|
this.turnPage = null;
|
||||||
|
this.backPage = toPage;
|
||||||
|
// console.log('完成翻页,当前页', this.backPage)
|
||||||
|
this.updateTurn();
|
||||||
|
this.turnActive = false;
|
||||||
|
this.$emit("change", this.backPage);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!this.action) {
|
||||||
|
this.action = "backward";
|
||||||
|
this.turnPage = toPage;
|
||||||
|
this.backPage = fromPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hideFolded(startPoint || fromPoint, () => {
|
||||||
|
this.viewIndex = toPage;
|
||||||
|
this.turnPage = null;
|
||||||
|
this.backPage = toPage;
|
||||||
|
// console.log('完成翻页,当前页', this.backPage)
|
||||||
|
this.updateTurn();
|
||||||
|
this.turnActive = false;
|
||||||
|
this.$emit("change", this.backPage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// console.log('this.turnActive', this.turnPage, this.turnActive)
|
||||||
|
this.$emit("turning", this.backPage);
|
||||||
|
},
|
||||||
|
turn(fromPoint, complete) {
|
||||||
|
const { width, height } = this;
|
||||||
|
this.runAnimation = turnPage(fromPoint, 600, width, height, point => {
|
||||||
|
this.updateTurn(fold(point, width, height));
|
||||||
|
}, () => {
|
||||||
|
complete();
|
||||||
|
this.action = null;
|
||||||
|
this.turnPage = null;
|
||||||
|
this.backPage = this.viewIndex;
|
||||||
|
this.updateTurn();
|
||||||
|
this.runAnimation = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
hideFolded(fromPoint, complete) {
|
||||||
|
const { width, height } = this;
|
||||||
|
this.runAnimation = hideFoldedPage(fromPoint, width, height, point => {
|
||||||
|
this.updateTurn(fold(point, width, height));
|
||||||
|
}, () => {
|
||||||
|
complete();
|
||||||
|
this.action = null;
|
||||||
|
this.turnPage = null;
|
||||||
|
this.backPage = this.viewIndex;
|
||||||
|
this.updateTurn();
|
||||||
|
this.turnActive = false;
|
||||||
|
this.runAnimation = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleCoverTouchStart(e) {
|
||||||
|
const x = e.touches[0].clientX;
|
||||||
|
this.touchTimeline = [{ t: Date.now(), x }];
|
||||||
|
},
|
||||||
|
handleCoverTouchMove(e) {
|
||||||
|
const x = e.touches[0].clientX;
|
||||||
|
this.touchTimeline.push({ t: Date.now(), x });
|
||||||
|
},
|
||||||
|
handleCoverTouchEnd(e) {
|
||||||
|
const first = this.touchTimeline[0];
|
||||||
|
const last = this.touchTimeline[this.touchTimeline.length - 1];
|
||||||
|
if (last.x - first.x > 20 && last.t - first.t < 200) {
|
||||||
|
this.showLastCoverPage = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,325 @@
|
||||||
|
<template>
|
||||||
|
<div class="turn-wraper"
|
||||||
|
:style="{width: width+'px', height: height+'px', overflow: active ? 'visible' : 'hidden', zIndex: length - index}">
|
||||||
|
<div class="turn-page-left" :style="{left: '-'+width+'px'}">
|
||||||
|
<div class="turn-page-left-clip" :style="(Object.assign({}, {width: clipSize+'px', height: clipSize+'px'}, styles[3]))">
|
||||||
|
<div class="turn-page-left-content"
|
||||||
|
:style="(Object.assign({}, {width: width+'px', height: height+'px'}, styles[1]))">
|
||||||
|
<div class="turn-page-left-inner">
|
||||||
|
<div class="manual-item">
|
||||||
|
<div class="page-count">{{index + 1}} / {{length}}</div>
|
||||||
|
<div class="manual-page">
|
||||||
|
<div class="page-photo">
|
||||||
|
<img :src="item.picture_image">
|
||||||
|
</div>
|
||||||
|
<!--<div class="page-content page-content-type-1">-->
|
||||||
|
<!--<div class="desc"><h4 class="name">-->
|
||||||
|
<!--小程序组件小程序组件小程序组件小程序组件小程序组件小程序组件</h4>-->
|
||||||
|
<!--<div class="price">¥19800</div> <!––> <!––></div>-->
|
||||||
|
<!--<div class="buy-button">-->
|
||||||
|
<!--<button type="button">查看详情</button>-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--</div>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="turn-page-left-gradient" :style="(Object.assign({}, {top: ('-' + (height / 2)+'px'), height: (height* 2)+'px'}, styles[4]))"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="turn-page-right" :style="{width: width+'px', height: height+'px'}">
|
||||||
|
<div class="turn-page-right-gradient" :style="(Object.assign({}, {top: ('-' + (height / 2)+'px'), height: (height* 2)+'px'}, styles[5]))"></div>
|
||||||
|
|
||||||
|
<div class="turn-page-right-clip" :style="(Object.assign({}, {width: clipSize+'px', height: clipSize+'px'}, styles[2]))">
|
||||||
|
<div class="turn-page-right-content" :style="(Object.assign({}, {width: width+'px', height: height+'px'}, styles[0]))">
|
||||||
|
<div class="manual-item">
|
||||||
|
<div class="page-count">{{index + 1}} / {{length}}</div>
|
||||||
|
<div class="manual-page">
|
||||||
|
<div class="page-photo">
|
||||||
|
<img :src="item.picture_image">
|
||||||
|
</div>
|
||||||
|
<!--<div class="page-content page-content-type-1">-->
|
||||||
|
<!--<div class="desc"><h4 class="name">-->
|
||||||
|
<!--小程序组件小程序组件小程序组件小程序组件小程序组件小程序组件</h4>-->
|
||||||
|
<!--<div class="price">¥19800</div> <!––> <!––></div>-->
|
||||||
|
<!--<div class="buy-button">-->
|
||||||
|
<!--<button type="button">查看详情</button>-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--</div>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import turn_page_controller from "./turn_page_controller";
|
||||||
|
|
||||||
|
export default turn_page_controller;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
|
.turn-wraper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
-webkit-transition: all ease 0.35s;
|
||||||
|
transition: all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-left {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
z-index: 5;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-left-clip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-left-content {
|
||||||
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-left-inner {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
-webkit-transform: rotateY(180deg);
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
opacity: 0.3;
|
||||||
|
-webkit-transition: width all ease 0.35s, height all ease 0.35s;
|
||||||
|
transition: width all ease 0.35s, height all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-left-gradient {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
width: 100px;
|
||||||
|
-webkit-transform: scale3d(0, 1, 1);
|
||||||
|
transform: scale3d(0, 1, 1);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 100% 0%, from(rgba(0, 0, 0, 0)), color-stop(0.3, rgba(0, 0, 0, 0.2)), color-stop(0.5, rgba(0, 0, 0, 0.5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-right {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 4;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-right-gradient {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
width: 100px;
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale3d(0, 1, 1);
|
||||||
|
transform: scale3d(0, 1, 1);
|
||||||
|
background: -webkit-gradient(linear, 0% 0%, 100% 0%, from(rgba(0, 0, 0, 0)), color-stop(0.2, rgba(0, 0, 0, 0.3)), color-stop(0.2, rgba(0, 0, 0, 0.4)), color-stop(0.4, rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-right-clip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.turn-page-right-content {
|
||||||
|
position: absolute;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1;
|
||||||
|
transition: width all ease 0.35s, height all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-item {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
-webkit-transition: all ease 0.35s;
|
||||||
|
transition: all ease 0.35s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-count {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.8rem;
|
||||||
|
left: 50%;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 0 0.8rem;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.8;
|
||||||
|
-webkit-transform: translate(-50%, 0);
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page.loading {
|
||||||
|
/*background: url(/article-h5/static/img/loading.95eeac7.gif) no-repeat center center !important;*/
|
||||||
|
/*background-size: 60px !important;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo {
|
||||||
|
position: relative;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transition: opacity ease 0.2s;
|
||||||
|
transition: opacity ease 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manual-page.loading .page-photo {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
pointer-events: none;
|
||||||
|
background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.2)), color-stop(6%, rgba(255, 255, 255, 0.15)), to(rgba(255, 255, 255, 0.15)));
|
||||||
|
background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.2) 0%, rgba(255, 255, 255, 0.15) 6%, rgba(255, 255, 255, 0.15) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-photo img {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
text-align: left;
|
||||||
|
padding: 0.6rem 0.2rem;
|
||||||
|
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.92)), to(rgba(0, 0, 0, 0.00)));
|
||||||
|
background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.92) 0%, rgba(0, 0, 0, 0.00) 100%);
|
||||||
|
pointer-events: none;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content-type-1 {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content-type-2 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .desc {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
width: calc(65% - 0.14rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .name {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .price {
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .buy-button {
|
||||||
|
width: 35%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .buy-button button {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2rem;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
border: none;
|
||||||
|
padding: 0 0.16rem;
|
||||||
|
background: #FF8D00;
|
||||||
|
-webkit-box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
border-radius: 0.02rem;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-content .form-button {
|
||||||
|
height: 0.34rem;
|
||||||
|
border: none;
|
||||||
|
padding: 0 0.16rem;
|
||||||
|
background: #FFFFFF;
|
||||||
|
-webkit-box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
box-shadow: 0 0.02rem 0.04rem 0 rgba(0, 0, 0, 0.20);
|
||||||
|
border-radius: 0.02rem;
|
||||||
|
font-family: PingFangSC-Semibold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #0084BF;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,36 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
item: Object,
|
||||||
|
index: Number,
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
length: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
active: { // 翻动效果生效
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [{}, {}, {}, {}, {}, {}]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
clipSize() {
|
||||||
|
return Math.sqrt(Math.pow(this.width, 2) + Math.pow(this.height, 2), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,54 @@
|
||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const uglify = require("uglifyjs-webpack-plugin");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'source-map',
|
||||||
|
entry: "./src/index.js",//入口文件,就是上步骤的src目录下的index.js文件,
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, './dist'),//输出路径,就是上步骤中新建的dist目录,
|
||||||
|
publicPath: '/dist/',
|
||||||
|
filename: 'flip.min.js',
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
umdNamedDefine: true
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: 'vue-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss/,
|
||||||
|
use: [
|
||||||
|
{loader: "style-loader"},
|
||||||
|
{loader: "css-loader"},
|
||||||
|
{loader: "sass-loader"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
options:{
|
||||||
|
presets:["es2015"]
|
||||||
|
},
|
||||||
|
loader: 'babel-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg|gif|ttf|svg|woff|eot)$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 30000,
|
||||||
|
name: '[name].[ext]?[hash]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
"process.env": {
|
||||||
|
NODE_ENV: JSON.stringify("production")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
Loading…
Reference in New Issue