Adapt to mobile devices

This commit is contained in:
zyronon
2023-12-12 01:57:35 +08:00
parent c34ba02248
commit afc5438f38
31 changed files with 1233 additions and 63 deletions

View File

@@ -169,7 +169,7 @@ function changeSort(v: Sort, notice: boolean = true) {
function option(type: string) {
show = false
setTimeout(() => {
router.push({path: '/dict', query: {type: type}})
router.push({path: '/pc/dict', query: {type: type}})
}, 500)
}

View File

@@ -0,0 +1,106 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import GM from '@/utils/gm.js'
import {
getSlideDistance,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from "./common";
import {SlideType} from "@/types.ts";
const props = defineProps({
index: {
type: Number,
default: () => {
return 0
}
},
name: {
type: String,
default: () => ''
},
//改变index是否使用动画
changeActiveIndexUseAnim: {
type: Boolean,
default: true
},
anim: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['update:index'])
const judgeValue = 20
const wrapperEl = ref(null)
const state = reactive({
name: props.name,
localIndex: props.index,
needCheck: true,
next: false,
start: {x: 0, y: 0, time: 0},
move: {x: 0, y: 0},
wrapper: {width: 0, height: 0, childrenLength: 0},
slideItemsWidths:[]
})
watch(
() => props.index,
(newVal) => {
if (state.localIndex !== newVal) {
state.localIndex = newVal
if (props.changeActiveIndexUseAnim) {
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
}
GM.$setCss(wrapperEl.value, 'transform', `translate3d(${getSlideDistance(state, SlideType.HORIZONTAL)}px, 0, 0)`)
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.HORIZONTAL)
})
function touchStart(e) {
if (!props.anim) return
slideTouchStart(e, wrapperEl.value, state)
}
function touchMove(e) {
if (!props.anim) return
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, null, SlideType.HORIZONTAL)
}
function touchEnd(e) {
if (!props.anim) return
slideTouchEnd(e, state, canNext, () => {
})
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, emit)
}
function canNext(isNext) {
if (isNext){
return state.localIndex !== state.wrapper.childrenLength - 1
}else {
return state.localIndex !== 0
}
}
</script>
<template>
<div class="slide hhhh">
<div class="slide-list"
ref="wrapperEl"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<slot></slot>
</div>
</div>
</template>

View File

@@ -0,0 +1,18 @@
<template>
<div class="slide-item">
<slot></slot>
</div>
</template>
<script setup>
</script>
<style lang="scss">
.slide-item {
height: 100%;
width: 100%;
flex-shrink: 0;
position: relative;
}
</style>

View File

@@ -0,0 +1,135 @@
import {emitter as bus} from "@/utils/eventBus.ts";
import Utils from '@/utils/gm.js'
import {SlideType} from "@/types.ts";
import GM from "@/utils/gm.js";
export function slideInit(el, state, type) {
state.wrapper.width = GM.$getCss(el, 'width')
state.wrapper.height = GM.$getCss(el, 'height')
let els = el.children
state.wrapper.childrenLength = els.length
for (let i = 0; i < els.length; i++) {
let el = els[i]
state.slideItemsWidths.push(GM.$getCss(el, 'width'))
}
let t = getSlideDistance(state, type)
let dx1 = 0, dx2 = 0
if (type === SlideType.HORIZONTAL) dx1 = t
else dx2 = t
console.log('start', dx1)
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
}
export function slideTouchStart(e, el, state) {
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()
}
export function canSlide(state, judgeValue, type = SlideType.HORIZONTAL) {
if (state.needCheck) {
if (Math.abs(state.move.x) > judgeValue || Math.abs(state.move.y) > judgeValue) {
let angle = (Math.abs(state.move.x) * 10) / (Math.abs(state.move.y) * 10)
state.next = type === SlideType.HORIZONTAL ? angle > 1 : angle <= 1;
// console.log(angle)
state.needCheck = false
} else {
return false
}
}
return state.next
}
export function slideTouchMove(e, el, state, judgeValue, canNextCb, nextCb, type = SlideType.HORIZONTAL, notNextCb) {
state.move.x = e.touches[0].pageX - state.start.x
state.move.y = e.touches[0].pageY - state.start.y
let isNext = type === SlideType.HORIZONTAL ? state.move.x < 0 : state.move.y < 0
let canSlideRes = canSlide(state, judgeValue, type)
if (canSlideRes && state.localIndex === 0 && !isNext && type === SlideType.VERTICAL) {
bus.emit(state.name + '-moveY', state.move.y)
}
if (!canNextCb?.(isNext, state.move)) return
if (canSlideRes) {
nextCb?.()
if (type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-moveX', state.move.x)
}
Utils.$stopPropagation(e)
let t = getSlideDistance(state, type) + (isNext ? judgeValue : -judgeValue)
let dx1 = 0
let dx2 = 0
if (type === SlideType.HORIZONTAL) {
dx1 = t + state.move.x
} else {
dx2 = t + state.move.y
}
Utils.$setCss(el, 'transition-duration', `0ms`)
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
} else {
notNextCb?.()
}
}
export function slideTouchEnd(e, state, canNextCb, nextCb, notNextCb, type = SlideType.HORIZONTAL) {
let isHorizontal = type === SlideType.HORIZONTAL;
let isNext = isHorizontal ? state.move.x < 0 : state.move.y < 0
if (!canNextCb?.(isNext)) return notNextCb?.()
if (state.next) {
Utils.$stopPropagation(e)
let endTime = Date.now()
let gapTime = endTime - state.start.time
let distance = isHorizontal ? state.move.x : state.move.y
let judgeValue = isHorizontal ? state.wrapper.width : state.wrapper.height
if (Math.abs(distance) < 20) gapTime = 1000
if (Math.abs(distance) > (judgeValue / 3)) gapTime = 100
if (gapTime < 150) {
if (isNext) {
state.localIndex++
} else {
state.localIndex--
}
return nextCb?.(isNext)
}
}
notNextCb?.()
}
export function slideReset(el, state, type, emit) {
Utils.$setCss(el, 'transition-duration', `300ms`)
let t = getSlideDistance(state, type)
let dx1 = 0
let dx2 = 0
if (type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-end', state.localIndex)
dx1 = t
} else {
bus.emit(state.name + '-end',)
dx2 = t
}
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
emit?.('update:index', state.localIndex)
}
export function getSlideDistance(state, type = SlideType.HORIZONTAL) {
if (type === SlideType.HORIZONTAL) {
return state.slideItemsWidths.reduce((p, c, i) => {
if (i <= state.localIndex && i > 0) p -= c
return p
}, 0)
} else {
//TODO 这里需要改的和上面一样不然不能显示半屏的div
return -state.localIndex * state.wrapper.height
}
}