douyin/src/components/slide/VInfinite-Component.vue
2023-02-18 02:59:03 +08:00

185 lines
5.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="jsx">
import {computed, onMounted, reactive, ref, watch} from "vue";
import GM from '../../utils'
import {
getSlideDistance,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from "./common";
import {SlideType} from "../../utils/const_var";
import SlideItem from "@/pages/slideHooks/SlideItem.vue";
import TestItem from "@/pages/slideComponent/TestItem.vue";
const props = defineProps({
index: {
type: Number,
default: () => {
return 0
}
},
position: {
type: Object,
default: () => {
return {}
}
},
render: {
type: Function,
default: () => {
return null
}
},
list: {
type: Array,
default: () => {
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
}
},
virtualTotal: {
type: Number,
default: () => 5
},
name: {
type: String,
default: () => ''
},
})
const emit = defineEmits(['update:index', 'loadMore'])
const judgeValue = 20
const wrapperEl = ref(null)
const state = reactive({
name: 'SlideVertical',
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},
cs: [],
styleTop: 0,
components: {
one: <SlideItem class=" gray">
<div class="big">热点0</div>
</SlideItem>,
two: <SlideItem class=" gray">
<div class="big">热点1</div>
</SlideItem>,
three: <SlideItem class=" gray">
<div class="big">热点2</div>
</SlideItem>,
four: <SlideItem class=" gray">
<div class="big">热点3</div>
</SlideItem>,
five: <SlideItem class=" gray">
<div class="big">热点4</div>
</SlideItem>,
}
})
function r(item, index = -1) {
let node = props.render(item, state.localIndex, index === 0, props.position)
return <SlideItem class="slideItemClassName">
{node}
</SlideItem>
}
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)`)
}
}
)
watch(
() => props.list,
(newVal) => {
console.log('list', newVal)
let half = (props.virtualTotal + 1) / 2
if (state.localIndex >= half) {
state.cs = newVal.slice(state.localIndex - 2, state.localIndex + 3).map((v, i) => r(v))
state.styleTop = (state.localIndex - 2) * state.wrapper.height
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.VERTICAL)
state.cs = props.list.slice(0, props.virtualTotal).map((v, i) => r(v, i))
})
function touchStart(e) {
slideTouchStart(e, wrapperEl.value, state)
}
function touchMove(e) {
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, null, SlideType.VERTICAL)
}
function touchEnd(e) {
slideTouchEnd(e, state, canNext, (isNext) => {
console.log('state.localIndex', state.localIndex)
let half = (props.virtualTotal + 1) / 2
if (props.list.length > props.virtualTotal) {
if (isNext) {
if (state.localIndex > props.list.length - props.virtualTotal && state.localIndex > half) {
console.log('loadMore')
emit('loadMore')
}
if (state.localIndex >= half && state.localIndex <= props.list.length - half) {
console.log('push')
// state.cs = props.list.slice(state.localIndex - 2, state.localIndex + 3).map((v, i) => r(v))
state.cs.shift()
state.cs.push(r(props.list[state.localIndex + (half - 1)]))
state.styleTop = (state.localIndex - 2) * state.wrapper.height
}
} else {
//这里先加个1保持if表达式一致
let judgeIndex = state.localIndex + 1
if (judgeIndex >= half && judgeIndex <= props.list.length - half) {
console.log('unshift')
state.cs.unshift(r(props.list[state.localIndex - (half - 1)]))
state.cs.pop()
state.styleTop = (state.localIndex - 2) * state.wrapper.height
}
}
}
if (state.localIndex < half) {
console.log('--')
state.styleTop = 0
}
}, null, SlideType.VERTICAL)
slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
}
function canNext(isNext) {
return !((state.localIndex === 0 && !isNext) || (state.localIndex === props.list.length - 1 && isNext));
}
</script>
<template>
<div class="slide v">
<div class="slide-list flex-direction-column"
ref="wrapperEl"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<component :style='{top: state.styleTop + "px"}' :is="v" v-for="(v,i) in state.cs" :key="v.id"/>
</div>
</div>
</template>
测试用<component :is的方法是否可行结论可行但是不实用当list数据更新时<component的表现形式为不销毁组件只更新props
感觉会导致已经加载到的video重新加载但未经测试