155 lines
4.0 KiB
Vue
155 lines
4.0 KiB
Vue
<script setup lang="jsx">
|
||
import {onMounted, reactive, ref, watch, createApp} from "vue";
|
||
import GM from '../../utils'
|
||
import {getSlideDistance, slideInit, slideReset, slideTouchEnd, slideTouchMove, slideTouchStart} from "./common";
|
||
import {SlideType} from "../../utils/const_var";
|
||
import SlideItem from './SlideItem'
|
||
|
||
const props = defineProps({
|
||
index: {
|
||
type: Number,
|
||
default: () => {
|
||
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: 'SlideVerticalInfinite',
|
||
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}
|
||
})
|
||
|
||
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(() => {
|
||
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)
|
||
}
|
||
|
||
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-list flex-direction-column"
|
||
ref="wrapperEl"
|
||
@touchstart="touchStart"
|
||
@touchmove="touchMove"
|
||
@touchend="touchEnd"
|
||
>
|
||
<slot></slot>
|
||
</div>
|
||
</div>
|
||
</template>
|