zyronon 1 year ago
parent
commit
373d088812
  1. 20
      pnpm-lock.yaml
  2. 88
      src/pages/home/slide/Community.vue
  3. 92
      src/pages/other/AlbumDetail.vue
  4. 360
      src/pages/other/AlbumDetail2.vue

20
pnpm-lock.yaml

@ -11,6 +11,9 @@ dependencies: @@ -11,6 +11,9 @@ dependencies:
axios:
specifier: 1.6.0
version: 1.6.0
axios-mock-adapter:
specifier: ^1.22.0
version: 1.22.0(axios@1.6.0)
core-js:
specifier: 3.21.1
version: 3.21.1
@ -61,9 +64,6 @@ devDependencies: @@ -61,9 +64,6 @@ devDependencies:
'@vitejs/plugin-vue-jsx':
specifier: 3.0.0
version: 3.0.0(vite@4.5.2)(vue@3.4.21)
axios-mock-adapter:
specifier: ^1.22.0
version: 1.22.0(axios@1.6.0)
less:
specifier: 4.1.3
version: 4.1.3
@ -1432,6 +1432,7 @@ packages: @@ -1432,6 +1432,7 @@ packages:
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/axios-mock-adapter@1.22.0(axios@1.6.0):
resolution: {integrity: sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==}
@ -1441,7 +1442,7 @@ packages: @@ -1441,7 +1442,7 @@ packages:
axios: 1.6.0
fast-deep-equal: 3.1.3
is-buffer: 2.0.5
dev: true
dev: false
/axios@1.6.0:
resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==}
@ -1451,6 +1452,7 @@ packages: @@ -1451,6 +1452,7 @@ packages:
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@ -1717,6 +1719,7 @@ packages: @@ -1717,6 +1719,7 @@ packages:
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/commander@1.1.1:
resolution: {integrity: sha512-71Rod2AhcH3JhkBikVpNd0pA+fWsmAaVoti6OR38T76chA7vE3pSerS0Jor4wDw+tOueD2zLVvFOw5H0Rcj7rA==}
@ -1970,6 +1973,7 @@ packages: @@ -1970,6 +1973,7 @@ packages:
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/delegates@1.0.0:
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
@ -2445,7 +2449,7 @@ packages: @@ -2445,7 +2449,7 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
dev: false
/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
@ -2570,6 +2574,7 @@ packages: @@ -2570,6 +2574,7 @@ packages:
peerDependenciesMeta:
debug:
optional: true
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
@ -2578,6 +2583,7 @@ packages: @@ -2578,6 +2583,7 @@ packages:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/from2@2.3.0:
resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==}
@ -3037,7 +3043,7 @@ packages: @@ -3037,7 +3043,7 @@ packages:
/is-buffer@2.0.5:
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
engines: {node: '>=4'}
dev: true
dev: false
/is-core-module@2.13.1:
resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
@ -3445,6 +3451,7 @@ packages: @@ -3445,6 +3451,7 @@ packages:
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
@ -4003,6 +4010,7 @@ packages: @@ -4003,6 +4010,7 @@ packages:
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}

88
src/pages/home/slide/Community.vue

@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
<WaterfallList :list="list" class="list">
<template v-slot="{item}">
<div class="card"
@click="test"
@click="e=>test(e,item)"
>
<img class="poster" v-lazy="_checkImgUrl(item.note_card?.cover?.url_default)"/>
<div class="bottom">
@ -40,23 +40,30 @@ @@ -40,23 +40,30 @@
</ScrollList>
<div class="shadow">
<div class="wrap"></div>
<AlbumDetail v-if="state.d"
:detail="state.current"
@close="close"/>
</div>
</div>
</template>
<script setup>
import {reactive, watch} from "vue";
import {$no, _checkImgUrl} from "@/utils";
import {reactive, ref, watch} from "vue";
import {$no, _checkImgUrl, cloneDeep} from "@/utils";
import {recommendedPost} from "@/api/user";
import {useNav} from "@/utils/hooks/useNav";
import {Icon} from "@iconify/vue";
import WaterfallList from "@/components/WaterfallList.vue";
import ScrollList from "@/components/ScrollList.vue";
import {useBaseStore} from "@/store/pinia";
import AlbumDetail from "@/pages/other/AlbumDetail.vue";
import Mock from "mockjs";
//@click="nav('album-detail',{},item)"
const nav = useNav()
const baseStore = useBaseStore()
const props = defineProps({
active: {
type: Boolean,
@ -65,8 +72,22 @@ const props = defineProps({ @@ -65,8 +72,22 @@ const props = defineProps({
})
const state = reactive({
show: false
show: false,
current: {
"id": "",
"note_card": {
"interact_info": {},
"cover": {},
"image_list": [],
"display_title": "",
"user": {},
comment_list: [],
createTime: ''
}
},
d: false,
})
let rect = ref({})
watch(() => props.active, n => {
if (n && !state.show) {
@ -74,29 +95,59 @@ watch(() => props.active, n => { @@ -74,29 +95,59 @@ watch(() => props.active, n => {
}
}, {immediate: true})
function test(e) {
let rect = e.currentTarget.getBoundingClientRect()
console.log('e', rect)
let s = $('.shadow')
s.empty()
s.append($(e.currentTarget).clone())
function close() {
let s = $('.shadow ')
let domRect = rect.value
s.css('transition', 'all .3s')
s.css('top', domRect.top)
s.css('left', domRect.left)
s.css('width', domRect.width)
s.css('height', domRect.height)
// state.d = false
}
function test(e, item) {
let data = Mock.mock({
'comment_list|3-50': [{
name: '@cname',
text: '@cparagraph(3)'
}]
})
item.note_card.comment_list = data.comment_list
item.note_card.createTime = Mock.Random.date('MM-dd')
item.note_card.interact_info.collect_count = Mock.Random.integer(60, 3000)
item.note_card.interact_info.share_count = Mock.Random.integer(60, 3000)
state.current = cloneDeep(item)
console.log(state.current)
state.d = true
let domRect = e.currentTarget.getBoundingClientRect()
console.log('e', domRect)
let s = $('.shadow ')
let w = $('.shadow .wrap')
// w.empty()
// w.append($(e.currentTarget).clone())
s.css('transition', '0s')
s.css('top', rect.top)
s.css('left', rect.left)
s.css('width', rect.width)
s.css('top', domRect.top)
s.css('left', domRect.left)
s.css('width', domRect.width)
s.css('height', domRect.height)
rect.value = domRect
setTimeout(() => {
s.css('transition', 'all .3s')
s.css('top', 0)
s.css('left', 0)
s.css('width', '100vw')
s.css('height', '100vh')
})
}
</script>
<style scoped lang="less">
#Community {
font-size: 14rem;
color: white;
@ -196,7 +247,12 @@ function test(e) { @@ -196,7 +247,12 @@ function test(e) {
top: 0;
width: 100vw;
transition: all .3s;
}
overflow: hidden;
.wrap {
position: absolute;
z-index: 9999;
}
}
}
</style>

92
src/pages/other/AlbumDetail.vue

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
<template>
<div class="goods-detail base-page">
<div class="goods-detail base-page1">
<header>
<Icon
@click="$back()"
@click="$emit('close')"
icon="material-symbols-light:arrow-back-ios-new"/>
<div class="option" @click="nav('/home/search')">
<Icon icon="jam:search"/>
@ -11,42 +11,45 @@ @@ -11,42 +11,45 @@
<div class="slide-imgs">
<SlideHorizontal v-model:index="state.index">
<SlideItem v-for="item in state.detail.note_card?.image_list">
<SlideItem v-for="item in props.detail.note_card?.image_list">
<img :src="_checkImgUrl(item.info_list?.[0]?.url)" alt="">
</SlideItem>
</SlideHorizontal>
<div class="indicator-bar" v-if="state.detail.note_card?.image_list?.length > 1">
<div class="indicator-bar" v-if="props.detail.note_card?.image_list?.length > 1">
<div class="indicator"
:class="[i <= state.index+1 && 'active']"
v-for="i in state.detail.note_card?.image_list?.length"></div>
v-for="i in props.detail.note_card?.image_list?.length"></div>
</div>
</div>
<div class="content">
<div class="shop">
<header>
<img class="avatar" :src="_checkImgUrl(state.detail.note_card?.user?.avatar)"/>
<img class="avatar" :src="_checkImgUrl(props.detail.note_card?.user?.avatar)"/>
<div class="right">
<div class="name">{{ state.detail.note_card.user.nick_name }}</div>
<div class="r">关注</div>
<div class="name">{{ props.detail.note_card.user.nick_name }}</div>
<div class="r" @click="$emit('close')">关注</div>
</div>
</header>
<div class="desc">
{{ state.detail.note_card?.display_title }}
{{ props.detail.note_card?.display_title }}
</div>
<div class="date">{{ state.detail.note_card.createTime }}</div>
<div class="date">{{ props.detail.note_card.createTime }}</div>
</div>
<div class="card comments">
<header>
<span class="l">评论 {{ state.detail.note_card.comment_list.length }}</span>
<span class="l">评论 {{ props.detail.note_card.comment_list.length }}</span>
<div class="r">
<span>查看全部</span>
<Icon class="arrow" icon="mingcute:right-line"/>
</div>
</header>
<div class="comment" v-for="i in state.detail.note_card.comment_list.slice(0,2)">
<div class="comment"
@click="$emit('close')"
v-for="i in props.detail.note_card.comment_list.slice(0,2)">
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<span>
{{ i.name }}{{ i.text }}
@ -62,19 +65,19 @@ @@ -62,19 +65,19 @@
<div class="options">
<div class="option">
<Icon icon="solar:heart-linear"/>
<div class="text">{{ state.detail.note_card?.interact_info?.liked_count }}</div>
<div class="text">{{ props.detail.note_card?.interact_info?.liked_count }}</div>
</div>
<div class="option">
<Icon icon="mage:message-dots-round" class="icon"/>
<div class="text">{{ state.detail.note_card.comment_list.length }}</div>
<div class="text">{{ props.detail.note_card.comment_list.length }}</div>
</div>
<div class="option">
<Icon icon="mage:star"/>
<div class="text">{{ state.detail.note_card?.interact_info?.collect_count }}</div>
<div class="text">{{ props.detail.note_card?.interact_info?.collect_count }}</div>
</div>
<div class="option">
<Icon icon="ph:share-fat-light"/>
<div class="text">{{ state.detail.note_card?.interact_info?.share_count }}</div>
<div class="text">{{ props.detail.note_card?.interact_info?.share_count }}</div>
</div>
</div>
</div>
@ -84,12 +87,11 @@ @@ -84,12 +87,11 @@
<script setup>
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
import SlideItem from "@/components/slide/SlideItem.vue";
import {onMounted, reactive} from "vue";
import {reactive} from "vue";
import {useNav} from "@/utils/hooks/useNav";
import {Icon} from "@iconify/vue";
import {useBaseStore} from "@/store/pinia";
import {_checkImgUrl, cloneDeep} from "@/utils";
import Mock from 'mockjs'
import {_checkImgUrl} from "@/utils";
const nav = useNav()
const store = useBaseStore()
@ -98,36 +100,30 @@ defineOptions({ @@ -98,36 +100,30 @@ defineOptions({
name: 'Album-Detail'
})
const state = reactive({
const props = defineProps({
detail: {
"id": "",
"note_card": {
"interact_info": {},
"cover": {},
"image_list": [],
"display_title": "",
"user": {},
comment_list: [],
createTime: ''
type: Object,
default() {
return {
"id": "",
"note_card": {
"interact_info": {},
"cover": {},
"image_list": [],
"display_title": "",
"user": {},
comment_list: [],
createTime: ''
}
}
}
},
index: 0,
}
})
onMounted(() => {
state.detail = cloneDeep(store.routeData)
let data = Mock.mock({
'comment_list|3-50': [{
name: '@cname',
text: '@cparagraph(3)'
}]
})
state.detail.note_card.comment_list = data.comment_list
state.detail.note_card.createTime = Mock.Random.date('MM-dd')
state.detail.note_card.interact_info.collect_count = Mock.Random.integer(60, 3000)
state.detail.note_card.interact_info.share_count = Mock.Random.integer(60, 3000)
console.log('sta', state.detail)
const state = reactive({
index: 0,
})
</script>
<style scoped lang="less">
@ -142,10 +138,10 @@ onMounted(() => { @@ -142,10 +138,10 @@ onMounted(() => {
@red: rgb(248, 38, 74);
& > header {
position: fixed;
position: absolute;
left: 0;
top: 0;
width: 100vw;
width: 100%;
z-index: 9;
display: flex;
justify-content: space-between;
@ -163,7 +159,7 @@ onMounted(() => { @@ -163,7 +159,7 @@ onMounted(() => {
.slide-imgs {
position: relative;
height: 55vh;
max-height: 55vh;
img {
height: 100%;
@ -176,7 +172,7 @@ onMounted(() => { @@ -176,7 +172,7 @@ onMounted(() => {
position: absolute;
bottom: 5rem;
left: 3vw;
width: 94vw;
width: 94%;
display: flex;
gap: 5rem;

360
src/pages/other/AlbumDetail2.vue

@ -0,0 +1,360 @@ @@ -0,0 +1,360 @@
<template>
<div class="goods-detail base-page1">
<header>
<Icon
@click="$back()"
icon="material-symbols-light:arrow-back-ios-new"/>
<div class="option" @click="nav('/home/search')">
<Icon icon="jam:search"/>
</div>
</header>
<div class="slide-imgs">
<SlideHorizontal v-model:index="state.index">
<SlideItem v-for="item in state.detail.note_card?.image_list">
<img :src="_checkImgUrl(item.info_list?.[0]?.url)" alt="">
</SlideItem>
</SlideHorizontal>
<div class="indicator-bar" v-if="state.detail.note_card?.image_list?.length > 1">
<div class="indicator"
:class="[i <= state.index+1 && 'active']"
v-for="i in state.detail.note_card?.image_list?.length"></div>
</div>
</div>
<div class="content">
<div class="shop">
<header>
<img class="avatar" :src="_checkImgUrl(state.detail.note_card?.user?.avatar)"/>
<div class="right">
<div class="name">{{ state.detail.note_card.user.nick_name }}</div>
<div class="r">关注</div>
</div>
</header>
<div class="desc">
{{ state.detail.note_card?.display_title }}
</div>
<div class="date">{{ state.detail.note_card.createTime }}</div>
</div>
<div class="card comments">
<header>
<span class="l">评论 {{ state.detail.note_card.comment_list.length }}</span>
<div class="r">
<span>查看全部</span>
<Icon class="arrow" icon="mingcute:right-line"/>
</div>
</header>
<div class="comment" v-for="i in state.detail.note_card.comment_list.slice(0,2)">
<img src="https://cdn.seovx.com/?mom=302" alt="" class="avatar">
<span>
{{ i.name }}{{ i.text }}
</span>
</div>
</div>
</div>
<div class="toolbar">
<div class="input-wrap">
说点什么...
</div>
<div class="options">
<div class="option">
<Icon icon="solar:heart-linear"/>
<div class="text">{{ state.detail.note_card?.interact_info?.liked_count }}</div>
</div>
<div class="option">
<Icon icon="mage:message-dots-round" class="icon"/>
<div class="text">{{ state.detail.note_card.comment_list.length }}</div>
</div>
<div class="option">
<Icon icon="mage:star"/>
<div class="text">{{ state.detail.note_card?.interact_info?.collect_count }}</div>
</div>
<div class="option">
<Icon icon="ph:share-fat-light"/>
<div class="text">{{ state.detail.note_card?.interact_info?.share_count }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
import SlideItem from "@/components/slide/SlideItem.vue";
import {onMounted, reactive} from "vue";
import {useNav} from "@/utils/hooks/useNav";
import {Icon} from "@iconify/vue";
import {useBaseStore} from "@/store/pinia";
import {_checkImgUrl, cloneDeep} from "@/utils";
import Mock from 'mockjs'
const nav = useNav()
const store = useBaseStore()
defineOptions({
name: 'Album-Detail'
})
const state = reactive({
detail: {
"id": "",
"note_card": {
"interact_info": {},
"cover": {},
"image_list": [],
"display_title": "",
"user": {},
comment_list: [],
createTime: ''
}
},
index: 0,
})
onMounted(() => {
state.detail = cloneDeep(store.routeData)
let data = Mock.mock({
'comment_list|3-50': [{
name: '@cname',
text: '@cparagraph(3)'
}]
})
state.detail.note_card.comment_list = data.comment_list
state.detail.note_card.createTime = Mock.Random.date('MM-dd')
state.detail.note_card.interact_info.collect_count = Mock.Random.integer(60, 3000)
state.detail.note_card.interact_info.share_count = Mock.Random.integer(60, 3000)
console.log('sta', state.detail)
})
</script>
<style scoped lang="less">
@import "@/assets/less/index.less";
.goods-detail {
background: var(--color-message);
color: white;
font-size: 14rem;
@c: #a2a2a2;
@c2: #c0c0c0;
@red: rgb(248, 38, 74);
& > header {
position: fixed;
left: 0;
top: 0;
width: 100vw;
z-index: 9;
display: flex;
justify-content: space-between;
padding: 15rem;
box-sizing: border-box;
svg {
font-size: 20rem;
background: rgba(176, 176, 176, 0.4);
padding: 5rem;
color: white;
border-radius: 50%;
}
}
.slide-imgs {
position: relative;
height: 55vh;
img {
height: 100%;
width: 100%;
object-fit: cover;
touch-action: none;
}
.indicator-bar {
position: absolute;
bottom: 5rem;
left: 3vw;
width: 94vw;
display: flex;
gap: 5rem;
.indicator {
background: rgba(162, 160, 160, 0.5);
height: 3rem;
flex: 1;
border-radius: 2rem;
}
.active {
background: rgba(250, 246, 246, 0.58);
}
}
.index {
font-size: 12rem;
position: absolute;
padding: 3rem 10rem;
border-radius: 15rem;
background: rgba(91, 89, 89, 0.5);
right: 10rem;
bottom: 30rem;
color: white;
}
}
.card {
margin-top: 15rem;
border-radius: 10rem;
padding: 10rem 15rem;
background: black;
}
.arrow {
font-size: 16rem;
}
.content {
padding: 15rem;
padding-bottom: 10vh;
border-radius: 16rem 16rem 0 0;
.comments {
& > header {
margin-bottom: 16rem;
display: flex;
justify-content: space-between;
align-items: center;
.l {
font-size: 15rem;
}
.r {
color: gray;
font-size: 12rem;
display: flex;
align-items: center;
}
}
.comment {
margin-bottom: 16rem;
display: flex;
align-items: center;
gap: 5rem;
span {
display: inline-block;
white-space: nowrap;
flex: 1;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
}
img {
border-radius: 50%;
width: 20rem;
height: 20rem;
}
&:last-child {
margin-bottom: 0;
}
}
}
.shop {
& > header {
display: flex;
align-items: center;
gap: 10rem;
img {
width: 36rem;
height: 36rem;
border-radius: 50%;
}
.right {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
.name {
font-size: 16rem;
}
.r {
border-radius: 4rem;
padding: 6rem 16rem;
background: var(--primary-btn-color);
font-size: 12rem;
color: white;
}
}
}
.desc {
margin-top: 10rem;
}
.date {
font-size: 12rem;
margin-top: 10rem;
color: gray;
}
}
}
.toolbar {
position: fixed;
bottom: 0;
width: 100vw;
left: 0;
background: var(--color-message);
border-top: 1px solid rgba(white, .1);
display: flex;
align-items: center;
padding: 8rem 10rem;
padding-right: 0;
box-sizing: border-box;
gap: 6rem;
.input-wrap {
width: 110rem;
padding-left: 15rem;
height: 34rem;
border-radius: 30rem;
background: var(--second-btn-color-tran);
color: gray;
display: flex;
align-items: center;
}
.options {
flex: 1;
display: flex;
.option {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 13rem;
color: white;
svg {
font-size: 24rem;
}
}
}
}
}
</style>
Loading…
Cancel
Save