11 changed files with 471 additions and 170 deletions
@ -0,0 +1,241 @@
@@ -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 @@
@@ -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 @@
@@ -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