Adapt to mobile devices
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
106
src/components/slide/SlideHorizontal.vue
Normal file
106
src/components/slide/SlideHorizontal.vue
Normal 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>
|
||||
18
src/components/slide/SlideItem.vue
Normal file
18
src/components/slide/SlideItem.vue
Normal 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>
|
||||
135
src/components/slide/common.js
Normal file
135
src/components/slide/common.js
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user