@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
< template >
< div id = "SlideImgs" >
< div class = "img-slide-wrapper" ref = "wap" >
< div class = "img-slide-wrapper" >
< div class = "img-slide-list"
ref = "list "
@ touchstart = "touchs tart"
@ touchmove = "touchm ove"
@ touchend = "touche nd" >
< div class = "img-slide-item" v-for ="img in modelValue.imgs" >
ref = "wrapperE l"
@ touchstart = "touchS tart"
@ touchmove = "touchM ove"
@ touchend = "touchE nd" >
< div class = "img-slide-item" v-for ="img in props. modelValue.imgs" >
< img :ref ="setItemRef" :src ="img" >
< / div >
< / div >
@ -20,11 +20,20 @@
@@ -20,11 +20,20 @@
< / div >
< / template >
< script >
< script setup lang = "jsx" >
import enums from "../../utils/enums" ;
import globalMethod s from '../../utils'
import Util s from '../../utils'
import { mat4 } from 'gl-matrix'
import { cloneDeep } from "lodash" ;
import { onMounted , reactive , ref } from "vue" ;
import {
getSlideDistance ,
slideInit ,
slideReset ,
slideTouchEnd ,
slideTouchMove ,
slideTouchStart
} from "../../pages/slideHooks/common" ;
import { SlideType } from "../../utils/const_var" ;
let out = new Float32Array ( [
0 , 0 , 0 , 0 ,
@ -38,12 +47,8 @@ let ov = new Float32Array([
@@ -38,12 +47,8 @@ let ov = new Float32Array([
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 ,
] ) ;
let original = cloneDeep ( ov )
const rectMap = new Map ( )
export default {
name : "SlideImgs" ,
components : { } ,
props : {
const props = defineProps ( {
modelValue : {
type : Object ,
default ( ) {
@ -141,323 +146,192 @@ export default {
@@ -141,323 +146,192 @@ export default {
}
}
}
} ,
data ( ) {
return {
itemRefs : [ ] ,
baseActiveIndex : 0 ,
progress : 0 ,
cycleFn : null ,
state : 'play' , / / s t o p , c u s t o m
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 } ,
startCenter : { x : 0 , y : 0 } ,
a : { } ,
b : { } ,
} )
const judgeValue = 20
const wrapperEl = ref ( null )
const state = reactive ( {
name : 'SlideHorizontal' ,
localIndex : 0 ,
needCheck : true ,
isTwo : true ,
next : false ,
wrapper : { width : 0 , height : 0 , childrenLength : 0 } ,
last : {
ratio : 1 ,
point1 : { x : 0 , y : 0 } ,
point2 : { x : 0 , y : 0 } ,
} ,
start : {
x : 0 , y : 0 ,
point1 : { x : 0 , y : 0 } ,
point2 : { x : 0 , y : 0 } ,
}
}
center : { x : 0 , y : 0 } ,
time : 0
} ,
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) ` )
move : { x : 0 , y : 0 } ,
itemRefs : [ ] ,
status : 'play' , / / s t o p , c u s t o m
progress : 0 ,
cycleFn : null ,
} )
onMounted ( ( ) => {
slideInit ( wrapperEl . value , state , SlideType . HORIZONTAL )
state . cycleFn = ( ) => {
if ( state . status !== 'play' ) return cancelAnimationFrame ( state . cycleFn )
if ( state . progress < props . modelValue . imgs . length * 100 ) {
state . progress += .4
state . localIndex = parseInt ( state . progress / 100 )
if ( wrapperEl . value ) {
Utils . $setCss ( wrapperEl . value , 'transition-duration' , ` 300ms ` )
Utils . $setCss ( wrapperEl . value , 'transform' , ` translate3d( ${ getSlideDistance ( state ) } px, 0px, 0px) ` )
}
} else {
this . progress = 0
state . progress = 0
/ / c a n c e l A n i m a t i o n F r a m e ( t h i s . c y c l e F n )
}
requestAnimationFrame ( this . cycleFn )
requestAnimationFrame ( state . cycleFn )
}
return
/ / r e q u e s t A n i m a t i o n F r a m e ( t h i s . c y c l e F n )
requestAnimationFrame ( state . 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 ( ) } ) ` ;
/ / i m a g e . s e t A t t r i b u t e ( " s t y l e " , ` t r a n s f o r m : m a t r i x 3 d ( $ { o v . t o S t r i n g ( ) } ) ; ` ) ;
} )
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 ) {
const x = ( a . x + b . x ) / 2 ;
const y = ( a . y + b . y ) / 2 ;
return { x , y }
} ,
/ / 获 取 坐 标 之 间 的 举 例
getDistance ( start , stop ) {
return Math . hypot ( stop . x - start . x , stop . y - start . y ) ;
} ,
touchstart ( e ) {
function touchStart ( e ) {
console . log ( 'start' , e . touches . length )
if ( this . state !== 'custom' ) {
this . state = 'stop '
}
/ / i f ( s . s t a t e ! = = ' c u s t o m ' ) {
/ / t h i s . s t a t e = ' s t o p '
/ / }
if ( 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 ( )
state . isTwo = false
slideTouchStart ( e , wrapperEl . value , state )
} else {
if ( this . isTwo ) return
this . isTwo = true
this . itemRefs [ this . i ndex] . style [ 'transition-duration' ] = '0ms' ;
if ( e . cancelable ) {
e . preventDefault ( ) ;
if ( state . isTwo ) return
state . isTwo = true
state . itemRefs [ state . localIndex ] . style [ 'transition-duration' ] = '0ms' ;
state . last . point1 = state . start . point1 = { x : e . touches [ 0 ] . pageX , y : e . touches [ 0 ] . pageY } ;
state . last . point2 = state . start . point2 = { x : e . touches [ 1 ] . pageX , y : e . touches [ 1 ] . pageY } ;
state . start . center = Utils . getCenter ( state . start . point1 , state . start . point2 )
}
}
function touchMove ( e ) {
/ / c o n s o l e . l o g ( ' m o v e ' , e . t o u c h e s . l e n g t h )
if ( state . isTwo && e . touches . length === 1 ) {
state . status = 'pause'
Utils . $stopPropagation ( e )
this . last . point1 = this . point1 = { x : e . touches [ 0 ] . pageX , y : e . touches [ 0 ] . pageY } ;
this . last . point2 = this . point2 = { x : e . touches [ 1 ] . pageX , y : e . touches [ 1 ] . pageY } ;
this . startCenter = this . getCenter ( this . point1 , this . point2 )
}
} ,
touchmove ( e ) {
console . log ( 'move' , e . touches . length )
if ( this . isTwo && e . touches . length === 1 ) {
/ / c o n s o l e . l o g ( ' 单 手 移 动 ' , )
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 )
let movementX = current . x - state . last . point1 . x
let movementY = current . y - state . last . point1 . y
/ / c o n s o l e . l o g ( m o v e m e n t X , m o v e m e n t Y )
const t = new Float32Array ( [ 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , movementX , movementY , 0 , 1 , ] ) ;
let ov1 = mat4 . multiply ( out , t , ov ) ;
this . itemRefs [ this . i ndex] . style . transform = ` matrix3d( ${ ov1 . toString ( ) } ) ` ;
/ / t h i s . l a s t . p o i n t 1 = c u r r e n t
ov = mat4 . multiply ( out , t , ov ) ;
state . itemRefs [ state . localIndex ] . style . transform = ` matrix3d( ${ ov . toString ( ) } ) ` ;
state . last . point1 = current
} else {
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
state . isTwo = false
slideTouchMove ( e , wrapperEl . value , state , judgeValue , canNext , ( ) => {
state . status = 'pause'
} , SlideType . HORIZONTAL )
} else {
state . isTwo = true
Utils . $stopPropagation ( e )
state . status = 'pause'
globalMethods . $setCss ( this . $refs . list , 'transform' ,
` translate3d( ${ - this . getWidth ( this . index ) +
this . moveX } px , 0 px , 0 px ) ` )
let rect = { x : 0 , y : 0 }
if ( rectMap . has ( state . localIndex ) ) {
rect = rectMap . get ( state . localIndex )
} else {
this . isTwo = true
if ( e . cancelable ) {
e . preventDefault ( ) ;
/ / g e t B o u n d i n g C l i e n t R e c t 在 手 机 上 获 取 不 到 值
let offset = $ ( state . itemRefs [ state . localIndex ] ) . offset ( )
rect = { x : offset . left , y : offset . top }
rectMap . set ( state . localIndex , rect )
}
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 = thi s. getDistance ( current1 , current2 ) / thi s. getDistance ( this . point1 , this . point2 ) ;
let currentRatio = Utils . getDistance ( current1 , current2 ) / Utils . getDistance ( state . start . point1 , state . start . point2 ) ;
let rect = { x : 0 , y : 0 }
if ( rectMap . has ( this . index ) ) {
rect = rectMap . get ( this . index )
} else {
/ / g e t B o u n d i n g C l i e n t R e c t 在 手 机 上 获 取 不 到 值
let offset = $ ( this . itemRefs [ this . index ] ) . offset ( )
rect . x = offset . left
rect . y = offset . top
rectMap . set ( this . index , rect )
}
let center = Utils . getCenter ( current1 , current2 )
let center = cloneDeep ( this . startCenter )
center . x -= rect . x
center . y -= rect . y
let zoom = ratio
/ / 用 最 新 的 放 大 倍 数 r a t i o 除 以 之 前 的 放 大 o v [ 0 ] 倍 数 , 算 出 本 次 要 累 加 放 大 的 倍 数
let zoom = currentRatio / ov [ 0 ]
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 , ] ) ;
/ / 如 果 z o o m 是 累 加 放 大 ( 比 如 每 次 都 是 0 . 1 5 ) , 第 三 个 参 数 用 o v
/ / 但 这 里 z o o m 是 每 次 都 是 最 后 放 大 倍 数 , 第 三 个 参 数 用 原 值 ( 即 , 矩 阵 x 乘 时 , 都 是 乘 以 单 位 矩 阵 )
ov = mat4 . multiply ( out , t , original ) ;
/ / 如 果 z o o m 是 每 次 都 是 最 后 放 大 倍 数 , 第 三 个 参 数 用 原 值 ( 即 , 矩 阵 x 乘 时 , 都 是 乘 以 单 位 矩 阵 )
/ / 如 果 z o o m 是 累 加 放 大 ( 比 如 每 次 都 是 0 . 1 5 ) , 第 三 个 参 数 用 o v 。 这 里 还 是 采 用 累 加 计 算
ov = mat4 . multiply ( out , t , ov ) ;
let movementX = current1 . x - this . last . point1 . x
let movementY = current1 . y - this . last . point1 . y
let movement2X = current2 . x - this . last . point2 . x
let movement2Y = current2 . y - this . last . point2 . y
let movementRatio = currentRatio - ov [ 0 ]
/ / 如 果 本 次 比 例 和 上 次 的 不 超 过 0 . 0 2 。 那 么 判 定 为 平 移
if ( Math . abs ( movementRatio ) <= 0.02 ) {
let movementX = current1 . x - state . last . point1 . x
let movementY = current1 . y - state . last . point1 . y
let movement2X = current2 . x - state . last . point2 . x
let movement2Y = current2 . y - state . last . point2 . y
let minX = Math . min ( movementX , movement2X )
let minY = Math . min ( movementY , movement2Y )
const t1 = new Float32Array ( [ 1 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , minX , minY , 0 , 1 , ] ) ;
ov = mat4 . multiply ( out , t1 , ov ) ;
}
console . log ( 'minX' , minX , 'minY' , minY )
this . itemRefs [ this . index ] . style . transform = ` matrix3d( ${ ov . toString ( ) } ) ` ;
this . last . point1 = current1
this . last . point2 = current2
state . itemRefs [ state . localIndex ] . style . transform = ` matrix3d( ${ ov . toString ( ) } ) ` ;
state . last . point1 = current1
state . last . point2 = current2
}
}
} ,
touchend ( e ) {
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 . isTwo ) {
ov = original
this . itemRefs [ this . index ] . style [ 'transition-duration' ] = '300ms' ;
this . itemRefs [ this . index ] . style . transform = ` matrix3d( ${ ov . toString ( ) } ) ` ;
/ / i f ( t h i s . s t a t e ! = = ' c u s t o m ' ) {
/ / t h i s . s t a t e = ' p l a y '
/ / }
/ / i f ( e . t o u c h e s . l e n g t h ) {
/ / t h i s . p o i n t 1 = { x : e . t o u c h e s [ 0 ] . p a g e X , y : e . t o u c h e s [ 0 ] . p a g e Y }
/ / }
}
function touchEnd ( e ) {
console . log ( 'end' , e . touches . length , state . isTwo )
/ / 双 指 缩 放 , 但 只 松 开 了 一 只 手
if ( state . isTwo && e . touches . length === 1 ) {
Utils . $stopPropagation ( e )
state . 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
let canSlide = this . width / 5 < Math . abs ( this . moveX ) ;
if ( Date . now ( ) - this . startTime < 40 ) canSlide = false
if ( state . isTwo ) {
Utils . $stopPropagation ( e )
state . itemRefs [ state . localIndex ] . style [ 'transition-duration' ] = '300ms' ;
state . itemRefs [ state . localIndex ] . style . transform = ` matrix3d( ${ ov . toString ( ) } ) ` ;
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
slideTouchEnd ( e , state , canNext ,
( ) => {
state . status = 'custom'
state . progress = ( state . localIndex + 1 ) * 100
} ,
setItemRef ( el ) {
if ( el ) {
this . itemRefs . push ( el )
( ) => {
if ( state . status !== 'custom' ) {
state . status = 'play'
requestAnimationFrame ( state . cycleFn )
}
} ,
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 } % ` }
)
slideReset ( wrapperEl . value , state , SlideType . HORIZONTAL , null )
}
}
}
function getProgressWidth ( index ) {
if ( state . progress >= ( index + 1 ) * 100 ) return { width : '100%' }
return { width : ` ${ state . progress - index * 100 < 0 ? 0 : state . progress - index * 100 } % ` }
}
function setItemRef ( el ) {
el && state . itemRefs . push ( el )
}
function canNext ( isNext ) {
return ! ( ( state . localIndex === 0 && ! isNext ) || ( state . localIndex === props . modelValue . imgs . length - 1 && isNext ) ) ;
}
< / script >
< style scoped lang = "less" >
@ -469,14 +343,10 @@ html {
@@ -469,14 +343,10 @@ html {
position : relative ;
background : black ;
width : 100 % ;
/ / h e i g h t : 1 0 0 % ;
height : calc ( 100 vh - 50 rem ) ;
height : 100 % ;
overflow : hidden ;
color : white ;
font - size : 14 rem ;
display : flex ;
align - items : center ;
justify - content : center ;
. img - slide - wrapper {
height : 100 % ;
@ -498,30 +368,15 @@ html {
@@ -498,30 +368,15 @@ html {
img {
transform - origin : 0 0 ;
width : 100 vw ;
}
}
width : 100 % ;
}
}
. content {
width : 100 vw ;
. base - slide - item {
display : flex ;
align - items : center ;
justify - content : center ;
}
img {
width : 100 vw ;
}
}
. progress - bar {
position : absolute ;
width : 100 vw ;
width : 100 % ;
bottom : 0 ;
display : flex ;
box - sizing : border - box ;