save
This commit is contained in:
parent
41a6f99e8e
commit
19f3733aa7
@ -96,7 +96,7 @@
|
||||
ref="virtualList"
|
||||
:list="videos"
|
||||
:renderSlide="render"
|
||||
v-model:active-index="videoActiveIndex"
|
||||
v-model:active-index="videoActixveIndex"
|
||||
@end="end"
|
||||
>
|
||||
</SlideColumnVirtualList>
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<script setup>
|
||||
import {ref, onMounted, reactive} from "vue";
|
||||
import {onMounted, reactive, ref, watch} from "vue";
|
||||
import GM from '../../utils'
|
||||
import bus from "../../utils/bus";
|
||||
import Common from "../../utils";
|
||||
import {slideReset, slideTouchStart} from "./common";
|
||||
import {getSlideDistance, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
@ -17,20 +16,33 @@ const emit = defineEmits(['update:index'])
|
||||
|
||||
const judgeValue = 20
|
||||
const wrapperEl = ref(null)
|
||||
const wrapper = reactive({width: 0, height: 0, childrenLength: 0})
|
||||
const state = reactive({
|
||||
name: 'SlideVertical',
|
||||
localIndex: 0,
|
||||
name: 'SlideHorizontal',
|
||||
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}
|
||||
})
|
||||
|
||||
// 单个 ref
|
||||
watch(
|
||||
() => props.index,
|
||||
(newVal) => {
|
||||
console.log('w')
|
||||
if (state.localIndex !== newVal) {
|
||||
state.localIndex = newVal
|
||||
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
GM.$setCss(wrapperEl.value, 'transform', `translate3d(${getSlideDistance(state, SlideType.HORIZONTAL)}px, 0, 0)`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
wrapper.childrenLength = wrapperEl.value.children.length
|
||||
state.wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
state.wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
})
|
||||
|
||||
function touchStart(e) {
|
||||
@ -38,58 +50,20 @@ function touchStart(e) {
|
||||
}
|
||||
|
||||
function touchMove(e) {
|
||||
state.move.x = e.touches[0].pageX - state.start.x
|
||||
state.move.y = e.touches[0].pageY - state.start.y
|
||||
|
||||
let isNext = state.move.x < 0
|
||||
if ((state.localIndex === 0 && !isNext) || (state.localIndex === wrapper.childrenLength - 1 && isNext)) return
|
||||
|
||||
checkDirection(e)
|
||||
|
||||
if (state.next) {
|
||||
bus.emit(state.name + '-moveX', state.move.x)
|
||||
GM.$stopPropagation(e)
|
||||
GM.$setCss(wrapperEl.value, 'transform',
|
||||
`translate3d(${getDistance()
|
||||
+ state.move.x
|
||||
+ (isNext ? judgeValue : -judgeValue)
|
||||
}px, 0, 0)`)
|
||||
}
|
||||
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, SlideType.HORIZONTAL)
|
||||
}
|
||||
|
||||
function touchEnd(e) {
|
||||
let isRight = state.move.x < 0
|
||||
if ((state.localIndex === 0 && !isRight) || (state.localIndex === wrapper.childrenLength - 1 && isRight)) state.next = false
|
||||
slideTouchEnd(e, state, canNext, () => {
|
||||
|
||||
let endTime = Date.now()
|
||||
let gapTime = endTime - state.start.time
|
||||
if (Math.abs(state.move.x) < 20) gapTime = 1000
|
||||
if (Math.abs(state.move.x) > (wrapper.width / 4)) gapTime = 100
|
||||
if (gapTime < 150 && state.next) {
|
||||
if (isRight) {
|
||||
state.localIndex++
|
||||
} else {
|
||||
state.localIndex--
|
||||
}
|
||||
}
|
||||
slideReset(wrapperEl.value, getDistance(), state, emit)
|
||||
})
|
||||
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, emit)
|
||||
}
|
||||
|
||||
function checkDirection(e) {
|
||||
if (!state.needCheck) return
|
||||
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 = angle > 1;
|
||||
// console.log(angle)
|
||||
return state.needCheck = false
|
||||
}
|
||||
return state.needCheck = true
|
||||
}
|
||||
|
||||
function getDistance() {
|
||||
return -state.localIndex * wrapper.width
|
||||
function canNext(isNext) {
|
||||
return !((state.localIndex === 0 && !isNext) || (state.localIndex === state.wrapper.childrenLength - 1 && isNext));
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@ -1,112 +1,56 @@
|
||||
<script setup>
|
||||
import {ref, onMounted, reactive} from "vue";
|
||||
import Common from '../../utils'
|
||||
import bus from "../../utils/bus";
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import GM from '../../utils'
|
||||
import {slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
|
||||
const props = defineProps({
|
||||
list: {
|
||||
type: Array,
|
||||
index: {
|
||||
type: Number,
|
||||
default: () => {
|
||||
return []
|
||||
return 0
|
||||
}
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:index'])
|
||||
|
||||
const judgeValue = 20
|
||||
const wrapperEl = ref(null)
|
||||
const wrapper = reactive({width: 0, height: 0, childrenLength: 0})
|
||||
const start = reactive({x: 0, y: 0, time: 0})
|
||||
const move = reactive({x: 0, y: 0})
|
||||
const state = reactive({
|
||||
name: 'SlideVertical',
|
||||
localIndex: 0,
|
||||
needCheck: true,
|
||||
next: false,
|
||||
start: {x: 0, y: 0, time: 0},
|
||||
move: {x: 0, y: 0},
|
||||
wrapper: {width: 0, height: 0, childrenLength: 0}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
checkChildren()
|
||||
state.wrapper.width = GM.$getCss(wrapperEl.value, 'width')
|
||||
state.wrapper.height = GM.$getCss(wrapperEl.value, 'height')
|
||||
state.wrapper.childrenLength = wrapperEl.value.children.length
|
||||
})
|
||||
|
||||
function checkChildren() {
|
||||
wrapper.width = Common.$getCss(wrapperEl.value, 'width')
|
||||
wrapper.height = Common.$getCss(wrapperEl.value, 'height')
|
||||
wrapper.childrenLength = wrapperEl.value.children.length
|
||||
}
|
||||
|
||||
function touchStart(e) {
|
||||
Common.$setCss(wrapperEl.value, 'transition-duration', `0ms`)
|
||||
start.x = e.touches[0].pageX
|
||||
start.y = e.touches[0].pageY
|
||||
start.time = Date.now()
|
||||
slideTouchStart(e, wrapperEl.value, state)
|
||||
}
|
||||
|
||||
function touchMove(e) {
|
||||
move.x = e.touches[0].pageX - start.x
|
||||
move.y = e.touches[0].pageY - start.y
|
||||
|
||||
let isNext = move.x < 0
|
||||
checkDirection(e)
|
||||
|
||||
if (state.localIndex === 0 && !isNext && state.next) {
|
||||
// bus.emit(this.name + '-moveY', this.moveY)
|
||||
}
|
||||
if ((state.localIndex === 0 && !isNext) || (state.localIndex === props.list.length- 1 && isNext)) return
|
||||
if (state.next) {
|
||||
Common.$stopPropagation(e)
|
||||
Common.$setCss(wrapperEl.value, 'transform',
|
||||
`translate3d(${getDistance()
|
||||
+ move.y
|
||||
+ (isNext ? judgeValue : -judgeValue)
|
||||
}px, 0)`)
|
||||
}
|
||||
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, SlideType.VERTICAL)
|
||||
}
|
||||
|
||||
function touchEnd(e) {
|
||||
let isRight = move.x < 0
|
||||
if ((state.localIndex === 0 && !isRight) || (state.localIndex === wrapper.childrenLength - 1 && isRight)) state.next = false
|
||||
slideTouchEnd(e, state, canNext, () => {
|
||||
|
||||
let endTime = Date.now()
|
||||
let gapTime = endTime - start.time
|
||||
if (Math.abs(move.x) < 20) gapTime = 1000
|
||||
if (Math.abs(move.x) > (wrapper.width / 4)) gapTime = 100
|
||||
if (gapTime < 150 && state.next) {
|
||||
if (isRight) {
|
||||
state.localIndex++
|
||||
} else {
|
||||
state.localIndex--
|
||||
}
|
||||
}
|
||||
reset()
|
||||
}, SlideType.VERTICAL)
|
||||
slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
|
||||
}
|
||||
|
||||
function checkDirection(e) {
|
||||
if (!state.needCheck) return
|
||||
if (Math.abs(move.x) > judgeValue || Math.abs(move.y) > judgeValue) {
|
||||
let angle = (Math.abs(move.x) * 10) / (Math.abs(move.y) * 10)
|
||||
state.next = angle <= 1;
|
||||
// console.log(angle)
|
||||
return state.needCheck = false
|
||||
}
|
||||
return state.needCheck = true
|
||||
|
||||
function canNext(isNext) {
|
||||
return !((state.localIndex === 0 && !isNext) || (state.localIndex === state.wrapper.childrenLength - 1 && isNext));
|
||||
}
|
||||
|
||||
function reset() {
|
||||
Common.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
|
||||
Common.$setCss(wrapperEl.value, 'transform',
|
||||
`translate3d(${getDistance()}px, 0, 0)`)
|
||||
|
||||
move.x = 0
|
||||
state.next = false
|
||||
state.needCheck = true
|
||||
start.time = null
|
||||
// this.$emit('update:index', state.localIndex)
|
||||
// bus.emit(this.name + '-end', state.localIndex)
|
||||
}
|
||||
|
||||
function getDistance() {
|
||||
return -state.localIndex * wrapper.height
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -120,4 +64,4 @@ function getDistance() {
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
67
src/pages/slideHooks/VInfinite.vue
Normal file
67
src/pages/slideHooks/VInfinite.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import GM from '../../utils'
|
||||
import {slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
|
||||
const props = defineProps({
|
||||
index: {
|
||||
type: Number,
|
||||
default: () => {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
})
|
||||
const emit = defineEmits(['update:index'])
|
||||
|
||||
const judgeValue = 20
|
||||
const wrapperEl = ref(null)
|
||||
const state = reactive({
|
||||
name: 'SlideVertical',
|
||||
localIndex: 0,
|
||||
needCheck: true,
|
||||
next: false,
|
||||
start: {x: 0, y: 0, time: 0},
|
||||
move: {x: 0, y: 0},
|
||||
wrapper: {width: 0, height: 0, childrenLength: 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
|
||||
})
|
||||
|
||||
function touchStart(e) {
|
||||
slideTouchStart(e, wrapperEl.value, state)
|
||||
}
|
||||
|
||||
function touchMove(e) {
|
||||
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, SlideType.VERTICAL)
|
||||
}
|
||||
|
||||
function touchEnd(e) {
|
||||
slideTouchEnd(e, state, canNext, () => {
|
||||
|
||||
}, SlideType.VERTICAL)
|
||||
slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
|
||||
}
|
||||
|
||||
|
||||
function canNext(isNext) {
|
||||
return !((state.localIndex === 0 && !isNext) || (state.localIndex === state.wrapper.childrenLength - 1 && isNext));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="slide">
|
||||
<div class="slide-wrapper flex-direction-column"
|
||||
ref="wrapperEl"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
@touchend="touchEnd"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,10 +1,88 @@
|
||||
import bus from "../../utils/bus";
|
||||
import Utils from '../../utils'
|
||||
import GM from "../../utils";
|
||||
import {SlideType} from "../../utils/const_var";
|
||||
|
||||
export function slideReset(el, distance, state, emit) {
|
||||
|
||||
export function slideTouchStart(e, el, state) {
|
||||
GM.$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, cb, type = SlideType.HORIZONTAL) {
|
||||
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
|
||||
|
||||
if (!cb?.(isNext)) return
|
||||
|
||||
if (canSlide(state, judgeValue, type)) {
|
||||
bus.emit(state.name + '-moveX', state.move.x)
|
||||
GM.$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
|
||||
}
|
||||
GM.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
|
||||
}
|
||||
}
|
||||
|
||||
export function slideTouchEnd(e, state, canNextCb, nextCb, type = SlideType.HORIZONTAL) {
|
||||
let isHorizontal = type === SlideType.HORIZONTAL;
|
||||
let isNext = isHorizontal ? state.move.x < 0 : state.move.y < 0
|
||||
|
||||
if (!canNextCb?.(isNext)) return
|
||||
if (state.next) {
|
||||
GM.$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--
|
||||
}
|
||||
nextCb?.()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function slideReset(el, state, type, emit) {
|
||||
Utils.$setCss(el, 'transition-duration', `300ms`)
|
||||
Utils.$setCss(el, 'transform', `translate3d(${distance}px, 0, 0)`)
|
||||
let t = getSlideDistance(state, type)
|
||||
let dx1 = 0
|
||||
let dx2 = 0
|
||||
if (type === SlideType.HORIZONTAL) {
|
||||
dx1 = t
|
||||
} else {
|
||||
dx2 = t
|
||||
}
|
||||
GM.$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
|
||||
@ -12,9 +90,10 @@ export function slideReset(el, distance, state, emit) {
|
||||
bus.emit(state.name + '-end', state.localIndex)
|
||||
}
|
||||
|
||||
export function slideTouchStart(e, el, state) {
|
||||
GM.$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 getSlideDistance(state, type = SlideType.HORIZONTAL) {
|
||||
if (type === SlideType.HORIZONTAL) {
|
||||
return -state.localIndex * state.wrapper.width
|
||||
} else {
|
||||
return -state.localIndex * state.wrapper.height
|
||||
}
|
||||
}
|
||||
@ -1,35 +1,61 @@
|
||||
<template>
|
||||
<div class="slide2">
|
||||
<H class="h" v-model:index="state.index">
|
||||
<SlideItem class="slide-item">
|
||||
<!-- <V>-->
|
||||
<!-- <SlideItem class="slide-item"></SlideItem>-->
|
||||
<!-- <SlideItem class="slide-item"></SlideItem>-->
|
||||
<!-- </V>-->
|
||||
<H class="h" v-model:index="state.baseIndex">
|
||||
<SlideItem class="slide-item gray">
|
||||
<H class="h" v-model:index="state.index">
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big">找红包</div>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big">热点</div>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big">社区</div>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big">关注</div>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item gray">
|
||||
<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>
|
||||
</SlideItem>
|
||||
</H>
|
||||
<Footer v-bind:init-tab="1"/>
|
||||
</SlideItem>
|
||||
<SlideItem class="slide-item">
|
||||
<!-- <V></V>-->
|
||||
<SlideItem class="slide-item gray">
|
||||
<div class="big" v-for="i in 100">主页</div>
|
||||
</SlideItem>
|
||||
</H>
|
||||
<span>{{ state.index }}</span>
|
||||
<Footer v-bind:init-tab="1"/>
|
||||
<span>{{ state.baseIndex }}</span>
|
||||
<button @click="state.baseIndex++">加</button>
|
||||
<button @click="state.baseIndex--">减</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import H from './H'
|
||||
import V from './V'
|
||||
import VInfinite from './VInfinite.vue'
|
||||
import SlideItem from './SlideItem'
|
||||
import {reactive} from "vue";
|
||||
|
||||
const state = reactive({
|
||||
index: 0
|
||||
baseIndex: 1,
|
||||
index: 1
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.slide2 {
|
||||
font-size: 14rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
@ -37,6 +63,11 @@ const state = reactive({
|
||||
color: white;
|
||||
font-size: 24rem;
|
||||
}
|
||||
|
||||
.big {
|
||||
font-weight: bold;
|
||||
font-size: 100rem;
|
||||
}
|
||||
}
|
||||
|
||||
.h {
|
||||
@ -44,12 +75,20 @@ const state = reactive({
|
||||
height: 80vh;
|
||||
overflow: hidden;
|
||||
|
||||
.slide-item {
|
||||
.red {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
background-color: gray;
|
||||
}
|
||||
.yellow {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.gray {
|
||||
background-color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,3 +19,7 @@ export default {
|
||||
REQUEST_FOLLOW: 4//关注请求
|
||||
}
|
||||
}
|
||||
export const SlideType = {
|
||||
HORIZONTAL:0,
|
||||
VERTICAL:1,
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user