save
This commit is contained in:
parent
19f3733aa7
commit
32ff343b83
@ -11,10 +11,12 @@
|
||||
"axios": "0.26.1",
|
||||
"core-js": "3.21.1",
|
||||
"dayjs": "1.11.0",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"lodash": "4.17.21",
|
||||
"mitt": "3.0.0",
|
||||
"mockjs": "1.1.0",
|
||||
"pinyin": "2.11.1",
|
||||
"vconsole": "^3.15.0",
|
||||
"vue": "3.2.31",
|
||||
"vue-router": "4.0.14",
|
||||
"vue-switches": "2.0.1",
|
||||
|
||||
@ -7,12 +7,14 @@ specifiers:
|
||||
axios: 0.26.1
|
||||
core-js: 3.21.1
|
||||
dayjs: 1.11.0
|
||||
gl-matrix: ^3.4.3
|
||||
less: ^4.1.3
|
||||
lodash: 4.17.21
|
||||
mitt: 3.0.0
|
||||
mobile-select: 1.1.2
|
||||
mockjs: 1.1.0
|
||||
pinyin: 2.11.1
|
||||
vconsole: ^3.15.0
|
||||
vite: 4.0.4
|
||||
vue: 3.2.31
|
||||
vue-router: 4.0.14
|
||||
@ -24,10 +26,12 @@ dependencies:
|
||||
axios: 0.26.1
|
||||
core-js: 3.21.1
|
||||
dayjs: 1.11.0
|
||||
gl-matrix: 3.4.3
|
||||
lodash: 4.17.21
|
||||
mitt: 3.0.0
|
||||
mockjs: 1.1.0
|
||||
pinyin: 2.11.1
|
||||
vconsole: 3.15.0
|
||||
vue: 3.2.31
|
||||
vue-router: 4.0.14_vue@3.2.31
|
||||
vue-switches: 2.0.1
|
||||
@ -305,6 +309,13 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/runtime/7.20.7:
|
||||
resolution: {integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
regenerator-runtime: 0.13.11
|
||||
dev: false
|
||||
|
||||
/@babel/template/7.20.7:
|
||||
resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -883,6 +894,11 @@ packages:
|
||||
is-what: 3.14.1
|
||||
dev: true
|
||||
|
||||
/copy-text-to-clipboard/3.0.1:
|
||||
resolution: {integrity: sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==}
|
||||
engines: {node: '>=12'}
|
||||
dev: false
|
||||
|
||||
/core-js/3.21.1:
|
||||
resolution: {integrity: sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==}
|
||||
deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.
|
||||
@ -1051,6 +1067,10 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/gl-matrix/3.4.3:
|
||||
resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==}
|
||||
dev: false
|
||||
|
||||
/glob/7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
dependencies:
|
||||
@ -1303,6 +1323,10 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/mutation-observer/1.0.3:
|
||||
resolution: {integrity: sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==}
|
||||
dev: false
|
||||
|
||||
/nanoid/3.3.4:
|
||||
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
@ -1448,6 +1472,10 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/regenerator-runtime/0.13.11:
|
||||
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||
dev: false
|
||||
|
||||
/resolve/1.22.1:
|
||||
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
|
||||
hasBin: true
|
||||
@ -1612,6 +1640,15 @@ packages:
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/vconsole/3.15.0:
|
||||
resolution: {integrity: sha512-8hq7wabPcRucSWQyN7/1tthMawP9JPvM95zgtMHpPknMMMCKj+abpoK7P7oKK4B0qw58C24Mdvo9+raUdpHyVQ==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.20.7
|
||||
copy-text-to-clipboard: 3.0.1
|
||||
core-js: 3.21.1
|
||||
mutation-observer: 1.0.3
|
||||
dev: false
|
||||
|
||||
/vite/4.0.4_less@4.1.3:
|
||||
resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
||||
@ -185,7 +185,7 @@ p {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.slide-wrapper {
|
||||
.slide-list {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div id="SlideImgs">
|
||||
<div class="img-slide-wrapper">
|
||||
<div class="img-slide-wrapper" ref="wap">
|
||||
<div class="img-slide-list"
|
||||
ref="list"
|
||||
@touchstart="start"
|
||||
@touchstart="touchstart"
|
||||
@touchmove="move"
|
||||
@touchend="end">
|
||||
<div class="img-slide-item" v-for="img in modelValue.imgs">
|
||||
@ -23,7 +23,23 @@
|
||||
<script>
|
||||
import enums from "../../utils/enums";
|
||||
import globalMethods from '../../utils'
|
||||
//TODO 放大功能待完善
|
||||
import {mat4} from 'gl-matrix'
|
||||
import {cloneDeep} from "lodash";
|
||||
|
||||
let out = new Float32Array([
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0
|
||||
])
|
||||
let ov = new Float32Array([
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1,
|
||||
]);
|
||||
let original = cloneDeep(ov)
|
||||
const rectMap = new Map()
|
||||
export default {
|
||||
name: "SlideImgs",
|
||||
components: {},
|
||||
@ -148,7 +164,6 @@ export default {
|
||||
store: {
|
||||
scale: 1
|
||||
},
|
||||
|
||||
result: {
|
||||
width: 414,
|
||||
height: 737
|
||||
@ -165,10 +180,18 @@ export default {
|
||||
lastPoint1: {x: 0, y: 0},
|
||||
lastPoint2: {x: 0, y: 0},
|
||||
lastCenter: {x: 0, y: 0},
|
||||
|
||||
startCenter: {x: 0, y: 0},
|
||||
a: {},
|
||||
b: {},
|
||||
|
||||
last: {
|
||||
ratio: 1,
|
||||
point1: {x: 0, y: 0},
|
||||
point2: {x: 0, y: 0},
|
||||
},
|
||||
start: {
|
||||
point1: {x: 0, y: 0},
|
||||
point2: {x: 0, y: 0},
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -200,7 +223,56 @@ export default {
|
||||
}
|
||||
requestAnimationFrame(this.cycleFn)
|
||||
}
|
||||
return
|
||||
// requestAnimationFrame(this.cycleFn)
|
||||
|
||||
let x = 0
|
||||
let y = 0
|
||||
let scale = 1
|
||||
|
||||
let isDrag = false // 按下标识
|
||||
const image = document.querySelector(`.img-slide-list`);
|
||||
let tt = new Map()
|
||||
image.addEventListener('wheel', e => {
|
||||
this.itemRefs[this.index].style['transition-duration'] = '0ms';
|
||||
|
||||
let {clientX, clientY, deltaY} = e;
|
||||
let rect = {x: 0, y: 0}
|
||||
if (tt.has(this.index)) {
|
||||
rect = tt.get(this.index)
|
||||
} else {
|
||||
rect = this.itemRefs[this.index].getBoundingClientRect()
|
||||
tt.set(this.index, rect)
|
||||
}
|
||||
clientX -= rect.x
|
||||
clientY -= rect.y
|
||||
const zoom = 1 + (deltaY < 0 ? 0.1 : -0.1);
|
||||
const x = clientX * (1 - zoom);
|
||||
const y = clientY * (1 - zoom);
|
||||
const t = new Float32Array([zoom, 0, 0, 0, 0, zoom, 0, 0, 0, 0, 1, 0, x, y, 0, 1,]);
|
||||
ov = mat4.multiply(out, t, ov);
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${ov.toString()})`;
|
||||
// image.setAttribute("style", `transform:matrix3d(${ov.toString()});`);
|
||||
})
|
||||
image.addEventListener('mousedown', () => {
|
||||
this.itemRefs[this.index].style['transition-duration'] = '0ms';
|
||||
isDrag = true
|
||||
});
|
||||
image.addEventListener('mousemove', (e) => {
|
||||
e.preventDefault();
|
||||
if (isDrag) {
|
||||
const {movementX, movementY} = e;
|
||||
const t = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, movementX, movementY, 0, 1,]);
|
||||
ov = mat4.multiply(out, t, ov);
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${ov.toString()})`;
|
||||
}
|
||||
});
|
||||
image.addEventListener('mouseup', () => {
|
||||
this.itemRefs[this.index].style['transition-duration'] = '300ms';
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${original.toString()})`;
|
||||
ov = original
|
||||
isDrag = false
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getCenter(a, b) {
|
||||
@ -208,12 +280,16 @@ export default {
|
||||
const y = (a.y + b.y) / 2;
|
||||
return {x, y}
|
||||
},
|
||||
start(e) {
|
||||
console.log('start')
|
||||
// 获取坐标之间的举例
|
||||
getDistance(start, stop) {
|
||||
return Math.hypot(stop.x - start.x, stop.y - start.y);
|
||||
},
|
||||
touchstart(e) {
|
||||
// console.log('start', e.touches.length)
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'stop'
|
||||
}
|
||||
if (e.touches && e.touches.length === 1) {
|
||||
if (e.touches.length === 1) {
|
||||
this.isTwo = false
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `0ms`)
|
||||
this.startX = e.touches[0].pageX
|
||||
@ -223,118 +299,121 @@ export default {
|
||||
this.isTwo = true
|
||||
this.itemRefs[this.index].style['transition-duration'] = '0ms';
|
||||
|
||||
let events = e.touches[0];
|
||||
let events2 = e.touches[1];
|
||||
|
||||
if (e.cancelable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.lastPoint1 = this.point1 = {x: events.pageX, y: events.pageY};
|
||||
this.lastPoint2 = this.point2 = {x: events2.pageX, y: events2.pageY};
|
||||
|
||||
this.lastCenter = this.getCenter(this.lastPoint1, this.lastPoint2)
|
||||
this.lastPoint1 = this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY};
|
||||
this.lastPoint2 = this.point2 = {x: e.touches[1].pageX, y: e.touches[1].pageY};
|
||||
this.startCenter = this.getCenter(this.point1, this.point2)
|
||||
}
|
||||
},
|
||||
move(e) {
|
||||
if (e.touches && e.touches.length === 1) {
|
||||
this.isTwo = false
|
||||
|
||||
this.moveX = e.touches[0].pageX - this.startX
|
||||
this.moveY = e.touches[0].pageY - this.startY
|
||||
|
||||
this.isDrawRight = this.moveX < 0
|
||||
this.isDrawDown = this.moveY < 0
|
||||
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index) +
|
||||
this.moveX}px, 0px, 0px)`)
|
||||
console.log('move', e.touches.length)
|
||||
if (this.isTwo && e.touches.length === 1) {
|
||||
// console.log('单手移动',)
|
||||
let current = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
let movementX = current.x - this.last.point1.x
|
||||
let movementY = current.y - this.last.point1.y
|
||||
// console.log(movementX, movementY)
|
||||
const t = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, movementX, movementY, 0, 1,]);
|
||||
ov = mat4.multiply(out, t, ov);
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${ov.toString()})`;
|
||||
this.last.point1 = current
|
||||
} else {
|
||||
this.isTwo = true
|
||||
if (e.cancelable) {
|
||||
e.preventDefault();
|
||||
if (e.touches.length === 1) {
|
||||
this.isTwo = false
|
||||
|
||||
this.moveX = e.touches[0].pageX - this.startX
|
||||
this.moveY = e.touches[0].pageY - this.startY
|
||||
|
||||
this.isDrawRight = this.moveX < 0
|
||||
this.isDrawDown = this.moveY < 0
|
||||
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index) +
|
||||
this.moveX}px, 0px, 0px)`)
|
||||
} else {
|
||||
this.isTwo = true
|
||||
if (e.cancelable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
let current1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
let current2 = {x: e.touches[1].pageX, y: e.touches[1].pageY}
|
||||
|
||||
// 双指缩放比例,就是对应的放大倍数
|
||||
let ratio = this.getDistance(current1, current2) / this.getDistance(this.point1, this.point2);
|
||||
|
||||
let rect = {x: 0, y: 0}
|
||||
if (rectMap.has(this.index)) {
|
||||
rect = rectMap.get(this.index)
|
||||
} else {
|
||||
//getBoundingClientRect在手机上获取不到值
|
||||
// rect = this.itemRefs[this.index].getBoundingClientRect()
|
||||
let offset = $(this.itemRefs[this.index]).offset()
|
||||
rect.x = offset.left
|
||||
rect.y = offset.top
|
||||
rectMap.set(this.index, rect)
|
||||
}
|
||||
let center = cloneDeep(this.startCenter)
|
||||
center.x -= rect.x
|
||||
center.y -= rect.y
|
||||
let zoom = ratio
|
||||
const x = center.x * (1 - zoom);
|
||||
const y = center.y * (1 - zoom);
|
||||
const t = new Float32Array([zoom, 0, 0, 0, 0, zoom, 0, 0, 0, 0, 1, 0, x, y, 0, 1,]);
|
||||
//如果zoom是累加放大(比如每次都是0.15),第三个参数用ov
|
||||
//但这里zoom是每次都是最后放大倍数,第三个参数用原值(即,矩阵x乘时,都是乘以单位矩阵)
|
||||
ov = mat4.multiply(out, t, original);
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${ov.toString()})`;
|
||||
}
|
||||
|
||||
let current1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
let current2 = {x: e.touches[1].pageX, y: e.touches[1].pageY}
|
||||
|
||||
// 获取坐标之间的举例
|
||||
let getDistance = function (start, stop) {
|
||||
return Math.hypot(stop.x - start.x, stop.y - start.y);
|
||||
};
|
||||
|
||||
// 双指缩放比例计算
|
||||
let ratio = getDistance(current1, current2) / getDistance(this.lastPoint1, this.lastPoint2);
|
||||
|
||||
|
||||
// 计算当前双指中心点坐标
|
||||
let center = this.getCenter(current1, current2)
|
||||
console.log('center', center)
|
||||
|
||||
// 计算图片中心偏移量,默认transform-origin: 50% 50%
|
||||
// 如果transform-origin: 30% 40%,那origin.x = (ratio - 1) * result.width * 0.3
|
||||
// origin.y = (ratio - 1) * result.height * 0.4
|
||||
// 如果通过修改宽高或使用transform缩放,但将transform-origin设置为左上角时。
|
||||
// 可以不用计算origin,因为(ratio - 1) * result.width * 0 = 0
|
||||
const origin = {
|
||||
x: (ratio - 1) * this.result.width * 0.5,
|
||||
y: (ratio - 1) * this.result.height * 0.5
|
||||
};
|
||||
// 计算偏移量,认真思考一下为什么要这样计算(带入特定的值计算一下)
|
||||
this.x -= (ratio - 1) * (center.x - this.x) - origin.x - (center.x - this.lastCenter.x);
|
||||
this.y -= (ratio - 1) * (center.y - this.y) - origin.y - (center.y - this.lastCenter.y);
|
||||
|
||||
// console.log('this.x', this.x)
|
||||
// console.log('this.y', this.y)
|
||||
|
||||
// 图像应用缩放效果
|
||||
this.itemRefs[this.index].style.transform =
|
||||
`translate3d(${this.x}px,${this.y}px,0) scale(${this.store.scale * ratio})`;
|
||||
|
||||
this.lastCenter = {x: center.x, y: center.y};
|
||||
this.lastPoint1 = {x: current1.x, y: current1.y};
|
||||
this.lastPoint2 = {x: current2.x, y: current2.y};
|
||||
}
|
||||
},
|
||||
end(e) {
|
||||
console.log('end',e.touches)
|
||||
if (this.isTwo) {
|
||||
this.store.scale = 1
|
||||
this.itemRefs[this.index].style['transition-duration'] = '300ms';
|
||||
this.itemRefs[this.index].style.transform = `translate3d(0,0,0) scale(1)`;
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'play'
|
||||
}
|
||||
if (e.touches.length){
|
||||
this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
}
|
||||
|
||||
console.log('end', e.touches.length, this.isTwo)
|
||||
if (this.isTwo && e.touches.length === 1) {
|
||||
//双指绽放,但只松开了一只手
|
||||
this.last.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
} else {
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
if (this.isTwo) {
|
||||
ov = original
|
||||
this.itemRefs[this.index].style['transition-duration'] = '300ms';
|
||||
this.itemRefs[this.index].style.transform = `matrix3d(${ov.toString()})`;
|
||||
// if (this.state !== 'custom') {
|
||||
// this.state = 'play'
|
||||
// }
|
||||
// if (e.touches.length) {
|
||||
// this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
// }
|
||||
|
||||
let canSlide = this.width / 5 < Math.abs(this.moveX);
|
||||
if (Date.now() - this.startTime < 40) canSlide = false
|
||||
|
||||
if (canSlide) {
|
||||
if (this.isDrawRight) {
|
||||
this.index += 1
|
||||
} else {
|
||||
this.index -= 1
|
||||
}
|
||||
this.state = 'custom'
|
||||
this.progress = (this.index + 1) * 100
|
||||
} else {
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'play'
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
|
||||
let canSlide = this.width / 5 < Math.abs(this.moveX);
|
||||
if (Date.now() - this.startTime < 40) canSlide = false
|
||||
|
||||
if (canSlide) {
|
||||
if (this.isDrawRight) {
|
||||
this.index += 1
|
||||
} else {
|
||||
this.index -= 1
|
||||
}
|
||||
this.state = 'custom'
|
||||
this.progress = (this.index + 1) * 100
|
||||
} else {
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'play'
|
||||
}
|
||||
}
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `300ms`)
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index)}px, 0px, 0px)`)
|
||||
}
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `300ms`)
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index)}px, 0px, 0px)`)
|
||||
}
|
||||
},
|
||||
getWidth(index) {
|
||||
@ -378,33 +457,35 @@ html {
|
||||
background: black;
|
||||
width: 100%;
|
||||
//height: 100%;
|
||||
height: calc(100vh - 5rem);
|
||||
overflow: auto;
|
||||
height: calc(100vh - 50rem);
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
font-size: 1.4rem;
|
||||
font-size: 14rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.img-slide-wrapper {
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.img-slide-list {
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.img-slide-item {
|
||||
min-width: 100vw;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
//transform-origin: left top;
|
||||
transform-origin: 0 0;
|
||||
width: 100vw;
|
||||
//position: absolute;
|
||||
//height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -431,22 +512,22 @@ html {
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
padding: 0 .5rem;
|
||||
padding: 0 5rem;
|
||||
justify-content: space-between;
|
||||
|
||||
.bar {
|
||||
border-radius: 1rem;
|
||||
border-radius: 10rem;
|
||||
flex: 1;
|
||||
margin: 0 .2rem;
|
||||
height: .2rem;
|
||||
margin: 0 2rem;
|
||||
height: 2rem;
|
||||
background: gray;
|
||||
position: relative;
|
||||
|
||||
.progress {
|
||||
border-radius: 1rem;
|
||||
border-radius: 10rem;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
height: .2rem;
|
||||
height: 2rem;
|
||||
background: white;
|
||||
//width: 100%;
|
||||
//animation: start 3s linear;
|
||||
|
||||
464
src/components/slide/SlideImgs2.vue
Normal file
464
src/components/slide/SlideImgs2.vue
Normal file
@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<div id="SlideImgs">
|
||||
<div class="img-slide-wrapper">
|
||||
<div class="img-slide-list"
|
||||
ref="list"
|
||||
@touchstart="start"
|
||||
@touchmove="move"
|
||||
@touchend="end">
|
||||
<div class="img-slide-item" v-for="img in modelValue.imgs">
|
||||
<img :ref="setItemRef" :src="img">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-bar" v-if="true">
|
||||
<div class="bar" v-for="(img,index) in modelValue.imgs">
|
||||
<div class="progress"
|
||||
:style="getProgressWidth(index)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import enums from "../../utils/enums";
|
||||
import globalMethods from '../../utils'
|
||||
//TODO 放大功能待完善
|
||||
export default {
|
||||
name: "SlideImgs",
|
||||
components: {},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
type: 'imgs',
|
||||
imgs: [
|
||||
new URL('../../assets/img/poster/0.jpg', import.meta.url).href,
|
||||
new URL('../../assets/img/poster/1.jpg', import.meta.url).href,
|
||||
new URL('../../assets/img/poster/2.jpg', import.meta.url).href,
|
||||
new URL('../../assets/img/poster/3.jpg', import.meta.url).href,
|
||||
],
|
||||
"id": "034ae83b-ca0a-401a-b7c6-cf78361bae7b",
|
||||
video: 'http://douyin.ttentau.top/0.mp4',
|
||||
"video_data_size": 26829508,
|
||||
"duration": 427780,
|
||||
"desc": "我不管我们宿舍第一好看",
|
||||
"allow_download": 0,
|
||||
"allow_duet": 0,
|
||||
"allow_react": 0,
|
||||
"allow_music": 1,
|
||||
"allow_douplus": 1,
|
||||
"allow_share": 1,
|
||||
"digg_count": 10480000,
|
||||
"comment_count": 79000,
|
||||
"download_count": 6,
|
||||
"play_count": 0,
|
||||
"share_count": 119000,
|
||||
"forward_count": 0,
|
||||
"collect_count": 3,
|
||||
"sort": 195,
|
||||
"is_top": 0,
|
||||
"city": "北京",
|
||||
address: '中央戏剧学院',
|
||||
"musicId": "2ee213c6-3e3f-4758-ba5a-7f1c955604a4",
|
||||
"create_time": "1630423555",
|
||||
"creator_id": "93864497380",
|
||||
"status": 1,
|
||||
"topics": [
|
||||
{
|
||||
"id": "85ceda30-898f-4b57-b891-0e58b3ab99a9",
|
||||
"name": "敬礼变装",
|
||||
"creator_id": "93864497380",
|
||||
"create_time": "1630423555",
|
||||
"status": 1
|
||||
},
|
||||
{
|
||||
"id": "85ceda30-898f-4b57-b891-0e58b3ab99a9",
|
||||
"name": "宿舍",
|
||||
"creator_id": "93864497380",
|
||||
"create_time": "1630423555",
|
||||
"status": 1
|
||||
}
|
||||
],
|
||||
"music": {
|
||||
"id": "cde50af2-628c-4d28-b9c6-67237a62518e",
|
||||
"cover": "https://p29.douyinpic.com/img/tos-cn-avt-0015/f4de202ff2e41b523838a4a767aebd16~c5_100x100.jpeg?from=116350172",
|
||||
"mp3": "https://sf3-cdn-tos.douyinstatic.com/obj/ies-music/1658584661080088.mp3",
|
||||
"title": "@穷电影创作的原声-小高快起来跳舞",
|
||||
"creator_id": "93864497380",
|
||||
"create_time": "1630423555",
|
||||
"status": 1
|
||||
},
|
||||
"author": {
|
||||
"id": "1",
|
||||
"unique_id_modify_time": "1630393144",
|
||||
"unique_id": "10040050",
|
||||
"favoriting_count": 143,
|
||||
"avatar": new URL('../../assets/img/icon/avatar/3.png', import.meta.url).href,
|
||||
school: {
|
||||
name: '中央戏剧学院',
|
||||
department: null,
|
||||
joinTime: null,
|
||||
education: null,
|
||||
displayType: enums.DISPLAY_TYPE.ALL,
|
||||
},
|
||||
"city": "",
|
||||
"province": '北京',
|
||||
"country": "",
|
||||
"location": "",
|
||||
"birthday": "2002-01-01",
|
||||
"cover": "https://p3.douyinpic.com/obj/c8510002be9a3a61aad2?from=116350172",
|
||||
"following_count": 66,
|
||||
"follower_count": 235000,
|
||||
"aweme_count": 1796000,
|
||||
"nickname": "我是小睿耶",
|
||||
certification: '',
|
||||
"phone": "",
|
||||
"sex": "",
|
||||
"last_login_time": "1630423555",
|
||||
"create_time": "1630423555",
|
||||
"status": 1,
|
||||
"desc": `一个普普通通学表演的\n看到的人都能开开心心`,
|
||||
"is_private": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
itemRefs: [],
|
||||
baseActiveIndex: 0,
|
||||
progress: 0,
|
||||
cycleFn: null,
|
||||
state: 'play',//stop,custom
|
||||
|
||||
startX: 0,
|
||||
startY: 0,
|
||||
|
||||
moveX: 0,
|
||||
moveY: 0,
|
||||
width: document.body.clientWidth,
|
||||
startTime: 0,
|
||||
index: 0,
|
||||
isDrawRight: false,
|
||||
isDrawDown: false,
|
||||
isTwo: false,
|
||||
store: {
|
||||
scale: 1
|
||||
},
|
||||
result: {
|
||||
width: 414,
|
||||
height: 737
|
||||
},
|
||||
x: 0,
|
||||
y: 79,
|
||||
scale: 1,
|
||||
maxScale: 3,
|
||||
minScale: 0.5,
|
||||
point1: {x: 0, y: 0},
|
||||
point2: {x: 0, y: 0},
|
||||
diff: {x: 0, y: 0},
|
||||
lastPointermove: {x: 0, y: 0},
|
||||
lastPoint1: {x: 0, y: 0},
|
||||
lastPoint2: {x: 0, y: 0},
|
||||
lastCenter: {x: 0, y: 0},
|
||||
a: {},
|
||||
b: {},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.width = document.body.clientWidth
|
||||
},
|
||||
watch: {
|
||||
state(newVal, oldVal) {
|
||||
return
|
||||
console.log('newVal', newVal)
|
||||
if (newVal === 'play') requestAnimationFrame(this.cycleFn)
|
||||
if (newVal === 'stop') cancelAnimationFrame(this.cycleFn)
|
||||
if (newVal === 'custom') cancelAnimationFrame(this.cycleFn)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.cycleFn = () => {
|
||||
if (this.state !== 'play') return cancelAnimationFrame(this.cycleFn)
|
||||
if (this.progress < this.modelValue.imgs.length * 100) {
|
||||
this.progress += .4
|
||||
this.index = parseInt(this.progress / 100)
|
||||
if (this.$refs.list) {
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `300ms`)
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index)}px, 0px, 0px)`)
|
||||
}
|
||||
} else {
|
||||
this.progress = 0
|
||||
// cancelAnimationFrame(this.cycleFn)
|
||||
}
|
||||
requestAnimationFrame(this.cycleFn)
|
||||
}
|
||||
// requestAnimationFrame(this.cycleFn)
|
||||
},
|
||||
methods: {
|
||||
getCenter(a, b) {
|
||||
const x = (a.x + b.x) / 2;
|
||||
const y = (a.y + b.y) / 2;
|
||||
return {x, y}
|
||||
},
|
||||
start(e) {
|
||||
console.log('start')
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'stop'
|
||||
}
|
||||
if (e.touches && e.touches.length === 1) {
|
||||
this.isTwo = false
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `0ms`)
|
||||
this.startX = e.touches[0].pageX
|
||||
this.startY = e.touches[0].pageY
|
||||
this.startTime = Date.now()
|
||||
} else {
|
||||
this.isTwo = true
|
||||
this.itemRefs[this.index].style['transition-duration'] = '0ms';
|
||||
|
||||
let events = e.touches[0];
|
||||
let events2 = e.touches[1];
|
||||
|
||||
if (e.cancelable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.lastPoint1 = this.point1 = {x: events.pageX, y: events.pageY};
|
||||
this.lastPoint2 = this.point2 = {x: events2.pageX, y: events2.pageY};
|
||||
|
||||
this.lastCenter = this.getCenter(this.lastPoint1, this.lastPoint2)
|
||||
}
|
||||
},
|
||||
move(e) {
|
||||
if (e.touches && e.touches.length === 1) {
|
||||
this.isTwo = false
|
||||
|
||||
this.moveX = e.touches[0].pageX - this.startX
|
||||
this.moveY = e.touches[0].pageY - this.startY
|
||||
|
||||
this.isDrawRight = this.moveX < 0
|
||||
this.isDrawDown = this.moveY < 0
|
||||
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index) +
|
||||
this.moveX}px, 0px, 0px)`)
|
||||
} else {
|
||||
this.isTwo = true
|
||||
if (e.cancelable) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
let current1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
let current2 = {x: e.touches[1].pageX, y: e.touches[1].pageY}
|
||||
|
||||
// 获取坐标之间的举例
|
||||
let getDistance = function (start, stop) {
|
||||
return Math.hypot(stop.x - start.x, stop.y - start.y);
|
||||
};
|
||||
|
||||
// 双指缩放比例计算
|
||||
let ratio = getDistance(current1, current2) / getDistance(this.lastPoint1, this.lastPoint2);
|
||||
|
||||
|
||||
// 计算当前双指中心点坐标
|
||||
let center = this.getCenter(current1, current2)
|
||||
console.log('center', center)
|
||||
|
||||
// 计算图片中心偏移量,默认transform-origin: 50% 50%
|
||||
// 如果transform-origin: 30% 40%,那origin.x = (ratio - 1) * result.width * 0.3
|
||||
// origin.y = (ratio - 1) * result.height * 0.4
|
||||
// 如果通过修改宽高或使用transform缩放,但将transform-origin设置为左上角时。
|
||||
// 可以不用计算origin,因为(ratio - 1) * result.width * 0 = 0
|
||||
const origin = {
|
||||
x: (ratio - 1) * this.result.width * 0.5,
|
||||
y: (ratio - 1) * this.result.height * 0.5
|
||||
};
|
||||
// 计算偏移量,认真思考一下为什么要这样计算(带入特定的值计算一下)
|
||||
this.x -= (ratio - 1) * (center.x - this.x) - origin.x - (center.x - this.lastCenter.x);
|
||||
this.y -= (ratio - 1) * (center.y - this.y) - origin.y - (center.y - this.lastCenter.y);
|
||||
|
||||
// console.log('this.x', this.x)
|
||||
// console.log('this.y', this.y)
|
||||
|
||||
// 图像应用缩放效果
|
||||
this.itemRefs[this.index].style.transform =
|
||||
`translate3d(${this.x}px,${this.y}px,0) scale(${this.store.scale * ratio})`;
|
||||
|
||||
this.lastCenter = {x: center.x, y: center.y};
|
||||
this.lastPoint1 = {x: current1.x, y: current1.y};
|
||||
this.lastPoint2 = {x: current2.x, y: current2.y};
|
||||
}
|
||||
},
|
||||
end(e) {
|
||||
console.log('end',e.touches)
|
||||
if (this.isTwo) {
|
||||
this.store.scale = 1
|
||||
this.itemRefs[this.index].style['transition-duration'] = '300ms';
|
||||
this.itemRefs[this.index].style.transform = `translate3d(0,0,0) scale(1)`;
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'play'
|
||||
}
|
||||
if (e.touches.length){
|
||||
this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (this.index === 0 && !this.isDrawRight) return
|
||||
if (this.index === this.modelValue.imgs.length - 1 && this.isDrawRight) return
|
||||
|
||||
let canSlide = this.width / 5 < Math.abs(this.moveX);
|
||||
if (Date.now() - this.startTime < 40) canSlide = false
|
||||
|
||||
if (canSlide) {
|
||||
if (this.isDrawRight) {
|
||||
this.index += 1
|
||||
} else {
|
||||
this.index -= 1
|
||||
}
|
||||
this.state = 'custom'
|
||||
this.progress = (this.index + 1) * 100
|
||||
} else {
|
||||
if (this.state !== 'custom') {
|
||||
this.state = 'play'
|
||||
}
|
||||
}
|
||||
globalMethods.$setCss(this.$refs.list, 'transition-duration', `300ms`)
|
||||
globalMethods.$setCss(this.$refs.list, 'transform',
|
||||
`translate3d(${-this.getWidth(this.index)}px, 0px, 0px)`)
|
||||
}
|
||||
},
|
||||
getWidth(index) {
|
||||
return index * this.width
|
||||
},
|
||||
setItemRef(el) {
|
||||
if (el) {
|
||||
this.itemRefs.push(el)
|
||||
}
|
||||
},
|
||||
beforeUpdate() {
|
||||
this.itemRefs = []
|
||||
},
|
||||
updated() {
|
||||
console.log(this.itemRefs)
|
||||
},
|
||||
toggle() {
|
||||
return
|
||||
if (this.state === 'stop') {
|
||||
this.state = 'play'
|
||||
requestAnimationFrame(this.cycleFn)
|
||||
} else {
|
||||
this.state = 'stop'
|
||||
}
|
||||
},
|
||||
getProgressWidth(index) {
|
||||
if (this.progress >= (index + 1) * 100) return {width: '100%'}
|
||||
return {width: `${this.progress - index * 100 < 0 ? 0 : this.progress - index * 100}%`}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
html {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#SlideImgs {
|
||||
position: relative;
|
||||
background: black;
|
||||
width: 100%;
|
||||
//height: 100%;
|
||||
height: calc(100vh - 5rem);
|
||||
overflow: auto;
|
||||
color: white;
|
||||
font-size: 1.4rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.img-slide-wrapper {
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
|
||||
.img-slide-list {
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
|
||||
.img-slide-item {
|
||||
min-width: 100vw;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
//transform-origin: left top;
|
||||
width: 100vw;
|
||||
//position: absolute;
|
||||
//height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100vw;
|
||||
|
||||
.base-slide-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
padding: 0 .5rem;
|
||||
justify-content: space-between;
|
||||
|
||||
.bar {
|
||||
border-radius: 1rem;
|
||||
flex: 1;
|
||||
margin: 0 .2rem;
|
||||
height: .2rem;
|
||||
background: gray;
|
||||
position: relative;
|
||||
|
||||
.progress {
|
||||
border-radius: 1rem;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
height: .2rem;
|
||||
background: white;
|
||||
//width: 100%;
|
||||
//animation: start 3s linear;
|
||||
|
||||
@keyframes start {
|
||||
0% {
|
||||
width: 0;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -8,7 +8,8 @@ import router from "./router";
|
||||
import store from "./store";
|
||||
import mixin from "./utils/mixin";
|
||||
import VueLazyload from '@jambonn/vue-lazyload'
|
||||
|
||||
import VConsole from 'vconsole';
|
||||
const vConsole = new VConsole();
|
||||
|
||||
const app = Vue.createApp(App)
|
||||
app.config.globalProperties.$api = {...api}
|
||||
|
||||
@ -50,7 +50,6 @@ export default {
|
||||
next: false,
|
||||
startTime: null,
|
||||
appInsMap: new Map()
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref, watch} from "vue";
|
||||
import GM from '../../utils'
|
||||
import {getSlideDistance, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {getSlideDistance, slideInit, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
import Utils from "../../utils";
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
@ -26,11 +27,9 @@ const state = reactive({
|
||||
wrapper: {width: 0, height: 0, childrenLength: 0}
|
||||
})
|
||||
|
||||
// 单个 ref
|
||||
watch(
|
||||
() => props.index,
|
||||
(newVal) => {
|
||||
console.log('w')
|
||||
if (state.localIndex !== newVal) {
|
||||
state.localIndex = newVal
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
@ -40,9 +39,7 @@ watch(
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
state.wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
state.wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
slideInit(wrapperEl.value,state,SlideType.HORIZONTAL)
|
||||
})
|
||||
|
||||
function touchStart(e) {
|
||||
@ -68,7 +65,7 @@ function canNext(isNext) {
|
||||
|
||||
<template>
|
||||
<div class="slide">
|
||||
<div class="slide-wrapper"
|
||||
<div class="slide-list"
|
||||
ref="wrapperEl"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {onMounted, reactive, ref,watch} from "vue";
|
||||
import GM from '../../utils'
|
||||
import {slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {getSlideDistance, slideInit, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
|
||||
const props = defineProps({
|
||||
@ -18,7 +18,7 @@ const judgeValue = 20
|
||||
const wrapperEl = ref(null)
|
||||
const state = reactive({
|
||||
name: 'SlideVertical',
|
||||
localIndex: 0,
|
||||
localIndex: props.index,
|
||||
needCheck: true,
|
||||
next: false,
|
||||
start: {x: 0, y: 0, time: 0},
|
||||
@ -26,10 +26,19 @@ const state = reactive({
|
||||
wrapper: {width: 0, height: 0, childrenLength: 0}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.index,
|
||||
(newVal) => {
|
||||
if (state.localIndex !== newVal) {
|
||||
state.localIndex = newVal
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
GM.$setCss(wrapperEl.value, 'transform', `translate3d(0,${getSlideDistance(state, SlideType.VERTICAL)}px, 0)`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
state.wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
state.wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
slideInit(wrapperEl.value, state, SlideType.VERTICAL)
|
||||
})
|
||||
|
||||
function touchStart(e) {
|
||||
@ -55,7 +64,7 @@ function canNext(isNext) {
|
||||
|
||||
<template>
|
||||
<div class="slide">
|
||||
<div class="slide-wrapper flex-direction-column"
|
||||
<div class="slide-list flex-direction-column"
|
||||
ref="wrapperEl"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
<script setup lang="jsx">
|
||||
import {onMounted, reactive, ref, watch, createApp} from "vue";
|
||||
import GM from '../../utils'
|
||||
import {slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {getSlideDistance, slideInit, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
import SlideItem from './SlideItem'
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
@ -11,14 +12,35 @@ const props = defineProps({
|
||||
return 0
|
||||
}
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
render: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return null
|
||||
}
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
virtualTotal: {
|
||||
type: Number,
|
||||
default: () => 5
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:index'])
|
||||
|
||||
const appInsMap = new Map()
|
||||
const judgeValue = 20
|
||||
const wrapperEl = ref(null)
|
||||
const state = reactive({
|
||||
name: 'SlideVertical',
|
||||
localIndex: 0,
|
||||
name: 'SlideVerticalInfinite',
|
||||
localIndex: props.index,
|
||||
needCheck: true,
|
||||
next: false,
|
||||
start: {x: 0, y: 0, time: 0},
|
||||
@ -26,12 +48,77 @@ const state = reactive({
|
||||
wrapper: {width: 0, height: 0, childrenLength: 0}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.index,
|
||||
(newVal) => {
|
||||
if (state.localIndex !== newVal) {
|
||||
state.localIndex = newVal
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
GM.$setCss(wrapperEl.value, 'transform', `translate3d(0,${getSlideDistance(state, SlideType.VERTICAL)}px, 0)`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
state.wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
state.wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
slideInit(wrapperEl.value, state, SlideType.VERTICAL)
|
||||
insertContent()
|
||||
})
|
||||
|
||||
//默认使用this.list,刷新时,考虑到vue可能更新外面的videos到this.list数据没有那么快,因为我要立即刷新
|
||||
function insertContent(list = props.list) {
|
||||
let start = 0
|
||||
let that = this
|
||||
|
||||
if (state.localIndex >= (props.virtualTotal - 1) / 2) {
|
||||
start = state.localIndex - (props.virtualTotal - 1) / 2
|
||||
}
|
||||
let end = start + 5
|
||||
if (end >= list.length) {
|
||||
end = list.length
|
||||
start = end - 5
|
||||
}
|
||||
if (start < 0) start = 0
|
||||
// console.log('start', start)
|
||||
// console.log('end', end)
|
||||
list.slice(start, end).map(
|
||||
(item, index) => {
|
||||
//自动播放,当前条(可能是0,可能是其他),试了下用jq来找元素,然后trigger play事件,要慢点样
|
||||
let el = getInsEl(item, start + index, start + index === state.localIndex)
|
||||
wrapperEl.value.appendChild(el)
|
||||
}
|
||||
)
|
||||
GM.$setCss(wrapperEl.value, 'transform', `translate3d(0px,
|
||||
${-state.localIndex * state.wrapper.height}px, 0px)`)
|
||||
|
||||
if (state.localIndex > 2 && list.length > 5) {
|
||||
$(wrapperEl.value).find(".slide-item").each(function () {
|
||||
if ((list.length - state.localIndex) > 2) {
|
||||
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
|
||||
} else {
|
||||
$(this).css('top', start * state.wrapper.height)
|
||||
}
|
||||
})
|
||||
}
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
}
|
||||
|
||||
function getInsEl(item, index, play = false) {
|
||||
// console.log('index',index,play)
|
||||
let slideVNode = props.render(item, index, play, props.prefix)
|
||||
const app = createApp({
|
||||
render() {
|
||||
return <SlideItem>{slideVNode}</SlideItem>
|
||||
// return slideVNode
|
||||
}
|
||||
})
|
||||
const parent = document.createElement('div')
|
||||
const ins = app.mount(parent)
|
||||
appInsMap.set(index, app)
|
||||
// this.appInsMap.set(index, ins)
|
||||
return ins.$el
|
||||
}
|
||||
|
||||
|
||||
function touchStart(e) {
|
||||
slideTouchStart(e, wrapperEl.value, state)
|
||||
}
|
||||
@ -55,7 +142,7 @@ function canNext(isNext) {
|
||||
|
||||
<template>
|
||||
<div class="slide">
|
||||
<div class="slide-wrapper flex-direction-column"
|
||||
<div class="slide-list flex-direction-column"
|
||||
ref="wrapperEl"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
|
||||
@ -1,11 +1,22 @@
|
||||
import bus from "../../utils/bus";
|
||||
import Utils from '../../utils'
|
||||
import GM from "../../utils";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
import GM from "../../utils";
|
||||
|
||||
export function slideInit(el, state, type) {
|
||||
state.wrapper.width = GM.$getCss(el, 'width')
|
||||
state.wrapper.height = GM.$getCss(el, 'height')
|
||||
state.wrapper.childrenLength = el.children.length
|
||||
|
||||
let t = getSlideDistance(state, type)
|
||||
let dx1 = 0, dx2 = 0
|
||||
if (type === SlideType.HORIZONTAL) dx1 = t
|
||||
else dx2 = t
|
||||
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
}
|
||||
|
||||
export function slideTouchStart(e, el, state) {
|
||||
GM.$setCss(el, 'transition-duration', `0ms`)
|
||||
Utils.$setCss(el, 'transition-duration', `0ms`)
|
||||
state.start.x = e.touches[0].pageX
|
||||
state.start.y = e.touches[0].pageY
|
||||
state.start.time = Date.now()
|
||||
@ -35,7 +46,7 @@ export function slideTouchMove(e, el, state, judgeValue, cb, type = SlideType.HO
|
||||
|
||||
if (canSlide(state, judgeValue, type)) {
|
||||
bus.emit(state.name + '-moveX', state.move.x)
|
||||
GM.$stopPropagation(e)
|
||||
Utils.$stopPropagation(e)
|
||||
let t = getSlideDistance(state, type) + (isNext ? judgeValue : -judgeValue)
|
||||
let dx1 = 0
|
||||
let dx2 = 0
|
||||
@ -44,7 +55,7 @@ export function slideTouchMove(e, el, state, judgeValue, cb, type = SlideType.HO
|
||||
} else {
|
||||
dx2 = t + state.move.y
|
||||
}
|
||||
GM.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +65,7 @@ export function slideTouchEnd(e, state, canNextCb, nextCb, type = SlideType.HORI
|
||||
|
||||
if (!canNextCb?.(isNext)) return
|
||||
if (state.next) {
|
||||
GM.$stopPropagation(e)
|
||||
Utils.$stopPropagation(e)
|
||||
let endTime = Date.now()
|
||||
let gapTime = endTime - state.start.time
|
||||
let distance = isHorizontal ? state.move.x : state.move.y
|
||||
@ -82,7 +93,7 @@ export function slideReset(el, state, type, emit) {
|
||||
} else {
|
||||
dx2 = t
|
||||
}
|
||||
GM.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
state.start.x = state.start.y = state.start.time = state.move.x = state.move.y = 0
|
||||
state.next = false
|
||||
state.needCheck = true
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="slide2">
|
||||
<H class="h" v-model:index="state.baseIndex">
|
||||
<div class="test-slide-wrapper">
|
||||
<H v-model:index="state.baseIndex">
|
||||
<SlideItem class="slide-item gray">
|
||||
<H class="h" v-model:index="state.index">
|
||||
<H class="h" v-model:index="state.navIndex">
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big">找红包</div>
|
||||
</SlideItem>
|
||||
@ -19,42 +19,108 @@
|
||||
<div class="big">商城</div>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item">
|
||||
<VInfinite>
|
||||
<SlideItem class="slide-item red"></SlideItem>
|
||||
<SlideItem class="slide-item yellow"></SlideItem>
|
||||
<SlideItem class="slide-item blue"></SlideItem>
|
||||
<VInfinite
|
||||
v-model:index="state.index"
|
||||
:render="render"
|
||||
:list="state.recommendVideos"
|
||||
:prefix="state.videoPrefix[0]"
|
||||
>
|
||||
</VInfinite>
|
||||
</SlideItem>
|
||||
</H>
|
||||
<div>
|
||||
<span>{{ state.baseIndex }}</span>
|
||||
<button @click="state.baseIndex++">加</button>
|
||||
<button @click="state.baseIndex--">减</button>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ state.navIndex }}</span>
|
||||
<button @click="state.navIndex++">加</button>
|
||||
<button @click="state.navIndex--">减</button>
|
||||
</div>
|
||||
<Footer v-bind:init-tab="1"/>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big" v-for="i in 100">主页</div>
|
||||
</SlideItem>
|
||||
</H>
|
||||
<span>{{ state.baseIndex }}</span>
|
||||
<button @click="state.baseIndex++">加</button>
|
||||
<button @click="state.baseIndex--">减</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="jsx">
|
||||
import H from './H'
|
||||
import V from './V'
|
||||
import VInfinite from './VInfinite.vue'
|
||||
import SlideItem from './SlideItem'
|
||||
import SlideVideo from "../../components/slide/SlideVideo";
|
||||
import SlideUser from "../../components/slide/SlideUser";
|
||||
import SlideImgs from "../../components/slide/SlideImgs";
|
||||
import resource from "../../assets/data/resource.js";
|
||||
import {reactive} from "vue";
|
||||
|
||||
const state = reactive({
|
||||
baseIndex: 1,
|
||||
index: 1
|
||||
baseIndex: 0,
|
||||
navIndex: 5,
|
||||
index: 0,
|
||||
recommendVideos: [
|
||||
{
|
||||
type: 'img',
|
||||
src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}`
|
||||
},
|
||||
{
|
||||
type: 'imgs',
|
||||
src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}`
|
||||
},
|
||||
],
|
||||
videoPrefix: ['one', 'two', 'three'],
|
||||
})
|
||||
|
||||
|
||||
function render(item, itemIndex, play) {
|
||||
let node
|
||||
if (item.type === 'img') {
|
||||
node = <img src={item.src} style="height:100%;"/>
|
||||
}
|
||||
if (item.type === 'imgs') {
|
||||
node = <SlideImgs/>
|
||||
}
|
||||
return node
|
||||
// return <SlideItem class="slide-item gray">{node}</SlideItem>
|
||||
}
|
||||
|
||||
// function render1(item, itemIndex, play) {
|
||||
// let node
|
||||
// if (item.type === 'recommend-video') {
|
||||
// node = <SlideVideo
|
||||
// isPlay={play}
|
||||
// video={item}
|
||||
// index={itemIndex}
|
||||
// onShowComments={e => this.isCommenting = true}
|
||||
// onShowShare={e => this.isSharing = true}
|
||||
// onGoUserInfo={e => this.baseActiveIndex = 1}
|
||||
// onGoMusic={e => this.$nav('/home/music')}
|
||||
// v-model={[this.videos[itemIndex], 'video']}
|
||||
// />
|
||||
// }
|
||||
// if (item.type === 'img') {
|
||||
// node = <img src={item.src} style="height:100%;"/>
|
||||
// }
|
||||
// if (item.type === 'imgs') {
|
||||
// node = <SlideImgs/>
|
||||
// }
|
||||
// if (item.type === 'send-video') {
|
||||
// node = <video src={item.src} style="height:100%;"/>
|
||||
// }
|
||||
// if (item.type === 'user') {
|
||||
// node = <SlideUser onClose={this.t} modelValue={item}/>
|
||||
// }
|
||||
// return node
|
||||
// }
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.slide2 {
|
||||
.test-slide-wrapper {
|
||||
font-size: 14rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
<template>
|
||||
<!-- <TestSlide></TestSlide>-->
|
||||
<!-- <SlideUser></SlideUser>-->
|
||||
<!-- <SlideImgs></SlideImgs>-->
|
||||
<!-- <TestImg/>-->
|
||||
<slideHooks></slideHooks>
|
||||
<SlideImgs></SlideImgs>
|
||||
<!-- <TestImg/>-->
|
||||
<!-- <slideHooks></slideHooks>-->
|
||||
|
||||
<!-- <div class="body">-->
|
||||
<!-- <div class="wrapper">-->
|
||||
<!-- <img :src="src" id="img">-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@ -13,6 +19,7 @@ import SlideUser from "../../components/slide/SlideUser";
|
||||
import SlideImgs from "../../components/slide/SlideImgs";
|
||||
import TestImg from "./TestImg";
|
||||
import slideHooks from '../slideHooks'
|
||||
import {mat4} from "gl-matrix";
|
||||
|
||||
export default {
|
||||
name: "Test",
|
||||
@ -23,5 +30,43 @@ export default {
|
||||
SlideImgs,
|
||||
TestImg
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
src: '',
|
||||
rect: {x: 0, y: 0}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
wheel() {
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
.body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background: black;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img {
|
||||
transform-origin: 0 0;
|
||||
max-width: 1040px;
|
||||
max-height: 600px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -83,6 +83,9 @@ export default {
|
||||
|
||||
|
||||
this.scale = this.scale * ratio
|
||||
console.log('ratio',ratio)
|
||||
console.log('scale',this.scale)
|
||||
|
||||
// 计算当前双指中心点坐标
|
||||
let center = this.getCenter(current1, current2)
|
||||
// console.log('center', center)
|
||||
@ -120,7 +123,6 @@ export default {
|
||||
|
||||
this.$refs.img.style.transform = `translate3d(0px,0px,0) scale(1)`;
|
||||
// this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ import Slide from "../pages/slide/Slide";
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/home'
|
||||
redirect: '/test'
|
||||
},
|
||||
{path: '/slide', component: Slide},
|
||||
{path: '/test', component: Test},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user