四零语境前端代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

262 lines
5.6 KiB

<template>
<view class="nx-turn">
<view
class="nx-turn-page-wrapper turn"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@touchcancel="touchCancel"
>
<view
class="nx-turn-page-content-wrapper"
:style="[{
width: `${pageContentWrapperWidth}px`,
height: `${pageContentWrapperWidth}px`
}, transformStyle.wrapper]"
>
<view
class="nx-turn-page-content-box"
:class="customClass"
:style="[{
width: `${pageWrapperInfo.width}px`,
height: `${pageWrapperInfo.height}px`
}, customStyle, transformStyle.content]"
>
<slot name="page-content" :page="page"></slot>
</view>
</view>
<view
class="nx-turn-page-content-wrapper nx-turn-page-content-wrapper-b"
:style="[{
width: `${pageContentWrapperWidth}px`,
height: `${pageContentWrapperWidth}px`
}, transformStyle.bwrapper]"
>
<view
class="nx-turn-page-content-box nx-turn-page-content-b-box"
:class="customClass"
:style="[{
width: `${pageWrapperInfo.width}px`,
height: `${pageWrapperInfo.height}px`
}, customStyle, transformStyle.bcontent]"
>
<view
class="nx-turn-page-content-wrapper-b-shadow"
:style="[{
width: `${pageWrapperInfo.width}px`,
height: `${pageWrapperInfo.height}px`
}, transformStyle.bgradient]"
></view>
<view class="nx-turn-page-content-b"></view>
</view>
</view>
<view
:style="[{
width: `${pageWrapperInfo.width}px`,
height: `${pageWrapperInfo.height}px`
}, transformStyle.gradient]"
></view>
</view>
<view
class="nx-turn-page-wrapper next"
:class="customClass"
:style="customStyle"
>
<slot name="next-page-content" :page="page + 1"></slot>
</view>
</view>
</template>
<script>
import {
getPageDiagonalLength,
point2D,
touchStartEvent,
touchMoveEvent,
touchEndEvent,
setPageNumber,
setPageCount
} from './js/nx-turn.js';
export default {
name:"nx-turn",
props: {
/**
* 初始页码,从0开始
*/
initPage: {
type: Number,
default: 0
},
/**
* 页数
*/
pageCount: {
type: Number,
default: -1
},
customClass: {
type: String,
default: 'nx-turn-theme'
},
customStyle: {
type: Object,
default: () => { return {} }
}
},
data() {
return {
// 起始触摸点X坐标
touchStartX: 0,
// 起始触摸点Y坐标
touchStartY: 0,
// 书页内容包装外框宽度(等于书页对角线长度)
pageContentWrapperWidth: 0,
// 书页包装外框信息
pageWrapperInfo: { width: 0, height: 0 },
// 变换样式
transformStyle: {},
// 当前页码
page: 0,
mouseIsDown: false
};
},
created() {
this.setPage();
setPageCount(this.pageCount);
},
mounted() {
this.$nextTick(() => {
this.init();
});
},
watch: {
initPage() {
this.setPage();
},
pageCount(newValue) {
setPageCount(newValue);
}
},
methods: {
init() {
const query = uni.createSelectorQuery().in(this);
query
.select('.nx-turn-page-wrapper.turn')
.boundingClientRect(async (data) => {
this.pageWrapperInfo = data;
this.pageContentWrapperWidth = getPageDiagonalLength(data);
this.$emit('init-completed', this.pageWrapperInfo);
})
.exec();
},
setPage() {
this.page = this.initPage;
setPageNumber(this.page);
},
touchStart(e) {
this.touchStartX = e.touches[0].clientX;
this.touchStartY = e.touches[0].clientY;
touchStartEvent(this.pageWrapperInfo, point2D(this.touchStartX, this.touchStartY));
},
mouseDown(e) {
this.mouseIsDown = true;
this.touchStart(e);
},
touchMove(e) {
// this.closeMenu();
const point = e.touches[0];
const { style, pageNumber } = touchMoveEvent(point2D(point.clientX, point.clientY));
this.transformStyle = style;
this.page = pageNumber;
this.$emit('turning');
},
mouseMove(e) {
if(this.mouseIsDown) {
this.touchMove(e);
}
},
touchEnd(e) {
e.preventDefault();
const point = e.changedTouches[0];
this.handleTouchEnd(point2D(point.clientX, point.clientY));
},
mouseUp(e) {
this.mouseIsDown = false;
this.touchEnd(e);
},
touchCancel(e) {
this.handleTouchEnd(point2D(this.touchStartX, this.touchStartY));
},
handleTouchEnd(point) {
touchEndEvent(
point,
({ style, pageNumber }) => {
// this.closeMenu();
this.transformStyle = style;
this.page = pageNumber;
this.$emit('turning');
},
({ style, pageNumber, isFirst, isLast }) => {
this.transformStyle = style;
this.page = pageNumber;
this.$emit('turned', { pageNumber, isFirst, isLast });
},
() => {
this.$emit('click-center');
}
);
},
}
}
</script>
<style lang="scss">
.nx-turn {
width: 100%;
height: 100%;
&-page {
&-wrapper {
position: absolute;
overflow: hidden;
height: 100%;
width: 100%;
perspective: 1000px;
&.turn {
z-index: 20;
}
&.next {
z-index: 10;
}
}
&-content {
height: 100%;
&-wrapper {
position: absolute;
top: 0px;
left: 0px;
overflow: hidden;
z-index: auto;
transform-origin: 0% 100%;
&-b {
transform: translate(-100%, 0);
&-shadow {
position: absolute;
top: 0px;
left: 0px;
overflow: hidden;
z-index: 1;
}
}
}
&-box {
position: absolute;
}
}
}
&-theme {
background-color: #EBD6B1;
color: mix(#000000, #EBD6B1, 70%);
border-color: mix(#FFFFFF, #EBD6B1, 70%);
}
}
</style>