16 changed files with 546 additions and 79 deletions
@ -0,0 +1,29 @@ |
|||||||
|
<template> |
||||||
|
<div class="big">{{ props.item.desc }}</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
import {onMounted, onUnmounted} from "vue"; |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
item: { |
||||||
|
type: Object, |
||||||
|
default: () => { |
||||||
|
return {} |
||||||
|
} |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
onMounted(()=>{ |
||||||
|
console.log('onMounted',props.item.desc) |
||||||
|
}) |
||||||
|
|
||||||
|
onUnmounted(()=>{ |
||||||
|
console.log('onUnmounted',props.item.desc) |
||||||
|
}) |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
|
||||||
|
</style> |
@ -0,0 +1,168 @@ |
|||||||
|
<script setup lang="jsx"> |
||||||
|
import {computed, onMounted, reactive, ref, watch} from "vue"; |
||||||
|
import GM from '../../utils' |
||||||
|
import { |
||||||
|
getSlideDistance, |
||||||
|
slideInit, |
||||||
|
slideReset, |
||||||
|
slideTouchEnd, |
||||||
|
slideTouchMove, |
||||||
|
slideTouchStart |
||||||
|
} from "../slideHooks/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) { |
||||||
|
let node = props.render(item, state.localIndex, true, 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)`) |
||||||
|
} |
||||||
|
} |
||||||
|
) |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
slideInit(wrapperEl.value, state, SlideType.VERTICAL) |
||||||
|
state.cs = props.list.slice(0, props.virtualTotal).map((v, i) => r(v)) |
||||||
|
}) |
||||||
|
|
||||||
|
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> |
@ -0,0 +1,180 @@ |
|||||||
|
<template> |
||||||
|
<div class="test-slide-wrapper" id="slideHook" v-love="'slideHook'"> |
||||||
|
<V |
||||||
|
name="main" |
||||||
|
v-model:index="state.itemIndex" |
||||||
|
:render="render" |
||||||
|
@loadMore="loadMore" |
||||||
|
:list="state.recommendVideos" |
||||||
|
:position="{ |
||||||
|
baseIndex:0, |
||||||
|
navIndex:5, |
||||||
|
}" |
||||||
|
> |
||||||
|
</V> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="jsx"> |
||||||
|
import V from './V.vue' |
||||||
|
import SlideImgs from "../../components/slide/SlideAlbum"; |
||||||
|
import BVideo from "../../components/slide/BVideo"; |
||||||
|
import Comment from "../../components/Comment"; |
||||||
|
|
||||||
|
import resource from "../../assets/data/resource.js"; |
||||||
|
import {onMounted, onUnmounted, provide, reactive} from "vue"; |
||||||
|
import bus, {EVENT_KEY} from "../../utils/bus"; |
||||||
|
import {useNav} from "../../utils/hooks/useNav"; |
||||||
|
|
||||||
|
const nav = useNav() |
||||||
|
|
||||||
|
const videos = resource.videos.slice(0, 7).map((v, i) => { |
||||||
|
v.type = 'recommend-video' |
||||||
|
// v.desc = i + v.desc |
||||||
|
return v |
||||||
|
}) |
||||||
|
|
||||||
|
const state = reactive({ |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 4, |
||||||
|
itemIndex: 0, |
||||||
|
recommendVideos: [ |
||||||
|
// { |
||||||
|
// type: 'img', |
||||||
|
// src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}` |
||||||
|
// }, |
||||||
|
// { |
||||||
|
// type: 'imgs', |
||||||
|
// src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}` |
||||||
|
// }, |
||||||
|
...videos |
||||||
|
], |
||||||
|
|
||||||
|
isCommenting: false, |
||||||
|
isSharing: false, |
||||||
|
canMove: true, |
||||||
|
loading: false, |
||||||
|
isUp: false, |
||||||
|
|
||||||
|
shareType: -1, |
||||||
|
|
||||||
|
showPlayFeedback: false, |
||||||
|
showShareDuoshan: false, |
||||||
|
showShareDialog: false, |
||||||
|
showShare2WeChatZone: false, |
||||||
|
showDouyinCode: false, |
||||||
|
showFollowSetting: false, |
||||||
|
showFollowSetting2: false, |
||||||
|
showBlockDialog: false, |
||||||
|
showChangeNote: false, |
||||||
|
shareToFriend: false, |
||||||
|
|
||||||
|
commentVisible: false, |
||||||
|
}) |
||||||
|
provide('commentVisible', () => state.commentVisible) |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
bus.on('singleClick', () => { |
||||||
|
let id = '' |
||||||
|
// if (state.navIndex === 5) { |
||||||
|
if (true) { |
||||||
|
id = state.recommendVideos[state.itemIndex].id |
||||||
|
} |
||||||
|
bus.emit('singleClickBroadcast', id) |
||||||
|
}) |
||||||
|
bus.on('update:item', val => { |
||||||
|
const {baseIndex, navIndex, itemIndex} = val.position |
||||||
|
if (navIndex === 5) { |
||||||
|
state.recommendVideos[itemIndex] = val.item |
||||||
|
} |
||||||
|
}) |
||||||
|
bus.on('nav', path => nav(path)) |
||||||
|
}) |
||||||
|
onUnmounted(() => { |
||||||
|
bus.offAll() |
||||||
|
}) |
||||||
|
|
||||||
|
function loadMore() { |
||||||
|
return |
||||||
|
state.recommendVideos = state.recommendVideos.concat(resource.videos.slice(0, 10).map((v, i) => { |
||||||
|
v.type = 'recommend-video' |
||||||
|
return v |
||||||
|
})) |
||||||
|
} |
||||||
|
|
||||||
|
function test() { |
||||||
|
state.commentVisible = true |
||||||
|
bus.emit(EVENT_KEY.TOGGLE_COMMENT,) |
||||||
|
} |
||||||
|
|
||||||
|
function render(item, itemIndex, play, position) { |
||||||
|
let node |
||||||
|
if (item.type === 'img') { |
||||||
|
node = <img src={item.src} style="height:100%;"/> |
||||||
|
} |
||||||
|
if (item.type === 'imgs') { |
||||||
|
node = <SlideImgs/> |
||||||
|
} |
||||||
|
if (item.type === 'recommend-video') { |
||||||
|
node = <BVideo |
||||||
|
isPlay={false} |
||||||
|
item={item} |
||||||
|
position={{...position, itemIndex}} |
||||||
|
onShowComments={test} |
||||||
|
onShowShare={e => state.isSharing = true} |
||||||
|
onGoUserInfo={e => state.baseIndex = 1} |
||||||
|
/> |
||||||
|
} |
||||||
|
return node |
||||||
|
|
||||||
|
return <SlideItem class="slideItemClassName"> |
||||||
|
{node} |
||||||
|
</SlideItem> |
||||||
|
} |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="less"> |
||||||
|
@import "@/assets/less/index"; |
||||||
|
|
||||||
|
.test-slide-wrapper { |
||||||
|
font-size: 24rem; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
color: white; |
||||||
|
|
||||||
|
span { |
||||||
|
color: white; |
||||||
|
font-size: 24rem; |
||||||
|
} |
||||||
|
|
||||||
|
.big { |
||||||
|
font-weight: bold; |
||||||
|
font-size: 100rem; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.h { |
||||||
|
width: 90vw; |
||||||
|
height: 80vh; |
||||||
|
//height: calc(100vh - @footer-height); |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
.red { |
||||||
|
background-color: red; |
||||||
|
} |
||||||
|
|
||||||
|
.yellow { |
||||||
|
background-color: yellow; |
||||||
|
} |
||||||
|
|
||||||
|
.blue { |
||||||
|
background-color: blue; |
||||||
|
} |
||||||
|
|
||||||
|
.gray { |
||||||
|
background-color: gray; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
</style> |
Loading…
Reference in new issue