11 changed files with 471 additions and 170 deletions
@ -0,0 +1,241 @@ |
|||||||
|
<template> |
||||||
|
<SlideItem id="slide0"> |
||||||
|
<div class="sub-type" |
||||||
|
:class="state.subTypeIsTop?'top':''" |
||||||
|
ref="subTypeRef"> |
||||||
|
<div class="local"> |
||||||
|
<div class="card" @touchmove.capture="stop"> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>美食</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>休闲娱乐</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>游玩</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>丽人/美发</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>住宿</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>游玩</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>丽人/美发</span> |
||||||
|
</div> |
||||||
|
<div class="nav-item"> |
||||||
|
<img src="@/assets/img/icon/msg-icon9.webp" alt=""> |
||||||
|
<span>住宿</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="sub-type-notice" |
||||||
|
v-if="state.subType===-1 && !state.subTypeVisible" |
||||||
|
@click="showSubType">附近吃喝玩乐 |
||||||
|
</div> |
||||||
|
<SlideList |
||||||
|
:style="{background: 'black',marginTop:state.subTypeVisible?state.subTypeHeight:0}" |
||||||
|
:api="api.videos.recommended" |
||||||
|
@touchstart="pageClick" |
||||||
|
html-id="slide0-list" |
||||||
|
/> |
||||||
|
</SlideItem> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="jsx"> |
||||||
|
import SlideItem from '@/components/slide/SlideItem.vue' |
||||||
|
import {onMounted, onUnmounted, reactive, ref, watch} from "vue"; |
||||||
|
import bus, {EVENT_KEY} from "@/utils/bus"; |
||||||
|
import Utils from "@/utils"; |
||||||
|
import api from "@/api"; |
||||||
|
import Loading from "@/components/Loading.vue"; |
||||||
|
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender"; |
||||||
|
import SlideList from './SlideList.vue'; |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
cbs: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {} |
||||||
|
} |
||||||
|
}, |
||||||
|
active: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
} |
||||||
|
}) |
||||||
|
const emit = defineEmits([ |
||||||
|
'update:item', |
||||||
|
'goUserInfo', |
||||||
|
'showComments', |
||||||
|
'showShare', |
||||||
|
'goMusic', |
||||||
|
]) |
||||||
|
|
||||||
|
function stop(e) { |
||||||
|
e.stopPropagation() |
||||||
|
} |
||||||
|
|
||||||
|
const p = { |
||||||
|
onShowComments() { |
||||||
|
console.log('onShowComments') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
watch( |
||||||
|
() => props.active, |
||||||
|
(newVal, oldVal) => { |
||||||
|
console.log('newVal', newVal, 'oldVal', oldVal) |
||||||
|
if (newVal === false) { |
||||||
|
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, { |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 0, |
||||||
|
itemIndex: state.index, |
||||||
|
type: EVENT_KEY.ITEM_STOP |
||||||
|
}) |
||||||
|
} else { |
||||||
|
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, { |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 0, |
||||||
|
itemIndex: state.index, |
||||||
|
type: EVENT_KEY.ITEM_PLAY |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
const render = useSlideListItemRender({...props.cbs, ...p}) |
||||||
|
const subTypeRef = ref(null) |
||||||
|
const listRef = ref(null) |
||||||
|
const state = reactive({ |
||||||
|
loading: false, |
||||||
|
index: 0, |
||||||
|
subType: -1, |
||||||
|
subTypeVisible: false, |
||||||
|
subTypeHeight: '0', |
||||||
|
//用于改变zindex的层级到上层,反正比slide高就行。不然摸不到subType. |
||||||
|
subTypeIsTop: false, |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
function showSubType(e) { |
||||||
|
Utils.$stopPropagation(e) |
||||||
|
console.log('subTypeRef',) |
||||||
|
state.subTypeHeight = subTypeRef.value.getBoundingClientRect().height + 'px' |
||||||
|
state.subTypeVisible = true |
||||||
|
setTimeout(() => state.subTypeIsTop = true, 300) |
||||||
|
bus.emit(EVENT_KEY.OPEN_SUB_TYPE,) |
||||||
|
} |
||||||
|
|
||||||
|
function pageClick(e) { |
||||||
|
// console.log('pageClick') |
||||||
|
if (state.subTypeVisible) { |
||||||
|
state.subTypeIsTop = state.subTypeVisible = false |
||||||
|
bus.emit(EVENT_KEY.CLOSE_SUB_TYPE,) |
||||||
|
Utils.$stopPropagation(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function dislike() { |
||||||
|
listRef.value.dislike(state.list[1]) |
||||||
|
state.list[state.index] = state.list[1] |
||||||
|
Utils.$notice('操作成功,将减少此类视频的推荐') |
||||||
|
} |
||||||
|
|
||||||
|
function end() { |
||||||
|
// this.$notice('暂时没有更多了') |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
// getData() |
||||||
|
}) |
||||||
|
onUnmounted(() => { |
||||||
|
}) |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="less"> |
||||||
|
@import "@/assets/less/index"; |
||||||
|
|
||||||
|
#slide0 { |
||||||
|
position: relative; |
||||||
|
|
||||||
|
.sub-type { |
||||||
|
width: 100%; |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
|
||||||
|
&.top { |
||||||
|
z-index: 2; |
||||||
|
} |
||||||
|
|
||||||
|
.local { |
||||||
|
transition: all .3s; |
||||||
|
font-size: 14rem; |
||||||
|
color: gray; |
||||||
|
background: #f9f9f9; |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
.card { |
||||||
|
margin: 20rem; |
||||||
|
margin-top: @header-height; |
||||||
|
padding: 20rem; |
||||||
|
border-radius: 8rem; |
||||||
|
width: 100%; |
||||||
|
background: white; |
||||||
|
box-sizing: border-box; |
||||||
|
display: flex; |
||||||
|
align-items: flex-end; |
||||||
|
justify-content: space-between; |
||||||
|
overflow: auto; |
||||||
|
} |
||||||
|
|
||||||
|
.nav-item { |
||||||
|
@width: 35rem; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
flex-direction: column; |
||||||
|
flex-shrink: 0; |
||||||
|
width: 17vw; |
||||||
|
|
||||||
|
img { |
||||||
|
width: @width; |
||||||
|
height: @width; |
||||||
|
margin-bottom: 5rem; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.sub-type-notice { |
||||||
|
position: fixed; |
||||||
|
background: rgba(black, .4); |
||||||
|
top: 100rem; |
||||||
|
left: 50%; |
||||||
|
transform: translateX(-50%); |
||||||
|
padding: 3rem 12rem; |
||||||
|
border-radius: 10rem; |
||||||
|
z-index: 3; |
||||||
|
font-size: 12rem; |
||||||
|
color: white; |
||||||
|
} |
||||||
|
|
||||||
|
#slide0-infinite { |
||||||
|
z-index: 1; |
||||||
|
margin-top: 0; |
||||||
|
transition: all .3s; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,155 @@ |
|||||||
|
<template> |
||||||
|
<Loading v-if="state.loading && state.list.length === 0"/> |
||||||
|
<SlideVerticalInfinite |
||||||
|
ref="listRef" |
||||||
|
v-love="htmlId" |
||||||
|
name="main" |
||||||
|
:id="htmlId" |
||||||
|
v-model:index="state.index" |
||||||
|
:render="render" |
||||||
|
:list="state.list" |
||||||
|
:position="{ |
||||||
|
baseIndex:0, |
||||||
|
navIndex:0, |
||||||
|
}" |
||||||
|
@loadMore="loadMore" |
||||||
|
@refresh="() => getData(true)" |
||||||
|
/> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="jsx"> |
||||||
|
import SlideVerticalInfinite from '@/components/slide/SlideVerticalInfinite.vue' |
||||||
|
import {onMounted, onUnmounted, reactive, ref, watch} from "vue"; |
||||||
|
import bus, {EVENT_KEY} from "@/utils/bus"; |
||||||
|
import Utils from "@/utils"; |
||||||
|
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender"; |
||||||
|
import Loading from "@/components/Loading.vue"; |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
cbs: { |
||||||
|
type: Object, |
||||||
|
default() { |
||||||
|
return {} |
||||||
|
} |
||||||
|
}, |
||||||
|
active: { |
||||||
|
type: Boolean, |
||||||
|
default: false |
||||||
|
}, |
||||||
|
api: { |
||||||
|
type: Function, |
||||||
|
default: void 0 |
||||||
|
}, |
||||||
|
htmlId: { |
||||||
|
type: String, |
||||||
|
default: 'guid' |
||||||
|
} |
||||||
|
}) |
||||||
|
const emit = defineEmits([ |
||||||
|
'update:item', |
||||||
|
'goUserInfo', |
||||||
|
'showComments', |
||||||
|
'showShare', |
||||||
|
'goMusic', |
||||||
|
]) |
||||||
|
|
||||||
|
function stop(e) { |
||||||
|
e.stopPropagation() |
||||||
|
} |
||||||
|
|
||||||
|
const p = { |
||||||
|
onShowComments() { |
||||||
|
console.log('onShowComments') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
watch( |
||||||
|
() => props.active, |
||||||
|
(newVal, oldVal) => { |
||||||
|
console.log('newVal', newVal, 'oldVal', oldVal) |
||||||
|
if (newVal === false) { |
||||||
|
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, { |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 0, |
||||||
|
itemIndex: state.index, |
||||||
|
type: EVENT_KEY.ITEM_STOP |
||||||
|
}) |
||||||
|
} else { |
||||||
|
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, { |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 0, |
||||||
|
itemIndex: state.index, |
||||||
|
type: EVENT_KEY.ITEM_PLAY |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
const render = useSlideListItemRender({...props.cbs, ...p}) |
||||||
|
const subTypeRef = ref(null) |
||||||
|
const listRef = ref(null) |
||||||
|
const state = reactive({ |
||||||
|
loading: false, |
||||||
|
index: 0, |
||||||
|
list: [ |
||||||
|
// { |
||||||
|
// type: 'user', |
||||||
|
// src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}` |
||||||
|
// }, |
||||||
|
], |
||||||
|
totalSize: 0, |
||||||
|
pageSize: 10, |
||||||
|
pageNo: 0, |
||||||
|
}) |
||||||
|
|
||||||
|
function loadMore() { |
||||||
|
if (!state.loading) { |
||||||
|
state.pageNo++ |
||||||
|
getData() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async function getData(refresh = false) { |
||||||
|
if (state.loading) return |
||||||
|
state.loading = true |
||||||
|
let res = await props.api({pageNo: refresh ? 0 : state.pageNo, pageSize: state.pageSize}) |
||||||
|
console.log('getSlide0Data-', 'refresh', refresh, res) |
||||||
|
state.loading = false |
||||||
|
if (res.code === 200) { |
||||||
|
state.totalSize = res.data.total |
||||||
|
if (refresh) { |
||||||
|
state.list = [] |
||||||
|
} |
||||||
|
state.list = state.list.concat(res.data.list) |
||||||
|
} else { |
||||||
|
state.pageNo-- |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function dislike() { |
||||||
|
listRef.value.dislike(state.list[1]) |
||||||
|
state.list[state.index] = state.list[1] |
||||||
|
Utils.$notice('操作成功,将减少此类视频的推荐') |
||||||
|
} |
||||||
|
|
||||||
|
function end() { |
||||||
|
// this.$notice('暂时没有更多了') |
||||||
|
} |
||||||
|
|
||||||
|
function click(htmlId) { |
||||||
|
if (htmlId !== props.htmlId) return |
||||||
|
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, { |
||||||
|
baseIndex: 0, |
||||||
|
navIndex: 0, |
||||||
|
itemIndex: state.index, |
||||||
|
type: EVENT_KEY.ITEM_TOGGLE |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
// getData() |
||||||
|
getData() |
||||||
|
bus.on(EVENT_KEY.SINGLE_CLICK, click) |
||||||
|
}) |
||||||
|
onUnmounted(() => { |
||||||
|
bus.off(EVENT_KEY.SINGLE_CLICK, click) |
||||||
|
}) |
||||||
|
</script> |
@ -0,0 +1,32 @@ |
|||||||
|
import SlideAlbum from "@/components/slide/SlideAlbum.vue"; |
||||||
|
import SlideUser from "@/components/slide/SlideUser.vue"; |
||||||
|
import BVideo from "@/components/slide/BVideo.vue"; |
||||||
|
|
||||||
|
export function useSlideListItemRender(props) { |
||||||
|
return function render(item, itemIndex, play, position) { |
||||||
|
// console.log('item', item) |
||||||
|
let node |
||||||
|
if (item.type === 'img') { |
||||||
|
node = <img src={item.src} style="height:100%;"/> |
||||||
|
} |
||||||
|
if (item.type === 'imgs') { |
||||||
|
node = <SlideAlbum/> |
||||||
|
} |
||||||
|
if (item.type === 'user') { |
||||||
|
node = <SlideUser {...props}/> |
||||||
|
} |
||||||
|
if (item.type === 'send-video') { |
||||||
|
node = <video src={item.src} style="height:100%;"/> |
||||||
|
} |
||||||
|
// onGoUserInfo={() => cb('onGoUserInfo')} |
||||||
|
if (item.type === 'recommend-video') { |
||||||
|
node = <BVideo |
||||||
|
isPlay={play} |
||||||
|
item={item} |
||||||
|
position={{...position, itemIndex}} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
} |
||||||
|
return node |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue