zyronon 1 year ago
parent
commit
68b225d839
  1. 4
      package.json
  2. 2
      src/components/Call.vue
  3. 2
      src/components/Loading.vue
  4. 14
      src/components/Scroll.vue
  5. 67
      src/components/ScrollList.vue
  6. 45
      src/components/WaterfallList.vue
  7. 15
      src/mock/index.js
  8. 4
      src/pages/home/components/IndicatorHome.vue
  9. 6
      src/pages/home/index.vue
  10. 234
      src/pages/home/slide/Community.vue
  11. 16
      src/pages/message/AllMessage.vue
  12. 30
      src/pages/message/chat/Chat.vue
  13. 3
      src/pages/message/components/ChatMessage.vue

4
package.json

@ -21,14 +21,14 @@ @@ -21,14 +21,14 @@
"vue": "3.4.21",
"vue-masonry": "0.16.0",
"vue-router": "4.3.0",
"vue-switches": "2.0.1"
"vue-switches": "2.0.1",
"axios-mock-adapter": "^1.22.0"
},
"devDependencies": {
"@iconify/vue": "^4.1.1",
"@types/lodash-es": "^4.17.9",
"@vitejs/plugin-vue": "4.0.0",
"@vitejs/plugin-vue-jsx": "3.0.0",
"axios-mock-adapter": "^1.22.0",
"less": "4.1.3",
"vite-plugin-compression": "^0.5.1",
"rollup-plugin-visualizer": "^5.9.2",

2
src/components/Call.vue

@ -135,8 +135,6 @@ export default { @@ -135,8 +135,6 @@ export default {
</style>
<style scoped lang="less">
.call-float {
transition-property: all;
z-index: 9;

2
src/components/Loading.vue

@ -32,7 +32,7 @@ export default { @@ -32,7 +32,7 @@ export default {
&.full {
z-index: 999;
position: fixed;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);

14
src/components/Scroll.vue

@ -7,11 +7,13 @@ @@ -7,11 +7,13 @@
<Loading :is-full-screen="false" :style="pullUpStyle"/>
<div class="scroll-content" :style="pullUpStyle">
<slot></slot>
<Loading v-if="loading" :is-full-screen="false"/>
</div>
</div>
<div v-else class="scroll-wrapper scroll Scroll" ref="wrapper" @scroll="scroll">
<div class="scroll-content">
<slot></slot>
<Loading v-if="loading" :is-full-screen="fullLoading"/>
</div>
</div>
</template>
@ -32,6 +34,14 @@ export default { @@ -32,6 +34,14 @@ export default {
useRefresh: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
fullLoading: {
type: Boolean,
default: false
}
},
data() {
@ -110,5 +120,9 @@ export default { @@ -110,5 +120,9 @@ export default {
.scroll-wrapper {
overflow: auto;
.scroll-content {
padding-bottom: 30rem;
}
}
</style>

67
src/components/ScrollList.vue

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
<template>
<Scroll
:loading="state.loading"
:full-loading="!state.list.length"
@pulldown="loadData">
<slot :list="state.list"></slot>
<NoMore v-if="state.total !== 0 && state.total === state.list.length"/>
</Scroll>
</template>
<script setup>
import {onMounted, reactive} from "vue";
import {_notice} from "@/utils";
import Scroll from "@/components/Scroll.vue";
import NoMore from "@/components/NoMore.vue";
const props = defineProps({
api: {
type: Function,
default() {
return () => void 0
}
}
})
const state = reactive({
list: [],
total: 0,
pageNo: 0,
pageSize: 10,
loading: false
})
function loadData() {
if (state.loading) return
state.pageNo++
getData()
}
async function getData(refresh = false) {
if (refresh) {
state.pageNo = 0
} else {
if (state.total !== 0 && state.total === state.list.length) return
}
if (state.loading) return
state.loading = true
let res = await props.api({pageNo: state.pageNo, pageSize: state.pageSize})
state.loading = false
if (res.success) {
if (refresh) {
state.list = res.data.list
} else {
state.list = state.list.concat(res.data.list)
}
state.total = res.data.total
} else {
_notice('查询失败')
}
}
onMounted(getData)
</script>
<style scoped lang="less">
</style>

45
src/components/WaterfallList.vue

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
<script setup>
import {computed} from "vue";
const props = defineProps({
list: {
type: Array,
default() {
return []
}
}
})
const leftList = computed(() => {
return props.list.filter((v, index) => index % 2 === 0)
})
const rightList = computed(() => {
return props.list.filter((v, index) => index % 2 !== 0)
})
</script>
<template>
<div class="waterfall">
<div class="waterfall-row">
<slot :item="item" v-for="item in leftList"></slot>
</div>
<div class="waterfall-row">
<slot :item="item" v-for="item in rightList"></slot>
</div>
</div>
</template>
<style scoped lang="less">
.waterfall {
display: flex;
gap: 10rem;
.waterfall-row {
width: 50%;
display: flex;
flex-direction: column;
}
}
</style>

15
src/mock/index.js

@ -6,7 +6,7 @@ import {useBaseStore} from "@/store/pinia"; @@ -6,7 +6,7 @@ import {useBaseStore} from "@/store/pinia";
import axiosInstance from "@/utils/request";
import MockAdapter from "axios-mock-adapter";
const mock = new MockAdapter(axiosInstance);
const mock = new MockAdapter(axiosInstance, {delayResponse: 300});
function getPage2(params) {
let offset = params.pageNo * params.pageSize
@ -71,12 +71,6 @@ async function fetchData() { @@ -71,12 +71,6 @@ async function fetchData() {
allRecommendVideos = allRecommendVideos.concat(v)
})
})
fetch(BASE_URL + '/data/posts.json').then(r => {
r.json().then(v => {
allRecommendPosts = v
})
})
}
export async function startMock() {
@ -192,11 +186,16 @@ export async function startMock() { @@ -192,11 +186,16 @@ export async function startMock() {
mock.onGet(/post\/recommended/).reply(async (config) => {
let page = getPage2(config.params)
if (!allRecommendPosts.length) {
let r = await fetch(BASE_URL + '/data/posts.json')
allRecommendPosts = await r.json()
}
return [200, {
data: {
pageNo: page.pageNo,
total: allRecommendPosts.length,
list: allRecommendPosts.slice(page.offset, page.limit),
list: allRecommendPosts.slice(0, 1000).slice(page.offset, page.limit),
}, code: 200, msg: '',
}]
})

4
src/pages/home/components/IndicatorHome.vue

@ -17,13 +17,13 @@ @@ -17,13 +17,13 @@
<img v-show="index === 0" src="../../../assets/img/icon/arrow-up-white.png" class="tab1-img">
</div>
<div class="tab" :class="{active:index === 1}" @click.stop="change(1)">
<span>社区</span>
<span>长视频</span>
</div>
<div class="tab" :class="{active:index === 2}" @click.stop="change(2)">
<span>关注</span>
<img src="../../../assets/img/icon/live.webp" class="tab2-img">
</div>
<div class="tab" :class="{active:index === 3}" @click.stop="change(3)"><span>长视频</span>
<div class="tab" :class="{active:index === 3}" @click.stop="change(3)"><span>经验</span>
</div>
<div class="tab" :class="{active:index === 4}" @click.stop="change(4)"><span>推荐</span>
</div>

6
src/pages/home/index.vue

@ -107,11 +107,11 @@ @@ -107,11 +107,11 @@
v-model:index="state.navIndex">
<Slide0 :active="state.navIndex === 0 && state.baseIndex === 1"/>
<SlideItem>
<Community :active="state.navIndex === 1 && state.baseIndex === 1"/>
<LongVideo :active="state.navIndex === 1 && state.baseIndex === 1"/>
</SlideItem>
<Slide2 :active="state.navIndex === 2 && state.baseIndex === 1"/>
<SlideItem>
<LongVideo :active="state.navIndex === 3 && state.baseIndex === 1"/>
<Community :active="state.navIndex === 3 && state.baseIndex === 1"/>
</SlideItem>
<Slide4 :active="state.navIndex === 4 && state.baseIndex === 1"/>
</SlideHorizontal>
@ -223,7 +223,7 @@ const baseStore = useBaseStore() @@ -223,7 +223,7 @@ const baseStore = useBaseStore()
const state = reactive({
baseIndex: 1,
navIndex: 4,
navIndex: 3,
test: '',
recommendList: [],
isSharing: false,

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

@ -1,45 +1,60 @@ @@ -1,45 +1,60 @@
<template>
<div id="Community">
<Scroll class="Scroll"
@pulldown="loadData">
<div v-masonry class="goods-list"
transition-duration="0s"
item-selector=".goods">
<div v-masonry-tile class="goods"
@click="nav('album-detail',{},item)"
v-for="(item, index) in state.list">
<div class="card">
<!-- <img class="poster" v-lazy="Utils.$imgPreview(item.src)"/>-->
<img class="poster" :src="_checkImgUrl(item.note_card?.cover?.url_default)"/>
<div class="bottom">
<div class="title">
{{ item.note_card?.display_title }}
</div>
<div class="b2">
<div class="user">
<img class="avatar" :src="_checkImgUrl(item.note_card?.user?.avatar)"/>
<div class="name">{{ item.note_card?.user?.nickname }}</div>
<ScrollList class="Scroll"
v-if="state.show"
:api="recommendedPost"
>
<template v-slot="{list}">
<div class="search" @click="nav('/home/search')">
<div class="left">
<Icon class="icon" icon="ion:search" @click.stop="$no()"/>
<span>壁纸</span>
</div>
<div class="right">搜索</div>
</div>
<WaterfallList :list="list" class="list">
<template v-slot="{item}">
<div class="card"
@click="test"
>
<img class="poster" v-lazy="_checkImgUrl(item.note_card?.cover?.url_default)"/>
<div class="bottom">
<div class="title">
{{ item.note_card?.display_title }}
</div>
<div class="star">
<Icon icon="solar:heart-linear"/>
<div class="num">{{ item.note_card?.interact_info?.liked_count }}</div>
<div class="b2">
<div class="user">
<img class="avatar" :src="_checkImgUrl(item.note_card?.user?.avatar)"/>
<div class="name">{{ item.note_card?.user?.nickname }}</div>
</div>
<div class="star">
<Icon icon="solar:heart-linear"/>
<div class="num">{{ item.note_card?.interact_info?.liked_count }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Scroll>
</template>
</WaterfallList>
</template>
</ScrollList>
<div class="shadow">
</div>
</div>
</template>
<script setup>
import {reactive, watch} from "vue";
import {_checkImgUrl, _notice} from "@/utils";
import Scroll from "@/components/Scroll.vue";
import {$no, _checkImgUrl} 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";
//@click="nav('album-detail',{},item)"
const nav = useNav()
const props = defineProps({
@ -50,42 +65,33 @@ const props = defineProps({ @@ -50,42 +65,33 @@ const props = defineProps({
})
const state = reactive({
list: [],
listEl: null,
total: 0,
pageNo: 0,
pageSize: 10,
show: false
})
watch(() => props.active, n => {
if (n && !state.list.length) {
getData(true, true)
}
})
function loadData() {
state.pageNo++
getData()
}
async function getData(loading = true, refresh = false) {
if (refresh) {
state.pageNo = 0
}
let res = await recommendedPost({pageNo: state.pageNo, pageSize: state.pageSize,})
console.log('res', res)
if (res.success) {
if (refresh) {
state.list = res.data.list
} else {
state.list = state.list.concat(res.data.list)
}
state.total = res.data.total
} else {
_notice('查询失败')
if (n && !state.show) {
state.show = true
}
}, {immediate: true})
function test(e) {
let rect = e.currentTarget.getBoundingClientRect()
console.log('e', rect)
let s = $('.shadow')
s.empty()
s.append($(e.currentTarget).clone())
s.css('transition', '0s')
s.css('top', rect.top)
s.css('left', rect.left)
s.css('width', rect.width)
setTimeout(() => {
s.css('transition', 'all .3s')
s.css('top', 0)
s.css('left', 0)
s.css('width', '100vw')
})
}
</script>
<style scoped lang="less">
@ -103,66 +109,94 @@ async function getData(loading = true, refresh = false) { @@ -103,66 +109,94 @@ async function getData(loading = true, refresh = false) {
@p: 1rem;
.goods-list {
padding: @p;
.search {
margin-left: 2vw;
width: 96vw;
box-sizing: border-box;
padding: 10rem;
border: 1px solid #646464;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16rem;
margin-bottom: 10rem;
border-radius: 8rem;
.left {
display: flex;
align-items: center;
gap: 5rem;
color: gray;
svg {
font-size: 16rem;
}
}
}
.goods {
width: calc(50% - @p);
padding: 3rem;
box-sizing: border-box;
.list {
margin-left: 2vw;
width: 96vw;
}
.card {
border-radius: 4rem;
overflow: hidden;
background: var(--main-bg);
.card {
border-radius: 4rem;
overflow: hidden;
background: var(--main-bg);
img {
width: 100%;
}
img {
width: 100%;
.bottom {
color: gainsboro;
padding: 10rem;
.title {
font-size: 14rem;
margin-bottom: 8rem;
}
.bottom {
color: gainsboro;
padding: 10rem;
.b2 {
display: flex;
justify-content: space-between;
align-items: center;
.user {
display: flex;
font-size: 12rem;
.title {
font-size: 15rem;
margin-bottom: 8rem;
img {
width: 15rem;
border-radius: 50%;
margin-right: 5rem;
}
}
.b2 {
.star {
display: flex;
justify-content: space-between;
align-items: center;
gap: 3rem;
.user {
display: flex;
font-size: 12rem;
img {
width: 15rem;
border-radius: 50%;
margin-right: 10rem;
}
svg {
font-size: 15rem;
}
.star {
display: flex;
align-items: center;
gap: 3rem;
svg {
font-size: 16rem;
}
.num {
font-size: 13rem;
}
.num {
font-size: 12rem;
}
}
}
}
}
.shadow {
position: absolute;
left: 0;
top: 0;
width: 100vw;
transition: all .3s;
}
}
</style>

16
src/pages/message/AllMessage.vue

@ -45,6 +45,7 @@ @@ -45,6 +45,7 @@
v-else
ref="mainScroll"
:use-refresh="true"
:loading="loadingMore"
@refresh="refresh"
@pulldown="loadData">
<div class="messages">
@ -110,7 +111,6 @@ @@ -110,7 +111,6 @@
<Peoples v-model:list="recommend"
:loading="loadingMore"
mode="recommend"/>
<Loading :is-full-screen="false" v-if="loadingMore"/>
</Scroll>
</div>
</div>
@ -213,17 +213,6 @@ export default { @@ -213,17 +213,6 @@ export default {
<style scoped lang="less">
.list-complete-enter-from,
.list-complete-leave-to {
opacity: 0;
}
.list-complete-leave-active {
position: absolute;
}
#AllMessage {
position: fixed;
left: 0;
@ -274,7 +263,7 @@ export default { @@ -274,7 +263,7 @@ export default {
}
.content {
padding: var(--page-padding);
padding:0 var(--page-padding);
padding-top: var(--common-header-height);
.scroll {
@ -297,6 +286,7 @@ export default { @@ -297,6 +286,7 @@ export default {
.avatar {
width: 48rem;
height: 48rem;
border-radius: 50%;
}

30
src/pages/message/chat/Chat.vue

@ -215,7 +215,7 @@ export default { @@ -215,7 +215,7 @@ export default {
data: '',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -230,7 +230,7 @@ export default { @@ -230,7 +230,7 @@ export default {
},
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -255,7 +255,7 @@ export default { @@ -255,7 +255,7 @@ export default {
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
},
loved: [
@ -285,7 +285,7 @@ export default { @@ -285,7 +285,7 @@ export default {
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
},
readState: READ_STATE.ARRIVED
@ -296,7 +296,7 @@ export default { @@ -296,7 +296,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -306,7 +306,7 @@ export default { @@ -306,7 +306,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -316,7 +316,7 @@ export default { @@ -316,7 +316,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -326,7 +326,7 @@ export default { @@ -326,7 +326,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -336,7 +336,7 @@ export default { @@ -336,7 +336,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -346,7 +346,7 @@ export default { @@ -346,7 +346,7 @@ export default {
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -372,7 +372,7 @@ export default { @@ -372,7 +372,7 @@ export default {
},
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -381,7 +381,7 @@ export default { @@ -381,7 +381,7 @@ export default {
data: '又在刷抖音',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -390,7 +390,7 @@ export default { @@ -390,7 +390,7 @@ export default {
data: '我昨天@你那个视频发给我下',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -408,7 +408,7 @@ export default { @@ -408,7 +408,7 @@ export default {
data: '我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了',
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
@ -437,7 +437,7 @@ export default { @@ -437,7 +437,7 @@ export default {
},
time: '2021-01-02 21:21',
user: {
id: '93864497380',
id: '2739632844317827',
avatar: '../../../assets/img/icon/head-image.jpg'
}
},

3
src/pages/message/components/ChatMessage.vue

@ -94,6 +94,7 @@ @@ -94,6 +94,7 @@
</template>
</div>
</template>
<script>
import {mapState} from "pinia";
@ -153,7 +154,7 @@ export default { @@ -153,7 +154,7 @@ export default {
computed: {
...mapState(useBaseStore, ['userinfo']),
isMe() {
return this.userinfo.id === this.message.user.id
return this.userinfo.uid === this.message.user.id
}
},
created() {

Loading…
Cancel
Save