Browse Source

清除测试组件

pull/40/head
zyronon 1 year ago
parent
commit
7e18fe228d
  1. 1
      package.json
  2. 132
      pnpm-lock.yaml
  3. 104
      src/components/BaseMarquee.vue
  4. 126
      src/components/Posters.vue
  5. 165
      src/components/UserPanel.vue
  6. 8
      src/components/Video.vue
  7. 2
      src/components/slide/BVideo.vue
  8. 9
      src/components/slide/ItemDesc.vue
  9. 2
      src/components/slide/SlideAlbum.vue
  10. 11
      src/components/slide/SlideVerticalInfinite.vue
  11. 699
      src/components/slide/SlideVideo.vue
  12. 322
      src/components/slide/UNUSE_SlideColumnVirtualList.txt
  13. 184
      src/components/slide/VInfinite-Component.vue
  14. 4
      src/main.js
  15. 2
      src/mock/index.js
  16. 2
      src/pages/home/SearchPage.vue
  17. 18
      src/pages/home/index.vue
  18. 18
      src/pages/home/slide/LongVideo.vue
  19. 14
      src/pages/home/slide/SlideList.vue
  20. 379
      src/pages/me/VideoDetail.vue
  21. 2
      src/pages/message/JoinedGroupChat.vue
  22. 2
      src/pages/message/Share2Friend.vue
  23. 166
      src/pages/slideHooks/InfiniteList.vue
  24. 40
      src/pages/test/Test.vue
  25. 147
      src/pages/test/TestImg.vue
  26. 404
      src/pages/test/TestSlide.vue
  27. 111
      src/pages/test/TestSwiperJs.vue
  28. 278
      src/pages/test/slide.jsx
  29. 4
      src/router/routes.js
  30. 2
      src/store/index.js
  31. 11
      src/store/pinia.js
  32. 3
      src/utils/index.jsx
  33. 2
      src/utils/mixin.js
  34. 3
      vite.config.js

1
package.json

@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
"less": "4.1.3",
"mobile-select": "1.1.2",
"unplugin-vue-macros": "^2.7.10",
"unplugin-vue-define-options": "^1.4.1",
"vite": "4.5.2"
}
}

132
pnpm-lock.yaml

@ -79,6 +79,9 @@ devDependencies: @@ -79,6 +79,9 @@ devDependencies:
mobile-select:
specifier: 1.1.2
version: 1.1.2
unplugin-vue-define-options:
specifier: ^1.4.1
version: 1.4.2(vue@3.4.21)
unplugin-vue-macros:
specifier: ^2.7.10
version: 2.7.10(vite@4.5.2)(vue@3.4.21)
@ -1509,6 +1512,15 @@ packages: @@ -1509,6 +1512,15 @@ packages:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
/errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
hasBin: true
requiresBuild: true
dependencies:
prr: 1.0.1
dev: true
optional: true
/esbuild@0.18.20:
resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
engines: {node: '>=12'}
@ -1709,6 +1721,14 @@ packages: @@ -1709,6 +1721,14 @@ packages:
dev: true
optional: true
/image-size@0.5.5:
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
engines: {node: '>=0.10.0'}
hasBin: true
requiresBuild: true
dev: true
optional: true
/imagesloaded@4.1.4:
resolution: {integrity: sha512-ltiBVcYpc/TYTF5nolkMNsnREHW+ICvfQ3Yla2Sgr71YFwQ86bDwV9hgpFhFtrGPuwEx5+LqOHIrdXBdoWwwsA==}
dependencies:
@ -1798,13 +1818,13 @@ packages: @@ -1798,13 +1818,13 @@ packages:
parse-node-version: 1.0.1
tslib: 2.6.2
optionalDependencies:
errno: r2.cnpmjs.org/errno@0.1.8
errno: 0.1.8
graceful-fs: 4.2.11
image-size: r2.cnpmjs.org/image-size@0.5.5
make-dir: r2.cnpmjs.org/make-dir@2.1.0
mime: r2.cnpmjs.org/mime@1.6.0
image-size: 0.5.5
make-dir: 2.1.0
mime: 1.6.0
needle: 3.2.0
source-map: r2.cnpmjs.org/source-map@0.6.1
source-map: 0.6.1
transitivePeerDependencies:
- supports-color
dev: true
@ -1853,6 +1873,16 @@ packages: @@ -1853,6 +1873,16 @@ packages:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
/make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
engines: {node: '>=6'}
requiresBuild: true
dependencies:
pify: 4.0.1
semver: 5.7.2
dev: true
optional: true
/make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
@ -1881,6 +1911,14 @@ packages: @@ -1881,6 +1911,14 @@ packages:
mime-db: 1.52.0
dev: false
/mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
engines: {node: '>=4'}
hasBin: true
requiresBuild: true
dev: true
optional: true
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
requiresBuild: true
@ -2014,6 +2052,19 @@ packages: @@ -2014,6 +2052,19 @@ packages:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: true
/nodejieba@2.5.2:
resolution: {integrity: sha512-ByskJvaBrQ2eV+5M0OeD80S5NKoGaHc9zi3Z/PTKl/95eac2YF8RmWduq9AknLpkQLrLAIcqurrtC6BzjpKwwg==}
engines: {node: '>= 10.20.0'}
requiresBuild: true
dependencies:
'@mapbox/node-pre-gyp': 1.0.11
node-addon-api: 3.2.1
transitivePeerDependencies:
- encoding
- supports-color
dev: false
optional: true
/nopt@5.0.0:
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
engines: {node: '>=6'}
@ -2116,7 +2167,7 @@ packages: @@ -2116,7 +2167,7 @@ packages:
commander: 1.1.1
object-assign: 4.1.1
optionalDependencies:
nodejieba: r2.cnpmjs.org/nodejieba@2.5.2
nodejieba: 2.5.2
transitivePeerDependencies:
- encoding
- supports-color
@ -2268,7 +2319,7 @@ packages: @@ -2268,7 +2319,7 @@ packages:
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: false
requiresBuild: true
/ssr-window@4.0.2:
resolution: {integrity: sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==}
@ -2655,70 +2706,3 @@ packages: @@ -2655,70 +2706,3 @@ packages:
requiresBuild: true
dev: false
optional: true
r2.cnpmjs.org/errno@0.1.8:
resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/errno/-/errno-0.1.8.tgz}
name: errno
version: 0.1.8
hasBin: true
requiresBuild: true
dependencies:
prr: 1.0.1
dev: true
optional: true
r2.cnpmjs.org/image-size@0.5.5:
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/image-size/-/image-size-0.5.5.tgz}
name: image-size
version: 0.5.5
engines: {node: '>=0.10.0'}
hasBin: true
requiresBuild: true
dev: true
optional: true
r2.cnpmjs.org/make-dir@2.1.0:
resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/make-dir/-/make-dir-2.1.0.tgz}
name: make-dir
version: 2.1.0
engines: {node: '>=6'}
requiresBuild: true
dependencies:
pify: 4.0.1
semver: 5.7.2
dev: true
optional: true
r2.cnpmjs.org/mime@1.6.0:
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/mime/-/mime-1.6.0.tgz}
name: mime
version: 1.6.0
engines: {node: '>=4'}
hasBin: true
requiresBuild: true
dev: true
optional: true
r2.cnpmjs.org/nodejieba@2.5.2:
resolution: {integrity: sha512-ByskJvaBrQ2eV+5M0OeD80S5NKoGaHc9zi3Z/PTKl/95eac2YF8RmWduq9AknLpkQLrLAIcqurrtC6BzjpKwwg==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/nodejieba/-/nodejieba-2.5.2.tgz}
name: nodejieba
version: 2.5.2
engines: {node: '>= 10.20.0'}
requiresBuild: true
dependencies:
'@mapbox/node-pre-gyp': 1.0.11
node-addon-api: 3.2.1
transitivePeerDependencies:
- encoding
- supports-color
dev: false
optional: true
r2.cnpmjs.org/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, registry: https://r.cnpmjs.org/, tarball: https://r2.cnpmjs.org/source-map/-/source-map-0.6.1.tgz}
name: source-map
version: 0.6.1
engines: {node: '>=0.10.0'}
requiresBuild: true
dev: true
optional: true

104
src/components/BaseMarquee.vue

@ -1,104 +0,0 @@ @@ -1,104 +0,0 @@
<template>
<div class="marquee" ref="marquee">
<span class="text" ref="marqueeText">
{{ text }}<span class="space"></span>
{{ text }}<span class="space"></span>
{{ text }}<span class="space"></span>
</span>
</div>
</template>
<script>
import Dom from "../utils/dom";
import {nextTick} from "vue";
export default {
name: "BaseMarquee",
props: {
text: {
type: String,
default: ''
},
},
data() {
return {
timer: null,
contentWidth: 0,
transformX: 0,
$marqueeContent: null,
}
},
methods: {
pause() {
// console.log('pause')
cancelAnimationFrame(this.timer)
},
stop() {
// console.log('stop')
cancelAnimationFrame(this.timer)
this.transformX = 0
this.marqueeText.css('transform', `translate3d(0,0,0)`)
},
start() {
// console.log('start')
if (this.contentWidth <= 0) { //
return;
}
let fn = () => {
if (this.transformX > (-this.contentWidth / 3)) {
this.transformX -= 1
this.marqueeText.css('transform', `translate3d(${this.transformX}px,0,0)`)
} else {
this.transformX = 0
}
this.timer = requestAnimationFrame(fn)
}
fn()
}
},
mounted() {
nextTick(() => {
//document.querySelectorAlldom$refs
this.marqueeText = new Dom(this.$refs.marqueeText)
//nextTickdomwidth
this.contentWidth = this.marqueeText.getWidth()
// console.log(this.name, this.isPlay, this.marqueeText)
// console.log(this.name, this.isPlay, this.contentWidth)
new Dom(this.$refs.marquee).on('pause', this.pause)
new Dom(this.$refs.marquee).on('start', this.start)
new Dom(this.$refs.marquee).on('stop', this.stop)
if (this.isPlay) {
this.start()
}
})
}
}
</script>
<style scoped lang="less">
.marquee {
width: 100%;
display: block;
margin: 0 auto;
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
position: relative;
.text {
color: white;
display: inline-block;
position: relative;
white-space: nowrap;
.space {
display: inline-block;
width: 50rem;
}
}
}
</style>

126
src/components/Posters.vue

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
<template>
<div class="posters">
<div class="poster-item" v-for="(i,index) in list" @click="$no">
<!-- @click="$nav('/video-detail')"-->
<img class="poster" v-lazy="$checkImgUrl(i.video.cover.url_list[0])" alt="">
<div class="poster-item" v-for="(i,index) in list"
@click="goDetail(index)">
<img class="poster" v-lazy="_checkImgUrl(i.video.cover.url_list[0])" alt="">
<div class="num" v-if="mode === 'normal'">
<Icon icon="icon-park-outline:like" />
<span>{{ formatNumber(i.statistics.digg_count) }}</span>
<Icon icon="icon-park-outline:like"/>
<span>{{ _formatNumber(i.statistics.digg_count) }}</span>
</div>
<div class="date" v-if="mode === 'date'">
<div class="day">{{ getDay(i.create_time) }}</div>
@ -20,61 +20,75 @@ @@ -20,61 +20,75 @@
</div>
</template>
<script>
import {_checkImgUrl, $no} from "@/utils";
<script setup>
import {_checkImgUrl, _formatNumber} from "@/utils";
import {useBaseStore} from "@/store/pinia";
import {useRouter} from "vue-router";
import {cloneDeep} from "lodash-es";
export default {
/*@click="$nav('/video-detail')"*/
name: "Posters",
props: {
list: {
type: [Array, Number],
default: () => {
return []
}
},
mode: {
type: String,
default: 'normal'//date,music
const store = useBaseStore()
const nav = useRouter()
const props = defineProps({
list: {
type: [Array, Number],
default: () => {
return []
}
},
methods: {
$no,
$checkImgUrl: _checkImgUrl,
getDay(time) {
let date = new Date(time * 1000)
return date.getDate()
},
getMonth(time) {
let date = new Date(time * 1000)
let month = date.getMonth() + 1
switch (month) {
case 1:
return '一月'
case 2:
return '二月'
case 3:
return '三月'
case 4:
return '四月'
case 5:
return '五月'
case 6:
return '六月'
case 7:
return '七月'
case 8:
return '八月'
case 9:
return '九月'
case 10:
return '十月'
case 11:
return '十一月'
case 12:
return '十二月'
}
author: {
type: Object,
default: () => {
return {}
}
},
mode: {
type: String,
default: 'normal'//date,music
}
})
defineOptions({
name: 'Posters'
})
function goDetail(index) {
store.routeData = cloneDeep({list: props.list, author: props.author, index})
nav.push({path: '/video-detail'})
}
function getDay(time) {
let date = new Date(time * 1000)
return date.getDate()
}
function getMonth(time) {
let date = new Date(time * 1000)
let month = date.getMonth() + 1
switch (month) {
case 1:
return '一月'
case 2:
return '二月'
case 3:
return '三月'
case 4:
return '四月'
case 5:
return '五月'
case 6:
return '六月'
case 7:
return '七月'
case 8:
return '八月'
case 9:
return '九月'
case 10:
return '十月'
case 11:
return '十一月'
case 12:
return '十二月'
}
}
</script>

165
src/components/UserPanel.vue

@ -96,94 +96,96 @@ @@ -96,94 +96,96 @@
</div>
</div>
</div>
<template v-if="props.currentItem.isRequest">
<div class="other">
<div class="scroll-x" @touchmove="stop">
<div class="item" v-for="item in props.currentItem.author.card_entries">
<img :src="item.icon_dark.url_list[0]" alt="">
<div class="right">
<div class="top">{{ item.title }}</div>
<div class="bottom">{{ item.sub_title }}</div>
</div>
<div class="other">
<div class="scroll-x" @touchmove="stop">
<div class="item" v-for="item in props.currentItem.author.card_entries">
<img :src="item.icon_dark.url_list[0]" alt="">
<div class="right">
<div class="top">{{ item.title }}</div>
<div class="bottom">{{ item.sub_title }}</div>
</div>
</div>
</div>
</div>
<div class="my-buttons">
<div class="follow-display">
<div class="follow-wrapper"
:class="props.currentItem.author.follow_status ? 'follow-wrapper-followed' : ''">
<div class="no-follow" @click="props.currentItem.author.follow_status = 1">
<img src="@/assets/img/icon/add-white.png" alt="">
<span>关注</span>
<div class="my-buttons">
<div class="follow-display">
<div class="follow-wrapper"
:class="props.currentItem.author.follow_status ? 'follow-wrapper-followed' : ''">
<div class="no-follow" @click="props.currentItem.author.follow_status = 1">
<img src="@/assets/img/icon/add-white.png" alt="">
<span>关注</span>
</div>
<div class="followed">
<div class="l-button" @click="$emit('showFollowSetting2')">
<span>已关注</span>
<Icon icon="bxs:down-arrow" class="arrow"/>
</div>
<div class="followed">
<div class="l-button" @click="$emit('showFollowSetting2')">
<span>已关注</span>
<Icon icon="bxs:down-arrow" class="arrow"/>
</div>
<div class="l-button" @click="$nav('/message/chat')">
<span>私信</span>
</div>
<div class="l-button" @click="$nav('/message/chat')">
<span>私信</span>
</div>
</div>
</div>
<div class="option"
:class="state.isShowRecommend?'option-recommend':''"
@click="state.isShowRecommend = !state.isShowRecommend">
<img v-if="state.loadings.showRecommend" class="loading" src="@/assets/img/icon/loading-gray.png"
alt="">
<Icon icon="bxs:down-arrow" v-else class="arrow"/>
</div>
</div>
<div class="option"
:class="state.isShowRecommend?'option-recommend':''"
@click="state.isShowRecommend = !state.isShowRecommend">
<img v-if="state.loadings.showRecommend" class="loading" src="@/assets/img/icon/loading-gray.png"
alt="">
<Icon icon="bxs:down-arrow" v-else class="arrow"/>
</div>
</div>
<div class="recommend" :class="{hidden:!state.isShowRecommend}">
<div class="title">
<span>你可能感兴趣</span>
<img src="@/assets/img/icon/about-gray.png">
</div>
<div class="friends"
@touchmove="stop">
<div class="friend" v-for="item in friends.all">
<img :style="item.select?'opacity: .5;':''" class="avatar" :src="_checkImgUrl(item.avatar)" alt="">
<span class="name">{{ item.name }}</span>
<span class="tips">可能感兴趣的人</span>
<dy-button type="primary">关注</dy-button>
<div class="close">
<dy-back img="close" scale=".6"></dy-back>
</div>
<div class="recommend" :class="{hidden:!state.isShowRecommend}">
<div class="title">
<span>你可能感兴趣</span>
<img src="@/assets/img/icon/about-gray.png">
</div>
<div class="friends"
@touchmove="stop">
<div class="friend" v-for="item in friends.all">
<img :style="item.select?'opacity: .5;':''" class="avatar" :src="_checkImgUrl(item.avatar)" alt="">
<span class="name">{{ item.name }}</span>
<span class="tips">可能感兴趣的人</span>
<dy-button type="primary">关注</dy-button>
<div class="close">
<dy-back img="close" scale=".6"></dy-back>
</div>
<div class="more" @click="$nav('/people/find-acquaintance')">
<div class="notice">
<div>点击查看</div>
<div>更多好友</div>
</div>
</div>
<div class="more" @click="$nav('/people/find-acquaintance')">
<div class="notice">
<div>点击查看</div>
<div>更多好友</div>
</div>
</div>
</div>
</div>
<div class="total" ref="total">
作品 {{ props.currentItem.author.aweme_count }}
<img class="arrow" src="@/assets/img/icon/arrow-up-white.png" alt="">
</div>
<div class="videos">
<Posters v-if="props.currentItem.aweme_list.length" :list="props.currentItem.aweme_list"></Posters>
</div>
</template>
<div class="total" ref="total">
作品 {{ props.currentItem.author.aweme_count }}
<img class="arrow" src="@/assets/img/icon/arrow-up-white.png" alt="">
</div>
<div class="videos">
<Posters v-if="props.currentItem.aweme_list.length"
:list="props.currentItem.aweme_list"
:author="props.currentItem.author"
></Posters>
<Loading :isFullScreen="false" v-else/>
</div>
</div>
</div>
</template>
<script setup>
import {computed, onMounted, reactive, ref, watch} from "vue";
import Utils, {_checkImgUrl, $no, _getUserDouyinId} from "@/utils";
import Utils, {$no, _checkImgUrl, _getUserDouyinId} from "@/utils";
import {useNav} from "@/utils/hooks/useNav";
import {useStore} from "vuex";
import resource from "@/assets/data/resource";
import Posters from '@/components/Posters'
import api from "@/api";
import {merge} from 'lodash'
import {merge} from 'lodash-es'
import {DefaultUser} from "@/utils/const_var";
import Loading from "@/components/Loading.vue";
const $nav = useNav()
const store = useStore()
@ -193,7 +195,6 @@ const props = defineProps({ @@ -193,7 +195,6 @@ const props = defineProps({
type: Object,
default: {
author: DefaultUser,
isRequest: false,
aweme_list: [],
}
},
@ -278,26 +279,30 @@ const state = reactive({ @@ -278,26 +279,30 @@ const state = reactive({
//
canMoveMaxHeight: document.body.clientHeight / 4,
//Cover
isAutoScaleCover: false
isAutoScaleCover: false,
uid: null
})
watch(() => props.active,
async (newVal) => {
if (newVal && !props.currentItem.isRequest) {
let res = await api.user.profile()
console.log('res', res)
if (res.code === 200) {
res.data.aweme_list = res.data.aweme_list.map(v => {
return {
cover: v.video.cover.url_list[0],
digg_count: v.statistics.digg_count,
create_time: v.create_time
}
if (newVal && !props.currentItem.aweme_list.length) {
// console.log('props.currentItem',props.currentItem)
let id = _getUserDouyinId(props.currentItem)
fetch(`/data/user-${id}.json`).then(r => {
r.json().then(l => {
setTimeout(() => {
emit('update:currentItem', merge(props.currentItem, {aweme_list: l}))
}, 800)
})
//idid
res.data.user.unique_id = props.currentItem.author.unique_id
emit('update:currentItem', merge(props.currentItem, {...res.data, isRequest: true}))
}
})
}
})
watch(() => props.currentItem.author.uid,
async (newVal) => {
if (props.currentItem.author.uid !== state.uid) {
state.uid = props.currentItem.author.uid
emit('update:currentItem', merge(props.currentItem, {aweme_list: []}))
}
})
@ -341,7 +346,7 @@ function touchStart(e) { @@ -341,7 +346,7 @@ function touchStart(e) {
if (state.isTop) {
cover.value.style.transition = 'none'
}
console.log('touchStart', page.value.scrollTop)
// console.log('touchStart', page.value.scrollTop)
}
function touchMove(e) {
@ -366,7 +371,7 @@ function touchEnd(e) { @@ -366,7 +371,7 @@ function touchEnd(e) {
}
let endTime = Date.now()
state.isAutoScaleCover = (endTime - state.start.time) < 100
console.log('touchEnd')
// console.log('touchEnd')
}
</script>

8
src/components/Video.vue

@ -70,11 +70,6 @@ @@ -70,11 +70,6 @@
</div>
<div class="music" @click.stop="$nav('/music')">
<img src="../assets/img/icon/music.svg" alt="" class="music-image">
<BaseMarquee :key="name"
:name="name"
:isPlay="isPlay"
:text="lVideo.music.title"
@click.stop="$emit('goMusic')"/>
</div>
</div>
<div v-else class="comment-status">
@ -117,16 +112,13 @@ @@ -117,16 +112,13 @@
<script>
import globalMethods from '../utils'
import BaseMarquee from "./BaseMarquee";
import Dom from "../utils/dom";
import BaseMusic from "./BaseMusic";
import {mapState} from "vuex";
import Loading from "./Loading";
export default {
name: "Video",
components: {
BaseMarquee,
BaseMusic,
Loading
},

2
src/components/slide/BVideo.vue

@ -366,9 +366,9 @@ export default { @@ -366,9 +366,9 @@ export default {
font-size: 14rem;
width: 100%;
height: 100%;
text-align: center;
video {
width: 100%;
height: 100%;
transition: height, margin-top .3s;
//background: black;

9
src/components/slide/ItemDesc.vue

@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
<script setup>
import {reactive} from "vue";
import BaseMarquee from "../BaseMarquee";
import bus from "../../utils/bus";
const props = defineProps({
@ -50,7 +49,7 @@ const state = reactive({ @@ -50,7 +49,7 @@ const state = reactive({
</div>
<div class="music" @click.stop="bus.emit('nav','/home/music')">
<img src="../../assets/img/icon/music.svg" alt="" class="music-image">
<BaseMarquee :text="props.item.music.title"/>
<span>{{ props.item.music.title }}</span>
</div>
</div>
<div v-else class="comment-status">
@ -86,8 +85,7 @@ const state = reactive({ @@ -86,8 +85,7 @@ const state = reactive({
.content {
color: #fff;
width: 75vw;
//display: flex;
//flex-direction: column;
text-align: left;
.location-wrapper {
display: flex;
@ -116,17 +114,14 @@ const state = reactive({ @@ -116,17 +114,14 @@ const state = reactive({
}
}
.music {
position: relative;
width: 60%;
display: flex;
align-items: center;
.music-image {
width: 20px;
height: 20px;
margin-top: 3px;
}
}
}

2
src/components/slide/SlideAlbum.vue

@ -96,7 +96,7 @@ import {SlideAlbumOperationStatus, SlideItemPlayStatus, SlideType} from "../../u @@ -96,7 +96,7 @@ import {SlideAlbumOperationStatus, SlideItemPlayStatus, SlideType} from "../../u
import ItemToolbar from "./ItemToolbar";
import ItemDesc from "./ItemDesc";
import GM from "../../utils";
import {cloneDeep} from "lodash";
import {cloneDeep} from "lodash-es";
import bus, {EVENT_KEY} from "../../utils/bus";
let out = new Float32Array([

11
src/components/slide/SlideVerticalInfinite.vue

@ -69,9 +69,9 @@ const judgeValue = computed(() => store.state.judgeValue) @@ -69,9 +69,9 @@ const judgeValue = computed(() => store.state.judgeValue)
watch(
() => props.list,
(newVal, oldVal) => {
// console.log('watch', newVal.length, oldVal.length, props.list)
//
if (newVal.length <= oldVal.length) {
console.log('watch-list', newVal.length, oldVal.length,)
//
if (newVal.length < oldVal.length) {
insertContent()
} else {
if (oldVal.length === 0) {
@ -99,8 +99,9 @@ watch( @@ -99,8 +99,9 @@ watch(
watch(
() => props.index,
(newVal, oldVal) => {
state.localIndex = newVal
console.log('watch-index', newVal, oldVal)
if (!props.list.length) return
// console.log('watch-index', newVal, oldVal)
bus.emit(EVENT_KEY.CURRENT_ITEM, props.list[newVal])
bus.emit(EVENT_KEY.SINGLE_CLICK_BROADCAST, {
uniqueId: props.uniqueId,
@ -155,6 +156,7 @@ function insertContent(list = props.list) { @@ -155,6 +156,7 @@ function insertContent(list = props.list) {
start = end - props.virtualTotal
}
if (start < 0) start = 0
console.log('start', start, end)
list.slice(start, end).map(
(item, index) => {
//0jqtrigger play
@ -175,7 +177,6 @@ function insertContent(list = props.list) { @@ -175,7 +177,6 @@ function insertContent(list = props.list) {
}
state.wrapper.childrenLength = wrapperEl.value.children.length
bus.emit(EVENT_KEY.CURRENT_ITEM, list[state.localIndex])
}
function dislike(item) {

699
src/components/slide/SlideVideo.vue

@ -1,699 +0,0 @@ @@ -1,699 +0,0 @@
<template>
<div class="video-wrapper" ref="videoWrapper" :class="name">
<Loading v-if="loading" style="position: absolute"/>
<video :src="video.video + '?v=123'"
:poster="video.video + videoPoster"
ref="video"
muted
preload
:autoplay="isPlay" loop>
<p> 您的浏览器不支持 video 标签</p>
</video>
<img src="../../assets/img/icon/play-white.png" class="pause" v-if="!isPlaying">
<div class="float" @click="togglePlayVideo">
<!-- @click.stop="togglePlayVideo" -->
<div :style="{opacity:isMove ? 0:1}" class="normal">
<div class="toolbar mb1r">
<div class="avatar-ctn mb4r">
<img class="avatar" :src="lVideo.author.avatar" alt=""
@click.stop="$emit('goUserInfo')">
<transition name="fade">
<div v-if="!isAttention" @click.stop="attention" class="options" ref="attention-option">
<img class="no" src="../../assets/img/icon/add-light.png" alt="">
<img class="yes" src="../../assets/img/icon/ok-red.png" alt="">
</div>
</transition>
</div>
<div class="love mb2r" @click.stop="loved($event)">
<div>
<img src="../../assets/img/icon/love.svg" class="love-image" v-if="!lVideo.isLoved">
<img src="../../assets/img/icon/loved.svg" class="love-image" v-if="lVideo.isLoved">
</div>
<span>{{ formatNumber(lVideo.digg_count) }}</span>
</div>
<div class="message mb2r" @click.stop="$emit('showComments')">
<!-- <div class="message mb15p" @click.stop="showComment">-->
<img src="../../assets/img/icon/message.svg" alt="" class="message-image">
<span>{{ formatNumber(lVideo.comment_count) }}</span>
</div>
<div v-if="!isMy" class="share mb4r" @click.stop="$emit('showShare')">
<img src="../../assets/img/icon/share-white-full.png" alt="" class="share-image">
<span>{{ formatNumber(lVideo.share_count) }}</span>
</div>
<div v-else class="share mb4r" @click.stop="$emit('showShare')">
<img src="../../assets/img/icon/share-white-full.png" alt="" class="share-image">
</div>
<BaseMusic
:cover="lVideo.music.cover"
:key="name"
:name="name"
:isPlay="isPlay"
@click.stop="$emit('goMusic')"
/>
</div>
<div class="content ml1r mb1r" v-if="!isMy">
<div class="location-wrapper" v-if=" lVideo.city || lVideo.address">
<div class="location">
<img src="../../assets/img/icon/location.webp" alt="">
<span>{{ lVideo.city }}</span>
<template v-if="lVideo.address && lVideo.address">
<div class="gang"></div>
</template>
<span>{{ lVideo.address }}</span>
</div>
</div>
<div class="name mb1r fb" @click.stop="$emit('goUserInfo')">@{{ lVideo.author.nickname }}</div>
<div class="description mb1r">
{{ lVideo.desc }}
</div>
<div class="music" @click.stop="$nav('/music')">
<img src="../../assets/img/icon/music.svg" alt="" class="music-image">
<BaseMarquee :key="name"
:name="name"
:isPlay="isPlay"
:text="lVideo.music.title"
@click.stop="$emit('goMusic')"/>
</div>
</div>
<div v-else class="comment-status">
<div class="comment">
<div class="type-comment">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar">
<div class="right">
<p>
<span class="name">zzzzz</span>
<span class="time">2020-01-20</span>
</p>
<p class="text">北京</p>
</div>
</div>
<transition-group name="comment-status" tag="div" class="loveds">
<div class="type-loved" :key="i" v-for="i in test">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="avatar">
<img src="../../assets/img/icon/love.svg" alt="" class="loved">
</div>
</transition-group>
</div>
</div>
</div>
<div class="progress"
v-if="duration > 60"
:class="progressClass"
@touchmove="move"
@touchend="end"
>
<div class="time" v-if="isMove">
<span class="currentTime">{{ $duration(currentTime) }}</span>
<span class="duration"> / {{ $duration(duration) }}</span>
</div>
<div class="line" :style="durationStyle" ref="line"></div>
<div class="point" :style="durationStyle" ref="point"></div>
</div>
</div>
</div>
</template>
<script>
import globalMethods from '../../utils'
import BaseMarquee from "../BaseMarquee";
import Dom from "../../utils/dom";
import BaseMusic from "../BaseMusic";
import Loading from "../Loading";
export default {
name: "Video",
components: {
BaseMarquee,
BaseMusic,
Loading,
},
props: {
video: {
type: Object,
default: () => {
return {}
}
},
index: {
type: Number,
default: () => {
return -1
}
},
//
isPlay: {
type: Boolean,
default: () => {
return true
}
},
isMy: {
type: Boolean,
default: () => {
return false
}
}
},
computed: {
durationStyle() {
return {left: this.pageX + 'px'}
},
progressClass() {
if (this.isMove) {
return 'stop'
} else {
return this.isPlaying ? '' : 'stop'
}
},
},
data() {
return {
loading: false,
name: `v-${this.index}-video`,
globalMethods: globalMethods,
duration: 0,
step: 0,
currentTime: -1,
pageX: 0,
height: 0,
width: 0,
isPlaying: this.isPlay,
isAttention: false,
line: null,
point: null,
isMove: false,
test: [1, 2],
lVideo: this.video,
videoPoster: `?vframe/jpg/offset/0/w/${document.body.clientWidth}`,
timer: null,
lastClickTime: 0
}
},
mounted() {
this.height = document.body.clientHeight
this.width = document.body.clientWidth
this.line = this.$refs.line
this.point = this.$refs.point
let video = this.$refs.video
video.currentTime = 0
let fun = e => {
this.currentTime = Math.ceil(e.target.currentTime)
this.pageX = this.currentTime * this.step
}
video.addEventListener('loadedmetadata', e => {
this.duration = video.duration
if (this.duration > 60) {
// if (this.duration > 6) {
this.step = this.width / Math.floor(this.duration)
video.addEventListener('timeupdate', fun)
}
})
let eventTester = (e, t) => {
video.addEventListener(e, () => {
if (e === 'playing') this.loading = false
if (e === 'progress') this.loading = true
if (e === 'waiting') this.loading = true
//
}, false);
}
// eventTester("loadstart", ''); //
// eventTester("abort", ''); //
// eventTester("loadstart", ''); //
eventTester("progress", '客户端正在请求数据'); //
// // eventTester("suspend", ''); //
// eventTester("abort", ''); //
// eventTester("error", ''); //
// eventTester("stalled", ''); //
// eventTester("play", 'play()autoplay'); //play()autoplay
// eventTester("pause", 'pause()'); //pause()
// eventTester("loadedmetadata", ''); //
// eventTester("loadeddata"); //
eventTester("waiting", '等待数据,并非错误'); //
eventTester("playing", '开始回放'); //
// eventTester("canplay", '/'); //
// eventTester("canplaythrough", ''); //
// eventTester("seeking", ''); //
// eventTester("seeked", ''); //
// // eventTester("timeupdate",''); //
// eventTester("ended", ''); //
// eventTester("ratechange", ''); //
// eventTester("durationchange", ''); //
// eventTester("volumechange", ''); //
this.$refs.videoWrapper.addEventListener('play', this.play)
this.$refs.videoWrapper.addEventListener('stop', this.stop)
},
methods: {
//
togglePlayVideo(e) {
let checkTime = 200
let nowTime = new Date().getTime();
if (nowTime - this.lastClickTime < checkTime) {
clearTimeout(this.timer);
} else {
this.timer = setTimeout(() => {
if (this.isPlaying) {
this.pause()
} else {
this.play()
}
}, checkTime);
}
this.lastClickTime = nowTime
},
play() {
new Dom(`.${this.name}-marquee`).trigger('start')
new Dom(`.${this.name}-music`).trigger('start')
// console.log('trigger-play')
this.isPlaying = true
if (this.currentTime !== -1) {
this.$refs.video.currentTime = this.currentTime
}
this.$refs.video.volume = 1
this.$refs.video.play()
},
stop() {
new Dom(`.${this.name}-marquee`).trigger('stop')
new Dom(`.${this.name}-music`).trigger('stop')
// console.log('trigger-stop')
this.$refs.video.pause()
this.isPlaying = false
this.$refs.video.currentTime = 0
},
pause() {
new Dom(`.${this.name}-marquee`).trigger('pause')
new Dom(`.${this.name}-music`).trigger('pause')
// console.log('trigger-pause')
this.$refs.video.pause()
this.isPlaying = false
},
formatNumber(v) {
return globalMethods.formatNumber(v)
},
$duration(v) {
return globalMethods.$duration(v)
},
attention() {
let option = this.$refs['attention-option']
option.classList.add('attention')
setTimeout(() => {
this.isAttention = true
}, 1000)
},
loved(e, index) {
this.lVideo.isLoved = !this.lVideo.isLoved
this.$emit('update:video', this.lVideo)
},
start(e) {
this.pageX = e.touches[0].pageX
},
move(e) {
if (this.isPlaying) return
this.isMove = true
this.pause()
this.pageX = e.touches[0].pageX
// console.log(this.step)
this.currentTime = Math.ceil(Math.ceil(e.touches[0].pageX) / this.step)
globalMethods.$stopPropagation(e)
},
end(e) {
if (this.isPlaying) return
console.log('end', e)
setTimeout(() => {
this.isMove = false
}, 1000)
this.currentTime = Math.ceil(Math.ceil(e.changedTouches[0].pageX) / this.step)
this.play()
globalMethods.$stopPropagation(e)
}
}
}
</script>
<style scoped lang="less">
@import "../../assets/less/color";
.fade-enter-active,
.fade-leave-active {
transition: transform 0.5s linear;
}
.fade-enter-from,
.fade-leave-to {
transform: scale(0);
}
.video-wrapper {
position: relative;
background: black;
font-size: 14rem;
width: 100%;
height: 100%;
video {
width: 100%;
height: 100%;
/*position: absolute;*/
}
.pause {
width: 100rem;
height: 100rem;
opacity: 0.5;
position: absolute;
margin: auto;
left: 0;
top: 0;
top: 0;
bottom: 0;
right: 0;
animation: pause-animation 1.1s linear;
@scale: scale(1.2);
@keyframes pause-animation {
0% {
opacity: 0;
transform: scale(2);
}
10% {
opacity: 0.5;
transform: @scale;
}
100% {
transform: @scale;
opacity: 0.5;
}
}
}
.float {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
.normal {
position: absolute;
bottom: 0;
width: 100%;
transition: all .3s;
.toolbar {
//width: 40px;
position: absolute;
bottom: 0;
right: 5px;
color: #fff;
.avatar-ctn {
position: relative;
.avatar {
width: 55px;
height: 55px;
border-radius: 50%;
}
.options {
position: absolute;
border-radius: 50%;
margin: auto;
left: 0;
right: 0;
bottom: -5px;
background: red;
//background: black;
width: 18px;
height: 18px;
display: flex;
justify-content: center;
align-items: center;
transition: all 1s;
img {
position: absolute;
width: 12px;
height: 12px;
transition: all 1s;
}
.yes {
opacity: 0;
transform: rotate(-180deg);
}
&.attention {
background: white;
.no {
opacity: 0;
transform: rotate(180deg);
}
.yes {
opacity: 1;
transform: rotate(0deg);
}
}
}
}
.love, .message, .share {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
@width: 35rem;
img {
width: @width;
height: @width;
}
span {
font-size: 12rem;
}
}
.loved {
background: red;
}
}
.content {
color: #fff;
position: absolute;
bottom: 0;
width: 75%;
//display: flex;
//flex-direction: column;
.location-wrapper {
display: flex;
.location {
margin-bottom: 10rem;
display: flex;
align-items: center;
font-size: 12rem;
padding: 4rem;
border-radius: 3rem;
background: @second-btn-color-tran;
.gang {
height: 8rem;
width: 1.5px;
margin: 0 5rem;
background: gray;
}
img {
margin-right: 7rem;
width: 18rem;
}
}
}
.music {
position: relative;
width: 60%;
display: flex;
align-items: center;
.music-image {
width: 20px;
height: 20px;
margin-top: 3px;
}
}
}
.comment-status {
display: flex;
align-items: center;
.comment {
.type-comment {
display: flex;
background: rgb(130, 21, 44);
border-radius: 50px;
padding: 3px;
margin-bottom: 20px;
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
}
.right {
margin: 0 10px;
color: @second-text-color;
.name {
margin-right: 10px;
}
.text {
color: white;
}
}
}
.loveds {
}
.type-loved {
width: 40px;
height: 40px;
position: relative;
margin-bottom: 20px;
animation: test 1s;
animation-delay: .5s;
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
}
.loved {
position: absolute;
bottom: 0;
left: 20px;
width: 10px;
height: 10px;
background: red;
padding: 3px;
border-radius: 50%;
border: 2px solid white;
}
}
@keyframes test {
from {
display: block;
transform: translate3d(0, 0, 0);
}
to {
display: none;
transform: translate3d(0, -60px, 0);
}
}
}
}
}
.progress {
bottom: -1px;
position: absolute;
height: 7px;
width: 100vw;
background: black;
.time {
position: absolute;
z-index: 9;
font-size: 24px;
bottom: 50px;
left: 0;
right: 0;
color: white;
text-align: center;
.duration {
color: darkgray;
}
}
&:before {
z-index: 9;
content: ' ';
height: 1.5px;
width: 100vw;
background: gray;
position: absolute;
top: 0;
}
.line {
z-index: 999;
content: '';
position: absolute;
top: 0;
height: 1px;
width: 200vw;
transform: translate3d(-200vw, 0, 0);
background: gray;
}
.point {
z-index: 10;
position: absolute;
left: 10vw;
top: -1px;
height: 4px;
width: 4px;
border-radius: 50%;
background: gray;
}
}
& .stop {
&:before {
height: 3.5px;
}
.line {
height: 3px;
background: white;
}
.point {
top: -2px;
height: 8px;
width: 8px;
background: white;
}
}
}
}
</style>

322
src/components/slide/UNUSE_SlideColumnVirtualList.txt

@ -1,322 +0,0 @@ @@ -1,322 +0,0 @@
<template>
<div id="base-slide-wrapper">
<div id="base-slide-list" ref="slideList"
:style="{'flex-direction':'column'}"
@touchstart="touchStart($event)"
@touchmove="touchMove($event)"
@touchend="touchEnd($event)">
<slot></slot>
</div>
</div>
</template>
<script>
import * as Vue from 'vue'
import Dom from "../../utils/dom";
export default {
name: "SlideColumnVirtualList",
props: {
renderSlide: {
type: Function,
default: () => {
return null
}
},
list: {
type: Array,
default: () => {
return []
}
},
defaultVirtualItemTotal: {
type: Number,
default: () => 5
},
activeIndex: {
type: Number,
default: () => 0
},
},
data() {
return {
wrapperHeight: 0,
startLocationX: 0,
startLocationY: 0,
moveXDistance: 0,
moveYDistance: 0,
judgeValue: 10,
startTime: 0,
currentSlideItemIndex: 0,
isDrawDown: true,
isCanDownWiping: false,
isNeedCheck: true,
slideList: null,
slideItems: null,
slideItemsHeights: [],
appInsMap: new Map()
}
},
watch: {
watchList: {
handler(newVal, oldVal) {
console.log('watch', newVal.length, oldVal.length)
let that = this
if (oldVal.length === 0) {
let startIndex = 0
if (this.currentSlideItemIndex >= this.defaultVirtualItemTotal) {
startIndex = this.currentSlideItemIndex - (this.defaultVirtualItemTotal - 1) / 2
}
this.list.slice(startIndex, startIndex + 5).map(
(item, index) => {
let el = null
//自动播放,当前条(可能是0,可能是其他),试了下用jq来找元素,然后trigger play事件,要慢点样
if (startIndex + index === this.currentSlideItemIndex) {
el = this.getInsEl(item, startIndex + index, true)
} else {
el = this.getInsEl(item, startIndex + index)
}
this.slideList.appendChild(el)
})
if (that.currentSlideItemIndex > 2) {
this.$setCss(this.slideList, 'transform', `translate3d(0px,
${-this.currentSlideItemIndex * this.wrapperHeight}px, 0px)`)
$(".video-slide-item").each(function () {
$(this).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
})
}
setTimeout(this.checkChildren, 100)
} else {
let endLength = oldVal.length + 3
newVal.slice(oldVal.length, endLength).map((item, index) => {
let el = this.getInsEl(item, oldVal.length + index)
//这里必须要设置个top值,不然会把前面的条目给覆盖掉
$(el).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
this.slideList.appendChild(el)
})
this.checkChildren()
}
},
deep: true
}
},
computed: {
//包装下,不然后watch里面监听到的新值和旧值是一样的,麻了
watchList() {
return [...this.list]
},
},
mounted: async function () {
this.checkChildren()
this.currentSlideItemIndex = this.activeIndex
this.list.slice(this.currentSlideItemIndex, (this.defaultVirtualItemTotal + 1) / 2).map((item, index) => {
this.slideList.appendChild(this.getInsEl(item, index))
})
this.checkChildren()
},
methods: {
dislike(item) {
let currentItem = new Dom(`.video-slide-item-${this.currentSlideItemIndex}`)
let replaceItem = this.getInsEl(item, this.currentSlideItemIndex, true)
new Dom(replaceItem).css('top', currentItem.css('top'))
$(currentItem.els[0]).replaceWith(replaceItem)
},
getInsEl(item, index, play = false) {
// console.log('index',index,play)
let slideVNode = this.renderSlide(item, index, play)
const app = Vue.createApp({
render() {
return slideVNode
}
})
const parent = document.createElement('div')
const ins = app.mount(parent)
this.appInsMap.set(index, app)
// this.appInsMap.set(index, ins)
return ins.$el
},
checkChildren() {
this.slideList = this.$refs.slideList
this.slideItems = this.slideList.children
this.wrapperHeight = this.$getCss(this.slideList, 'height')
},
touchStart(e) {
this.$setCss(this.slideList, 'transition-duration', `0ms`)
this.showIndicator && this.$setCss(this.indicatorRef, 'transition-duration', `0ms`)
this.toolbarStyleTransitionDuration = 0
this.startLocationX = e.touches[0].pageX
this.startLocationY = e.touches[0].pageY
this.startTime = Date.now()
let that = this
let items = $(".video-slide-item")
if (items.length > this.defaultVirtualItemTotal) {
let middle = (this.defaultVirtualItemTotal - 1) / 2
let removeNum = 0
items.each(function (index) {
if ($(this).data('index') === that.currentSlideItemIndex) {
console.log('start-index', index)
if (index !== middle) {
removeNum = index - middle
}
}
})
items.each(function (index) {
$(this).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
})
for (let i = 0; i < removeNum; i++) {
$(items[i]).remove()
}
}
},
touchMove(e) {
this.moveXDistance = e.touches[0].pageX - this.startLocationX
this.moveYDistance = e.touches[0].pageY - this.startLocationY
this.isDrawDown = this.moveYDistance < 0
this.checkDirection()
//me页面,需要获取向下滑动的时候
if (!this.isDrawDown) {
this.$attrs['onFirst'] && this.$emit('first', this.moveYDistance)
}
//todo 太卡了,后面考虑用原生js来写
// this.$attrs['onMove'] && this.$emit('move', {
// x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
// y: {distance: this.lastMoveYDistance, isDrawDown: this.isDrawDown},
// })
if (this.isCanDownWiping) {
if (this.currentSlideItemIndex === 0 && !this.isDrawDown) return; //在第一个item,并且想往下划。
if (this.currentSlideItemIndex === this.list.length - 1 && this.isDrawDown) return
// console.log('this.isCanDownWiping')
this.$stopPropagation(e)
this.$setCss(this.slideList, 'transform', `translate3d(0px, ${-this.getHeight(this.currentSlideItemIndex) +
this.moveYDistance +
(this.isDrawDown ? this.judgeValue : -this.judgeValue)
}px, 0px)`)
}
},
touchEnd(e) {
if (this.isCanDownWiping) {
if (this.currentSlideItemIndex === 0 && !this.isDrawDown) return
if (this.currentSlideItemIndex === this.list.length - 1 && this.isDrawDown) return this.$attrs['onEnd'] && this.$emit('end')
e && this.$stopPropagation(e)
this.$setCss(this.slideList, 'transition-duration', `300ms`)
let endTime = Date.now()
let gapTime = endTime - this.startTime
if (Math.abs(this.moveYDistance) < 20) gapTime = 1000
if (Math.abs(this.moveYDistance) > (this.wrapperHeight / 3)) gapTime = 100
if (gapTime < 150) {
if (this.isDrawDown) {
this.currentSlideItemIndex += 1
} else {
this.currentSlideItemIndex -= 1
}
// console.log('gapTime', this.currentSlideItemIndex)
// console.log(this.slideItems.length)
let that = this
if (this.isDrawDown) {
let addItemIndex = this.currentSlideItemIndex + 2
if (this.slideItems.length < this.defaultVirtualItemTotal) {
let res = $(`#base-slide-list .video-slide-item[data-index=${addItemIndex}]`)
if (res.length === 0) {
this.slideList.appendChild(this.getInsEl(this.list[addItemIndex], addItemIndex))
}
}
if (this.slideItems.length === this.defaultVirtualItemTotal
&& this.currentSlideItemIndex >= (this.defaultVirtualItemTotal + 1) / 2
&& this.currentSlideItemIndex <= this.list.length - 3
) {
let res = $(`#base-slide-list .video-slide-item[data-index=${addItemIndex}]`)
// console.log(videos)
if (res.length === 0) {
this.slideList.appendChild(this.getInsEl(this.list[addItemIndex], addItemIndex))
this.appInsMap.get($("#base-slide-list .video-slide-item:first").data('index')).unmount()
// $("#base-slide-list .base-slide-item:first").remove()
$(".video-slide-item").each(function () {
$(this).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
})
}
}
if (this.slideItems.length > this.defaultVirtualItemTotal) {
this.appInsMap.get($("#base-slide-list .video-slide-item:first").data('index')).unmount()
$(".video-slide-item").each(function () {
$(this).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
})
}
} else {
if (this.currentSlideItemIndex > 1 && this.currentSlideItemIndex <= this.list.length - 4) {
let addItemIndex = this.currentSlideItemIndex - 2
this.slideList.prepend(this.getInsEl(this.list[addItemIndex], addItemIndex))
this.appInsMap.get($("#base-slide-list .video-slide-item:last").data('index')).unmount()
// $("#base-slide-list .base-slide-item:last").remove()
$(".video-slide-item").each(function () {
$(this).css('top', (that.currentSlideItemIndex - 2) * that.wrapperHeight)
})
}
}
this.checkChildren()
}
this.$setCss(this.slideList, 'transform', `translate3d(0px, ${-this.getHeight(this.currentSlideItemIndex)}px, 0px)`)
}
this.resetConfig()
this.$attrs['onUpdate:activeIndex'] && this.$emit('update:active-index', this.currentSlideItemIndex)
},
resetConfig() {
this.isCanDownWiping = false
this.isNeedCheck = true
this.moveXDistance = 0
this.moveYDistance = 0
},
getHeight(index) {
return this.wrapperHeight * index
},
checkDirection() {
if (!this.isNeedCheck) return
if (Math.abs(this.moveXDistance) > this.judgeValue || Math.abs(this.moveYDistance) > this.judgeValue) {
let angle = (Math.abs(this.moveXDistance) * 10) / (Math.abs(this.moveYDistance) * 10)
if (angle > 1) {
this.isCanDownWiping = false
this.isCanRightWiping = true
// console.log('横划')
} else {
this.isCanDownWiping = true
this.isCanRightWiping = false
// console.log('竖划')
}
// console.log(angle)
return this.isNeedCheck = false
}
return this.isNeedCheck = true
}
}
}
</script>
<style scoped lang="less">
@import "../../assets/less/index";
#base-slide-wrapper {
width: 100%;
height: 100%;
overflow: hidden;
#base-slide-list {
display: flex;
height: 100%;
width: 100%;
position: relative;
}
}
</style>

184
src/components/slide/VInfinite-Component.vue

@ -1,184 +0,0 @@ @@ -1,184 +0,0 @@
<script setup lang="jsx">
import {computed, onMounted, reactive, ref, watch} from "vue";
import GM from '../../utils'
import {
getSlideDistance,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from "./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, index = -1) {
let node = props.render(item, state.localIndex, index === 0, 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)`)
}
}
)
watch(
() => props.list,
(newVal) => {
console.log('list', newVal)
let half = (props.virtualTotal + 1) / 2
if (state.localIndex >= half) {
state.cs = newVal.slice(state.localIndex - 2, state.localIndex + 3).map((v, i) => r(v))
state.styleTop = (state.localIndex - 2) * state.wrapper.height
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.VERTICAL)
state.cs = props.list.slice(0, props.virtualTotal).map((v, i) => r(v, i))
})
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 {
//1if
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>
测试用<component :is的方法是否可行结论可行但是不实用当list数据更新时<component的表现形式为不销毁组件只更新props
感觉会导致已经加载到的video重新加载但未经测试

4
src/main.js

@ -8,8 +8,9 @@ import router from "./router"; @@ -8,8 +8,9 @@ import router from "./router";
import store from "./store";
import mixin from "./utils/mixin";
import VueLazyload from '@jambonn/vue-lazyload'
import VConsole from 'vconsole';
import {VueMasonryPlugin} from "vue-masonry";
import {createPinia} from "pinia";
const pinia = createPinia()
// const vConsole = new VConsole();
const emitter = mitt()
@ -29,4 +30,5 @@ app.use(VueLazyload, { @@ -29,4 +30,5 @@ app.use(VueLazyload, {
app.use(VueMasonryPlugin)
app.use(router)
app.use(store)
app.use(pinia)
app.mount('#app')

2
src/mock/index.js

@ -4,7 +4,7 @@ import resource from "../assets/data/resource.js"; @@ -4,7 +4,7 @@ import resource from "../assets/data/resource.js";
import posts6 from "@/assets/data/posts6.json";
import users from '@/assets/data/users.json'
import post from '@/assets/data/post.json'
import {sample, shuffle, uniqueId} from "lodash";
import {sample, shuffle, uniqueId} from "lodash-es";
function getParams(options) {
let params = globalMethods.$parseURL(options.url).params

2
src/pages/home/SearchPage.vue

@ -198,7 +198,7 @@ @@ -198,7 +198,7 @@
</template>
<script>
import Search from "../../components/Search";
import _ from 'lodash'
import _ from 'lodash-es'
import Dom from "../../utils/dom";
import {nextTick} from "vue";

18
src/pages/home/index.vue

@ -112,7 +112,7 @@ @@ -112,7 +112,7 @@
</SlideItem>
<Slide2 :active="state.navIndex === 2 && state.baseIndex === 1"/>
<SlideItem>
<LongVideo/>
<LongVideo :active="state.navIndex === 3 && state.baseIndex === 1"/>
</SlideItem>
<Slide4 :active="state.navIndex === 4 && state.baseIndex === 1"/>
</SlideHorizontal>
@ -126,7 +126,7 @@ @@ -126,7 +126,7 @@
<UserPanel
ref="uploader"
v-model:currentItem="state.currentItem"
:active="state.baseIndex === 1"
:active="state.baseIndex === 2"
@toggleCanMove="e => state.canMove = e"
@back="state.baseIndex = 1"
@showFollowSetting="state.showFollowSetting = true"
@ -198,7 +198,7 @@ import SlideItem from '@/components/slide/SlideItem.vue' @@ -198,7 +198,7 @@ import SlideItem from '@/components/slide/SlideItem.vue'
import Comment from "../../components/Comment.vue";
import Share from "../../components/Share.vue";
import IndicatorHome from "./components/IndicatorHome.vue";
import {computed, onMounted, onUnmounted, reactive} from "vue";
import {computed, onActivated, onDeactivated, onMounted, onUnmounted, reactive} from "vue";
import bus, {EVENT_KEY} from "../../utils/bus";
import {useNav} from "@/utils/hooks/useNav";
import {useStore} from "vuex";
@ -260,21 +260,13 @@ function delayShowDialog(cb) { @@ -260,21 +260,13 @@ function delayShowDialog(cb) {
}
function setCurrentItem(item) {
if (state.baseIndex !== 1) return
if (state.currentItem.author.uid !== item.author.uid) {
let id = _getUserDouyinId(item)
console.log('item', id)
state.currentItem = {
...item,
isRequest: true,
isRequest: false,
aweme_list: [],
}
fetch(`/data/user-${id}.json`).then(r => {
r.json().then(l => {
// console.log('k', l)
state.currentItem.aweme_list = l
})
})
}
// console.log('item', item)
}

18
src/pages/home/slide/LongVideo.vue

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<script setup>
import {computed, onMounted, onUnmounted, reactive, ref} from "vue";
import {uniqueId} from "lodash";
import {computed, onMounted, onUnmounted, reactive, ref, watch} from "vue";
import {uniqueId} from "lodash-es";
import api from "@/api";
import {useStore} from "vuex";
import {_checkImgUrl, _duration, _formatNumber} from "@/utils";
@ -9,6 +9,10 @@ import {_checkImgUrl, _duration, _formatNumber} from "@/utils"; @@ -9,6 +9,10 @@ import {_checkImgUrl, _duration, _formatNumber} from "@/utils";
const store = useStore()
const loading = computed(() => store.state.loading)
const props = defineProps({
active: Boolean
})
const p = {
onShowComments() {
console.log('onShowComments')
@ -36,7 +40,7 @@ async function getData(refresh = false) { @@ -36,7 +40,7 @@ async function getData(refresh = false) {
if (loading.value) return
store.commit('setLoading', true)
let res = await api.videos.recommended({pageNo: refresh ? 0 : state.pageNo, pageSize: state.pageSize})
// console.log('getSlide4Data-', 'refresh', refresh, res)
console.log('getSlide4Data-', 'refresh', refresh, res)
store.commit('setLoading', false)
if (res.code === 200) {
state.totalSize = res.data.total
@ -49,8 +53,14 @@ async function getData(refresh = false) { @@ -49,8 +53,14 @@ async function getData(refresh = false) {
}
}
watch(() => props.active, n => {
if (!state.list.length && n) {
store.commit('setLoading', false)
getData()
}
})
onMounted(() => {
getData()
})
onUnmounted(() => {
})

14
src/pages/home/slide/SlideList.vue

@ -22,7 +22,7 @@ import bus, {EVENT_KEY} from "@/utils/bus"; @@ -22,7 +22,7 @@ import bus, {EVENT_KEY} from "@/utils/bus";
import Utils from "@/utils";
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender";
import {useStore} from "vuex";
import {uniqueId} from "lodash";
import {uniqueId} from "lodash-es";
const props = defineProps({
cbs: {
@ -39,6 +39,14 @@ const props = defineProps({ @@ -39,6 +39,14 @@ const props = defineProps({
type: Function,
default: void 0
},
index: {
type: Number,
default: 0
},
list: {
type: Array,
default: []
},
})
const store = useStore()
@ -53,8 +61,8 @@ const p = { @@ -53,8 +61,8 @@ const p = {
const render = useSlideListItemRender({...props.cbs, ...p})
const listRef = ref(null)
const state = reactive({
index: 0,
list: [],
index: props.index,
list: props.list,
uniqueId: uniqueId('uniqueId_'),
totalSize: 0,
pageSize: 10,

379
src/pages/me/VideoDetail.vue

@ -1,88 +1,45 @@ @@ -1,88 +1,45 @@
<template>
<div id="video-detail">
<SlideList key1="父" style="width: 100vw;" v-model:can-move="canMove">
<SlideItem>
<div class="search-wrapper">
<dy-back class="back" @click="$back"/>
<Search></Search>
</div>
<SlideList key1="子" direction="column" v-model:active-index="videoActiveIndex">
<SlideItem :style="itemTop" v-for="(item,index) of videos2">
<Video1
:disabled="videoActiveIndex !== addCount + index"
v-model:video="videos[index]"
@showComments="isCommenting = !isCommenting"
@showShare="isSharing = !isSharing"
@goUserInfo="baseActiveIndex = 1"
></Video1>
</SlideItem>
</SlideList>
<div class="share-to-friend" v-if="!isMy">
<span>留下你的精彩评论吧</span>
<div class="share-btn" @click="dialog.shareToFriend = true">分享给朋友</div>
</div>
<div class="permission-setting" v-if="isMy">
<div class="right">
<img src="../../assets/img/icon/play-white.png" alt="">
<span>3030浏览</span>
</div>
<div class="share-btn" @click="dialog.permissionDialog = true">权限设置</div>
</div>
</SlideItem>
<SlideItem style="font-size: 40px;overflow:auto;">
<div>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<p>详情页</p>
<div class="search-wrapper">
<dy-back class="back" @click="$back"/>
<Search></Search>
</div>
<div class="content">
<SlideVerticalInfinite
ref="listRef"
v-love="state.uniqueId"
:id="state.uniqueId"
:uniqueId="state.uniqueId"
name="main"
:active="true"
:loading="false"
v-model:index="state.index"
:render="render"
:list="state.list"
/>
</div>
<div class="footer">
<div class="share-to-friend" v-if="!data.isMy">
<span>留下你的精彩评论吧</span>
<div class="share-btn" @click="data.dialog.shareToFriend = true">分享给朋友</div>
</div>
<div class="permission-setting" v-if="data.isMy">
<div class="right">
<img src="../../assets/img/icon/play-white.png" alt="">
<span>3030浏览</span>
</div>
</SlideItem>
</SlideList>
<div class="share-btn" @click="data.dialog.permissionDialog = true">权限设置</div>
</div>
</div>
<from-bottom-dialog
v-model="dialog.shareToFriend"
page-id="video-detail"
v-model="data.dialog.shareToFriend"
height="50vh"
mode="light"
mask-mode="light"
>
<div class="share-dialog">
<div class="collection" @click="dialog.shareToFriend = false">
<div class="collection" @click="data.dialog.shareToFriend = false">
<img src="../../assets/img/icon/me/collection-black.png" alt="">
收藏
</div>
@ -104,13 +61,14 @@ @@ -104,13 +61,14 @@
</div>
</from-bottom-dialog>
<from-bottom-dialog
v-model="dialog.permissionDialog"
page-id="video-detail"
v-model="data.dialog.permissionDialog"
height="40vh"
mode="white"
mask-mode="white"
>
<div class="permission-dialog">
<div class="setting" @click="dialog.permissionDialog = false">
<div class="setting" @click="data.dialog.permissionDialog = false">
<img src="../../assets/img/icon/head-image.jpeg" alt="">
<div class="right">
<span>公开 所有人可见</span>
@ -150,233 +108,53 @@ @@ -150,233 +108,53 @@
</div>
</template>
<script>
import Comment from '../../components/Comment.vue'
import Share from '../../components/Share.vue'
import Footer from "../../components/Footer.vue"
import src1Bg from '../../assets/img/poster/src1-bg.png'
<script setup>
import Search from "../../components/Search";
import FromBottomDialog from "../../components/dialog/FromBottomDialog";
import SlideList from "@/pages/home/slide/SlideList.vue";
import api from "@/api";
import {nextTick, onMounted, reactive} from "vue";
import {useBaseStore} from "@/store/pinia";
import SlideVerticalInfinite from "@/components/slide/SlideVerticalInfinite.vue";
import {uniqueId} from "lodash-es";
import {useSlideListItemRender} from "@/utils/hooks/useSlideListItemRender";
export default {
name: "VideoDetail",
components: {
Footer, Comment, Share, Search,
FromBottomDialog
},
data() {
return {
list: [1, 2, 3, 4, 5],
videos: [
{
videoUrl: 'http://qy9rc9xff.hn-bkt.clouddn.com/0.mp4',
// videoUrl: 'http://babylife.qiniudn.com/FtRVyPQHHocjVYjeJSrcwDkApTLQ',
videoPoster: src1Bg,
isLoved: true,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
videoUrl: 'http://qy9rc9xff.hn-bkt.clouddn.com/1.mp4',
// videoUrl: 'http://babylife.qiniudn.com/FtRVyPQHHocjVYjeJSrcwDkApTLQ',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
videoUrl: 'http://qy9rc9xff.hn-bkt.clouddn.com/2.mp4',
// videoUrl: 'http://babylife.qiniudn.com/FtRVyPQHHocjVYjeJSrcwDkApTLQ',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
videoUrl: 'http://qy9rc9xff.hn-bkt.clouddn.com/3.mp4',
// videoUrl: 'http://babylife.qiniudn.com/FtRVyPQHHocjVYjeJSrcwDkApTLQ',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
videoUrl: 'http://qy9rc9xff.hn-bkt.clouddn.com/4.mp4',
// videoUrl: 'http://babylife.qiniudn.com/FtRVyPQHHocjVYjeJSrcwDkApTLQ',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
],
videos1: [
{
// videoUrl: mp40,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/0.mp4',
videoPoster: src1Bg,
isLoved: true,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp41,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/1.mp4',
videoPoster: src1Bg,
isLoved: true,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp42,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/2.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp43,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/3.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp44,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/4.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp45,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/5.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp46,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/6.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp47,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/7.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp48,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/8.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp49,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/9.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
{
// videoUrl: mp410,
videoUrl: 'http://qvutp218u.hn-bkt.clouddn.com/10.mp4',
videoPoster: src1Bg,
isLoved: false,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
},
],
videos2: [],
addCount: 0,
total: 10,
baseActiveIndex: 0,
videoActiveIndex: 0,
canMove: false,
dialog: {
shareToFriend: false,
permissionDialog: false,
test: false,
},
isMy: true
}
},
computed: {
itemTop() {
return {top: this.addCount * 812 + 'px'}
},
defineOptions({
name: 'VideoDetail'
})
const store = useBaseStore()
const data = reactive({
dialog: {
shareToFriend: false,
permissionDialog: false,
test: false,
},
created() {
// this.height = document.body.clientHeight
// this.width = document.body.clientWidth
for (let i = 0; i < 53; i++) {
this.videos2.push(
{
// videoUrl: mp40,
videoUrl: `http://douyin.ttentau.top/${i}.mp4`,
videoPoster: src1Bg,
isLoved: true,
loves: 1234,
comments: 666,
shared: 999,
duration: 99
})
}
// if (process.env.NODE_ENV !== 'development') {
// this.videos = this.$clone(this.videos1)
// }
}
}
isMy: true
})
const state = reactive({
index: 0,
list: [],
uniqueId: uniqueId('uniqueId_'),
totalSize: 0,
pageSize: 10,
pageNo: 0,
})
const render = useSlideListItemRender()
onMounted(() => {
console.log('s', store.routeData)
state.index = store.routeData.index
state.list = store.routeData.list.map(v => {
v.type = 'recommend-video'
v.author = store.routeData.author
return v
})
})
</script>
<style scoped lang="less">
@import "../../assets/less/index";
#video-detail {
position: fixed;
top: 0;
@ -387,6 +165,7 @@ export default { @@ -387,6 +165,7 @@ export default {
width: 100%;
.search-wrapper {
height: @header-height;
z-index: 9;
position: fixed;
top: 10rem;
@ -406,6 +185,14 @@ export default { @@ -406,6 +185,14 @@ export default {
}
}
.content {
height: calc(100vh - @footer-height);
}
.footer {
height: @footer-height;
}
.share-to-friend {
color: @second-text-color;
height: @footer-height;

2
src/pages/message/JoinedGroupChat.vue

@ -34,7 +34,7 @@ import Search from "../../components/Search"; @@ -34,7 +34,7 @@ import Search from "../../components/Search";
import {mapState} from "vuex";
import axios from "axios";
import Check from "../../components/Check";
import {forIn} from "lodash";
import {forIn} from "lodash-es";
export default {
name: "Share2Friend",

2
src/pages/message/Share2Friend.vue

@ -143,7 +143,7 @@ import Search from "../../components/Search"; @@ -143,7 +143,7 @@ import Search from "../../components/Search";
import {mapState} from "vuex";
import axios from "axios";
import Check from "../../components/Check";
import {forIn} from "lodash";
import {forIn} from "lodash-es";
export default {
name: "Share2Friend",

166
src/pages/slideHooks/InfiniteList.vue

@ -1,166 +0,0 @@ @@ -1,166 +0,0 @@
<template>
<VInfinite
:style="{background: 'black'}"
name="main"
v-model:index="state.itemIndex"
:render="render"
:list="state.recommendVideos"
:position="{
baseIndex:0,
navIndex:5,
}"
@loadMore="loadMore"
@refresh="() => getData(true)"
>
</VInfinite>
</template>
<script setup lang="jsx">
import VInfinite from '../../components/slide/SlideVerticalInfinite.vue'
import SlideAlbum from "../../components/slide/SlideAlbum";
import SlideUser from "../../components/slide/SlideUser";
import BVideo from "../../components/slide/BVideo";
import {computed, onMounted, onUnmounted, reactive, ref} from "vue";
import bus, {EVENT_KEY} from "../../utils/bus";
import {useNav} from "@/utils/hooks/useNav";
import Utils from "@/utils";
import api from "@/api";
import {useStore} from "vuex";
const nav = useNav()
function stop(e) {
e.stopPropagation()
}
const store = useStore()
const friends = computed(() => store.state.friends)
const bodyHeight = computed(() => store.state.bodyHeight)
const bodyWidth = computed(() => store.state.bodyWidth)
const subTypeRef = ref(null)
const state = reactive({
baseIndex: 0,
navIndex: 4,
itemIndex: 0,
test: '',
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}`
},
{
type: 'user',
src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}`
},
],
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,
fullScreen: false,
subType: -1,
//zindexslidesubType.
subTypeIsTop: false,
totalSize: 0,
pageSize: 10,
pageNo: 0,
})
async function getData(refresh = false) {
// if (process.env.NODE_ENV !== 'development') {
// state.totalSize = 11
// return state.recommendVideos = resource.videos
// }
if (state.loading) return
state.loading = true
let res = await api.videos.recommended({pageNo: refresh ? 0 : state.pageNo, pageSize: state.pageSize})
console.log('loadMore-', 'refresh', refresh, res)
state.loading = false
if (res.code === 200) {
state.totalSize = res.data.total
if (refresh) {
state.recommendVideos = []
}
state.recommendVideos = state.recommendVideos.concat(res.data.list)
} else {
state.pageNo--
}
}
function loadMore() {
if (!state.loading) {
state.pageNo++
getData()
}
}
function dislike() {
// this.$refs.virtualList.dislike(this.videos[10])
// this.videos[this.videoIndex] = this.videos[10]
// this.$notice('')
}
function end() {
// this.$notice('')
}
function closeComments() {
bus.emit(EVENT_KEY.CLOSE_COMMENTS)
}
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/>
}
if (item.type === 'send-video') {
node = <video src={item.src} style="height:100%;"/>
}
if (item.type === 'recommend-video') {
node = <BVideo
isPlay={false}
item={item}
position={{...position, itemIndex}}
onGoMusic={e => nav('/home/music')}
onShowShare={e => state.isSharing = true}
onGoUserInfo={e => state.baseIndex = 1}
/>
}
return node
}
</script>
<style scoped lang="less">
@import "@/assets/less/index";
</style>

40
src/pages/test/Test.vue

@ -1,46 +1,14 @@ @@ -1,46 +1,14 @@
<template>
<!-- <TestSlide></TestSlide>-->
<!-- <SlideUser></SlideUser>-->
<!-- <SlideImgs></SlideImgs>-->
<!-- <TestSwiperJs></TestSwiperJs>-->
<slideHooks/>
<!-- <Shop/>-->
<!-- <Community/>-->
<!-- <UserPanel/>-->
<!-- <div class="body">-->
<!-- <div class="wrapper">-->
<!-- <img :src="src" id="img">-->
<!-- </div>-->
<!-- </div>-->
<div>
test
</div>
</template>
<script>
import TestSlide from "./TestSlide";
import SlideUser from "../../components/slide/SlideUser";
import SlideImgs from "../../components/slide/SlideAlbum";
import TestImg from "./TestImg";
import slideHooks from '../home/index.vue'
import TestSwiperJs from "./TestSwiperJs";
import {mat4} from "gl-matrix";
import UserPanel from "@/components/UserPanel.vue";
import Shop from "@/pages/shop/Shop.vue";
import Community from "@/pages/home/slide/Community.vue";
export default {
name: "Test",
components: {
Community,
Shop,
UserPanel,
slideHooks,
TestSlide,
SlideUser,
SlideImgs,
TestImg,
TestSwiperJs,
},
components: {},
data() {
return {
src: '',

147
src/pages/test/TestImg.vue

@ -1,147 +0,0 @@ @@ -1,147 +0,0 @@
<template>
<div id="TestImg">
<img ref="img" src="../../assets/img/poster/0.jpg" alt=""
@touchstart="start"
@touchmove="move"
@touchend="end"
>
</div>
</template>
<script>
import globalMethods from "../../utils";
export default {
name: "TestImg",
data() {
return {
result: {
width: 393,
height: 699
},
x: 0,
y: 0,
scale: 1,
point1: {x: 0, y: 0},
point2: {x: 0, y: 0},
lastPoint1: {x: 0, y: 0},
lastPoint2: {x: 0, y: 0},
lastCenter: {x: 0, y: 0},
}
},
created() {
},
mounted() {
},
methods: {
getCenter(a, b) {
const x = (a.x + b.x) / 2;
const y = (a.y + b.y) / 2;
return {x, y}
},
getDistance(start, stop) {
return Math.hypot(stop.x - start.x, stop.y - start.y);
},
handlePointers(e, type) {
for (let i = 0; i < this.touches.length; i++) {
if (this.touches[i].pointerId === e.pointerId) {
if (type === 'update') {
this.touches[i] = e;
} else if (type === 'delete') {
this.touches.splice(i, 1);
}
}
}
},
start(e) {
// console.log('start')
if (e.touches && e.touches.length === 1) {
} else {
this.isTwo = true
this.$refs.img.style['transition-duration'] = '0ms';
let events = e.touches[0];
let events2 = e.touches[1];
this.lastPoint1 = this.point1 = {x: events.pageX, y: events.pageY};
this.lastPoint2 = this.point2 = {x: events2.pageX, y: events2.pageY};
this.lastCenter = this.getCenter(this.lastPoint1, this.lastPoint2)
// console.log('lastPoint1', this.lastPoint1)
}
},
move(e) {
if (e.touches && e.touches.length === 1) {
} else {
this.isTwo = true
e.preventDefault();
let current1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
let current2 = {x: e.touches[1].pageX, y: e.touches[1].pageY}
//
let ratio = this.getDistance(current1, current2) / this.getDistance(this.lastPoint1, this.lastPoint2);
this.scale = this.scale * ratio
console.log('ratio',ratio)
console.log('scale',this.scale)
//
let center = this.getCenter(current1, current2)
// console.log('center', center)
// transform-origin: 50% 50%
// transform-origin: 30% 40%origin.x = (ratio - 1) * result.width * 0.3
// origin.y = (ratio - 1) * result.height * 0.4
// 使transformtransform-origin
// origin(ratio - 1) * result.width * 0 = 0
const origin = {
x: (ratio - 1) * this.result.width * 0.5,
y: (ratio - 1) * this.result.height * 0.5
};
// ()
this.x -= (ratio - 1) * (center.x - this.x) - origin.x - (center.x - this.lastCenter.x);
this.y -= (ratio - 1) * (center.y - this.y) - origin.y - (center.y - this.lastCenter.y);
// console.log('this.x', this.x)
// console.log('this.y', this.y)
//
this.$refs.img.style.transform = `translate3d(${this.x}px,${this.y}px,0) scale(${this.scale})`;
this.lastCenter = {x: center.x, y: center.y};
this.lastPoint1 = {x: current1.x, y: current1.y};
this.lastPoint2 = {x: current2.x, y: current2.y};
}
},
end(e) {
// console.log('end', e)
//
this.scale = 1
this.x = this.y = 0
this.$refs.img.style['transition-duration'] = '300ms';
this.$refs.img.style.transform = `translate3d(0px,0px,0) scale(1)`;
// this.point1 = {x: e.touches[0].pageX, y: e.touches[0].pageY}
}
}
}
</script>
<style scoped lang="less">
</style>
<style scoped lang="less">
#TestImg {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
img {
width: 100%;
}
</style>

404
src/pages/test/TestSlide.vue

@ -1,404 +0,0 @@ @@ -1,404 +0,0 @@
<template>
<div id="TestSlide">
<SlideRowList
v-if="true"
name="baseSlide"
v-model:active-index="baseActiveIndex">
<SlideItem>
<SlideRowList
style="height: calc(100vh - 5rem);"
v-model:active-index="activeIndex">
<SlideItem>
<div id="TestSlide1" style="height: calc(100vh - 5rem);"></div>
</SlideItem>
<SlideItem>
<div id="TestSlide2" style="height: calc(100vh - 5rem);"></div>
</SlideItem>
</SlideRowList>
<Footer v-bind:init-tab="1"/>
</SlideItem>
<SlideItem>
<div id="TestSlide3" style="overflow: auto;height: 100vh;">
<p style="height: 50px;" v-for="item in 20">1</p>
</div>
</SlideItem>
</SlideRowList>
<!-- <div id="TestSlide1" style="height: calc(100% - 5rem);"></div>-->
</div>
</template>
<script lang="jsx">
import Slide from "./slide.jsx";
import SlideVideo from "../../components/slide/SlideVideo";
import SlideUser from "../../components/slide/SlideUser";
import SlideImgs from "../../components/slide/SlideAlbum";
import resource from "../../assets/data/resource.js";
import CONST_VAR from "../../utils/const_var";
import Dom from "../../utils/dom";
export default {
name: "TestSlide",
components: {},
props: {
modelValue: false
},
data() {
return {
totalSize: 52,
pageSize: 30,
pageNo: 0,
baseActiveIndex: 0,
activeIndex: 0,
lastClickTime: 0,
isDbClick: false,
dbClickTimer: null,
}
},
computed: {},
watch: {},
created() {
},
mounted() {
let list = resource.videos
list = list.concat(resource.videos)
list = list.slice(0, 5)
list.map(v => v.type = 'recommend-video')
if (true) {
// if (false) {
list.map(v => {
v.type = 'recommend-video'
})
// list.unshift({
// type: 'img',
// src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}`
// })
// list.unshift({
// type: 'user-imgs',
// src: `http://douyin.ttentau.top/0.mp4?vframe/jpg/offset/0/w/${document.body.clientWidth}`
// })
// list.unshift({
// type: 'send-video',
// src: `http://douyin.ttentau.top/0.mp4`
// })
// list.unshift({
// type: 'user',
// "id": "224e9a00-ffa0-4bc1-bb07-c318c7b02fa5",
// "avatar": new URL('../../assets/img/icon/avatar/1.png', import.meta.url).href,
// "name": "",
// "realName": "",
// "sex": "",
// "age": 25,
// "idCard": null,
// "phone": "",
// "address": null,
// "wechat": "",
// "password": null,
// "lastLoginTime": "1629993515",
// "createTime": "1630035089",
// "isDelete": 0,
// "account": "234",
// "pinyin": "H",
// "select": false,
// videos: [
// {
// "id": "c99d325c-741e-4722-9f39-82bb423a5989",
// "cover": "https://p26.douyinpic.com/img/tos-cn-i-0004/9cf624ff4e054c8f997295473dce49cc~c5_300x400.jpeg?from=4257465056_large",
// "dynamic_cover": "https://p3.douyinpic.com/obj/tos-cn-i-0004/9cf624ff4e054c8f997295473dce49cc?from=4257465056_large",
// "origin_cover": "https://p11.douyinpic.com/tos-cn-p-0015/d9e9b6dc783f4c13a8e5cc08df788a02_1627117997~tplv-dy-360p.jpeg?from=4257465056&s=&se=false&sh=&sc=&l=202108301444360102111780824E10113C&biz_tag=feed_cover",
// "video": "https://api.amemv.com/aweme/v1/play/?video_id=v0300fg10000c3ttjarc77ucs14tfra0&line=1&file_id=8b05a5dfb9644865a605ba13cc25f0fe&sign=07cddb6e3292bb2f4478d1f9e6187b33&is_play_url=1&source=PackSourceEnum_PUBLISH",
// "video_data_size": 10754240,
// "duration": 151720,
// "desc": "# #",
// "allow_download": 0,
// "allow_duet": 0,
// "allow_react": 0,
// "allow_music": 1,
// "allow_douplus": 1,
// "allow_share": 1,
// "digg_count": 156,
// "comment_count": 7,
// "download_count": 0,
// "play_count": 0,
// "share_count": 0,
// "forward_count": 0,
// "collect_count": 0,
// "sort": 9,
// "is_top": 0,
// "city": "350100",
// "musicId": "0da2663b-6bff-425f-a93e-9106b4889c99",
// "create_time": "1630391758",
// "creator_id": "54884802577",
// "status": 1,
// "topics": [
// {
// "id": "41821c6d-e14f-47f1-a391-f0b1f42afbe1",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// },
// {
// "id": "c10178eb-441f-4dc7-93b6-eaae1b6248cc",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// ],
// "music": {
// "id": "8ce2cb26-4772-4c7b-91d9-a2580c667c21",
// "cover": "https://p3.douyinpic.com/aweme/100x100/85f000239e43c3c985b5.jpeg?from=116350172",
// "mp3": "https://sf6-cdn-tos.douyinstatic.com/obj/ies-music/6995889105167076132.mp3",
// "title": "@",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// },
// {
// "id": "cf26d20e-577f-4e08-ae0e-77eac2f1adbb",
// "cover": "https://p3.douyinpic.com/img/tos-cn-i-0004/a62aa299fd1f48e28a783deec2cdccbe~c5_300x400.jpeg?from=4257465056_large",
// "dynamic_cover": "https://p3.douyinpic.com/obj/tos-cn-i-0004/a62aa299fd1f48e28a783deec2cdccbe?from=4257465056_large",
// "origin_cover": "https://p3.douyinpic.com/tos-cn-p-0015/15826b4e6ad54f0bbdb3bd8af024604c_1627117999~tplv-dy-360p.jpeg?from=4257465056&s=&se=false&sh=&sc=&l=202108301444360102111780824E10113C&biz_tag=feed_cover",
// "video": "https://api.amemv.com/aweme/v1/play/?video_id=v0300fg10000c3ttjarc77u4a4ivddk0&line=1&file_id=f8c9a32ba7bc4976b66db0437dd65d1b&sign=c96c9adfacde30c007555eee23f0f214&is_play_url=1&source=PackSourceEnum_PUBLISH",
// "video_data_size": 16850048,
// "duration": 216320,
// "desc": "# # ",
// "allow_download": 0,
// "allow_duet": 0,
// "allow_react": 0,
// "allow_music": 1,
// "allow_douplus": 1,
// "allow_share": 1,
// "digg_count": 72,
// "comment_count": 4,
// "download_count": 0,
// "play_count": 0,
// "share_count": 1,
// "forward_count": 0,
// "collect_count": 0,
// "sort": 10,
// "is_top": 0,
// "city": "350100",
// "musicId": "28944e2e-3bcb-4173-92d2-eb9a263aa826",
// "create_time": "1630391758",
// "creator_id": "54884802577",
// "status": 1,
// "topics": [
// {
// "id": "41821c6d-e14f-47f1-a391-f0b1f42afbe1",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// },
// {
// "id": "c10178eb-441f-4dc7-93b6-eaae1b6248cc",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// ],
// "music": {
// "id": "8ce2cb26-4772-4c7b-91d9-a2580c667c21",
// "cover": "https://p3.douyinpic.com/aweme/100x100/85f000239e43c3c985b5.jpeg?from=116350172",
// "mp3": "https://sf6-cdn-tos.douyinstatic.com/obj/ies-music/6995889105167076132.mp3",
// "title": "@",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// },
// {
// "id": "f3fd9b59-6ff5-4301-ac18-a4b8cbf35982",
// "cover": "https://p9.douyinpic.com/img/tos-cn-i-0004/890ebdf8a5c84abcae18c6e00c4165a0~c5_300x400.jpeg?from=4257465056_large",
// "dynamic_cover": "https://p3.douyinpic.com/obj/tos-cn-i-0004/890ebdf8a5c84abcae18c6e00c4165a0?from=4257465056_large",
// "origin_cover": "https://p26.douyinpic.com/tos-cn-p-0015/0d7948340d3543bda3357a9496e0cb86_1627117998~tplv-dy-360p.jpeg?from=4257465056&s=&se=false&sh=&sc=&l=202108301444360102111780824E10113C&biz_tag=feed_cover",
// "video": "https://api.amemv.com/aweme/v1/play/?video_id=v0200fg10000c3ttjarc77ucsm96q040&line=1&file_id=ccc7eccfa0d746febdcf7436841281a8&sign=a4fc8eb995aad2acdcc622371ecc9c7c&is_play_url=1&source=PackSourceEnum_PUBLISH",
// "video_data_size": 23547094,
// "duration": 230880,
// "desc": "# # ",
// "allow_download": 0,
// "allow_duet": 0,
// "allow_react": 0,
// "allow_music": 1,
// "allow_douplus": 1,
// "allow_share": 1,
// "digg_count": 93,
// "comment_count": 3,
// "download_count": 0,
// "play_count": 0,
// "share_count": 0,
// "forward_count": 0,
// "collect_count": 1,
// "sort": 11,
// "is_top": 0,
// "city": "350100",
// "musicId": "6fe6bbfc-d393-45f2-a2c8-432422c5904a",
// "create_time": "1630391758",
// "creator_id": "54884802577",
// "status": 1,
// "topics": [
// {
// "id": "41821c6d-e14f-47f1-a391-f0b1f42afbe1",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// },
// {
// "id": "c10178eb-441f-4dc7-93b6-eaae1b6248cc",
// "name": "",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// ],
// "music": {
// "id": "8ce2cb26-4772-4c7b-91d9-a2580c667c21",
// "cover": "https://p3.douyinpic.com/aweme/100x100/85f000239e43c3c985b5.jpeg?from=116350172",
// "mp3": "https://sf6-cdn-tos.douyinstatic.com/obj/ies-music/6995889105167076132.mp3",
// "title": "@",
// "creator_id": "54884802577",
// "create_time": "1630391758",
// "status": 1
// }
// },
// ]
// })
}
// console.log('length', list.length)
let config = {
render: (item, itemIndex, play) => {
let html
if (item.type === 'recommend-video') {
html = <SlideVideo
isPlay={play}
video={item}
index={itemIndex}
onShowComments={e => this.isCommenting = true}
onShowShare={e => this.isSharing = true}
onGoUserInfo={e => this.baseActiveIndex = 1}
onGoMusic={e => this.$nav('/home/music')}
v-model={[this.videos[itemIndex], 'video']}
/>
}
if (item.type === 'img') {
html = <img src={item.src} style="height:100%;"/>
}
if (item.type === 'imgs') {
html = <SlideImgs />
}
if (item.type === 'send-video') {
html = <video src={item.src} style="height:100%;"/>
}
if (item.type === 'user') {
html = <SlideUser onClose={this.t} modelValue={item}/>
}
return html
},
list,
index: 0,
request: async q => {
let res = await this.$api.videos.recommended(q)
if (res.code === 200) {
res.data.list.map(v => v.type = 'recommend-video')
return {code: 200, data: res.data}
}
return {code: 500}
}
};
let slide = new Slide('#TestSlide1', config)
let slide2 = new Slide('#TestSlide2', config)
// let layout = document.querySelector('#TestSlide')
// let checkTime = 300
// let setIsDbClickFalse = () => {
// this.dbClickTimer = setTimeout(() => {
// this.isDbClick = false
// }, checkTime);
// }
// layout.addEventListener('click', e => {
// if (this.isDbClick) {
// this.dbClick(e)
// clearTimeout(this.dbClickTimer);
// setIsDbClickFalse()
// return
// }
// let nowTime = new Date().getTime();
// if (nowTime - this.lastClickTime < checkTime) {
// this.dbClick(e)
// this.isDbClick = true
// setIsDbClickFalse()
// }
// this.lastClickTime = nowTime;
// }, true)
},
methods: {
t() {
console.log('t', this.totalSize)
},
dbClick(e) {
let id = 'a' + Date.now()
let elWidth = 80
let rotate = this.$randomNum(0, 1)
let template = `<img class="${rotate ? 'left love-dbclick' : 'right love-dbclick'}" id="${id}" src="src/assets/img/icon/loved.svg">`
let el = new Dom().create(template)
el.css({top: e.y - elWidth - 50, left: e.x - elWidth / 2,})
new Dom('#TestSlide').append(el)
setTimeout(() => {
new Dom(`#${id}`).remove()
}, 1000)
},
async getData() {
let res = await this.$api.videos.recommended({pageNo: this.pageNo, pageSize: this.pageSize})
console.log(res)
},
}
}
if (import.meta.hot) {
}
</script>
<style scoped>
.slide-wrapper {
width: 100%;
height: 100%;
overflow: hidden;
}
.slide-list {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
position: relative;
}
.slide-item {
min-width: 100%;
min-height: 100%;
position: relative;
}
</style>
<style lang="less">
@import "@/assets/less/index";
#TestSlide {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
overflow: auto;
color: white;
font-size: 1.4rem;
.content {
padding-top: 6rem;
}
}
</style>

111
src/pages/test/TestSwiperJs.vue

@ -1,111 +0,0 @@ @@ -1,111 +0,0 @@
<template>
<div class="slide">
<div class="slide-list"
ref="wrapperEl"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<slot></slot>
</div>
</div>
</template>
<script lang="jsx" setup>
import {onMounted, reactive, ref, watch} from "vue";
import GM from "@/utils";
import {
getSlideDistance,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from "@/components/slide/common";
import {SlideType} from "@/utils/const_var";
const emit = defineEmits(['update:index'])
const props = defineProps({
index: {
type: Number,
default: () => {
return 0
}
},
name: {
type: String,
default: () => ''
},
})
const judgeValue = 20
const wrapperEl = ref(null)
const state = reactive({
name: props.name,
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},
})
watch(
() => props.index,
(newVal) => {
if (state.localIndex !== newVal) {
state.localIndex = newVal
GM.$setCss(wrapperEl.value, 'transition-duration', `300ms`)
GM.$setCss(wrapperEl.value, 'transform', `translate3d(${getSlideDistance(state, SlideType.HORIZONTAL)}px, 0, 0)`)
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.HORIZONTAL)
})
function touchStart(e) {
slideTouchStart(e, wrapperEl.value, state)
}
function touchMove(e) {
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, null, SlideType.HORIZONTAL)
}
function touchEnd(e) {
slideTouchEnd(e, state, canNext, () => {
})
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, emit)
}
function canNext(isNext) {
return !((state.localIndex === 0 && !isNext) || (state.localIndex === state.wrapper.childrenLength - 1 && isNext));
}
</script>
<style lang="less" scoped>
.page {
font-size: 14rem;
color: white;
}
.swiper {
height: 50vh;
//width: 100%;
color: white;
font-size: 14rem;
.swiper-slide {
width: 100vw;
}
.aa {
height: 50vh;
width: 100vw;
}
}
</style>

278
src/pages/test/slide.jsx

@ -1,278 +0,0 @@ @@ -1,278 +0,0 @@
import Dom from "../../utils/dom";
import * as Vue from "vue";
export default class Slide {
constructor(id, config = {index: 0}) {
this.slideList = this.create('<div class="slide-list"></div>')
this.slideList.addEventListener('touchstart', this.touchstart.bind(this))
this.slideList.addEventListener('touchmove', this.touchmove.bind(this))
this.slideList.addEventListener('touchend', this.touchend.bind(this))
let container = new Dom(id)
// container.css('height','100%')
container.css('width', '100%')
container.css('overflow', 'hidden')
container.append(new Dom(this.slideList))
this.total = 0
this.pageSize = 10
this.pageNo = 0
this.list = []
this.index = config.index || 0
this.listMap = new Map()
this.loading = false
this.judgeValue = 0
this.startTime = 0
this.startLocationX = 0
this.startLocationY = 0
this.moveXDistance = 0
this.moveYDistance = 0
this.virtualTotal = 5
this.height = parseFloat(container.css('height'))
// console.log('height',this.height)
this.isDrawDown = true
this.config = config
this.appInsMap = new Map()
this.isRecommend = !(this.config.list && this.config.list.length);
this.getData(this.pageNo)
}
async getData(pageNo, init = true) {
if (this.isRecommend) {
this.getRecommend(pageNo).then(r => {
init && this.init()
})
} else {
if (init) {
this.total = this.config.list.length
for (let i = 0; i < this.config.list.length / this.virtualTotal; i++) {
this.listMap.set(i, this.config.list.slice(i * this.virtualTotal, (i + 1) * this.virtualTotal))
}
this.init()
}
}
}
async getRecommend(pageNo) {
// if (pageNo === 1) return
if (this.config.request) {
if (this.listMap.has(pageNo)) return
this.loading = true
let res = await this.config.request({pageNo, pageSize: this.pageSize})
this.loading = true
if (res.code === 200) {
this.total = res.data.total
this.pageNo = pageNo
// console.log('', res.data.list)
this.listMap.set(pageNo, res.data.list)
// this.list = this.list.concat(res.data.list)
}
}
}
init() {
//
// virtualTotal5
// 22
// 5
let start = 0
let end = start + this.virtualTotal
if (this.total > this.virtualTotal) {
if (this.index > 1) start = this.index - 2
end = start + this.virtualTotal
if (end > this.total) {
start = start - (end - this.total)
}
}
// console.log('startIndex', start)
// console.log('endIndex', end)
this.getList().slice(start, end).map((v, i) => {
let el = this.getInsEl(v, start + i, this.index === start + i)
this.slideList.appendChild(el)
})
//this.total > this.virtualTotalthis.virtualTotaltop
//this.index > 1 setTopthis.index > 2
// if (this.index > 1 && this.total > this.virtualTotal) {
if (this.index > 1) {
this.css(this.slideList, 'transform', `translate3d(0px, ${this.getHeight()}px, 0px)`)
this.slideList.childNodes.forEach(v => {
//(this.total - 1 - this.index) > 1 ? 0 : this.total - 1 - this.index) , Nheight
console.log('((this.total - 1 - this.index) > 1 ? 0 : this.total - 1 - this.index)',
(this.total - 1 - this.index) > 1 ? 0 : this.total - 1 - this.index)
this.css(v, 'top', (this.index - 2 - ((this.total - 1 - this.index) > 1 ? 0 : this.total - 1 - this.index)) * this.height + 'px')
})
}
// this.setTop()
this.setActive()
}
getInsEl(item, index, play = false) {
// console.log('index',index,play)
let slideVNode = this.config.render(item, index, play)
const app = Vue.createApp({
render() {
return <div class={`slide-item slide-item-${index}`}>{slideVNode}</div>
}
})
const ins = app.mount(document.createElement('div'))
this.appInsMap.set(index, app)
return ins.$el
}
touchstart(e) {
// console.log('start')
this.startLocationX = e.touches[0].pageX
this.startLocationY = e.touches[0].pageY
this.moveXDistance = 0
this.moveYDistance = 0
this.startTime = Date.now()
// console.log('touchstart', this.startTime)
this.css(this.slideList, 'transition-duration', '0ms')
}
touchmove(e) {
// console.log('move')
this.moveXDistance = e.touches[0].pageX - this.startLocationX
this.moveYDistance = e.touches[0].pageY - this.startLocationY
// console.log('touchmove', this.moveXDistance)
// console.log('touchmove', this.moveYDistance)
this.isDrawDown = this.moveYDistance < 0
// console.log('isDrawDown', this.isDrawDown)
if (this.isDrawDown) {
if (this.index === this.getList().length - 1) {
this.css(this.slideList, 'transform', `translate3d(0px, ${this.getHeight() + (Math.abs(this.moveYDistance) > this.height / 5 ? -this.height / 5 : this.moveYDistance)}px, 0px)`)
return
}
} else {
if (this.index === 0) return
}
this.css(this.slideList, 'transform', `translate3d(0px, ${this.getHeight() + this.moveYDistance + (this.isDrawDown ? this.judgeValue : -this.judgeValue)}px, 0px)`)
}
touchend() {
// console.log('end')
//
if (this.isDrawDown && this.loading && this.index === this.getList().length - 1) {
return console.log('加载中')
}
let canSlide = this.height / 8 < Math.abs(this.moveYDistance) && Math.abs(this.moveYDistance) > 40;
if (Date.now() - this.startTime < 40) canSlide = false
if (canSlide) {
let stopPreviousNodeFn = (index) => {
setTimeout(() => {
let previousNode = this.slideList.querySelector(`.slide-item-${index} .video-wrapper`)
previousNode && previousNode.dispatchEvent(new Event('stop'))
}, 300)
}
//index
stopPreviousNodeFn(this.index)
if (this.isDrawDown) {
if (this.index < this.getList().length - 1) {
this.index += 1
}
if (this.index < this.total - 2) {
let addIndex = this.index + 2
let removeIndex = this.index - 3
//
if (this.getList()[addIndex]) {
let res = this.slideList.querySelector(`.slide-item-${addIndex}`)
if (!res) {
this.slideList.appendChild(this.getInsEl(this.getList()[addIndex], addIndex))
}
let res2 = this.slideList.querySelector(`.slide-item-${removeIndex}`)
if (res2) {
this.appInsMap.get(removeIndex).unmount()
// this.slideList.removeChild(res2)
}
} else {
this.getData(this.pageNo + 1, false)
console.log('没有这条数据')
}
if (this.index + 5 > this.getList().length) {
this.getData(this.pageNo + 1, false)
}
}
} else {
if (this.index > 0) {
this.index -= 1
}
if (this.index > 1) {
let addIndex = this.index - 2
let removeIndex = this.index + 3
let res = this.slideList.querySelector(`.slide-item-${addIndex}`)
if (!res) {
this.slideList.insertBefore(this.getInsEl(this.getList()[addIndex], addIndex), this.slideList.firstChild)
}
let res2 = this.slideList.querySelector(`.slide-item-${removeIndex}`)
if (res2) {
this.appInsMap.get(removeIndex).unmount()
// this.slideList.removeChild(res2)
}
}
}
let nextNode = this.slideList.querySelector(`.slide-item-${this.index} .video-wrapper`)
nextNode && nextNode.dispatchEvent(new Event('play'))
this.setTop()
this.setActive()
}
this.css(this.slideList, 'transition-duration', '300ms')
this.css(this.slideList, 'transform', `translate3d(0px, ${this.getHeight()}px, 0px)`)
}
getList() {
return Array.from(this.listMap.values()).flat()
}
create(template) {
let tempNode = document.createElement('div');
tempNode.innerHTML = template.trim();
return tempNode.firstChild;
}
css(el, ...args) {
el.style[args[0]] = args[1]
}
getHeight() {
return -this.index * this.height
}
setActive() {
this.slideList.childNodes.forEach(v => {
v.classList.remove('active')
})
this.slideList.childNodes.forEach(v => {
if (v.classList.value.search(this.index) !== -1) {
v.classList.add('active')
}
})
}
setTop() {
if (this.index > 1 && this.index < this.getList().length - 2) {
this.slideList.childNodes.forEach(v => {
this.css(v, 'top', (this.index - 2) * this.height + 'px')
})
}
}
}

4
src/router/routes.js

@ -72,7 +72,6 @@ const routes = [ @@ -72,7 +72,6 @@ const routes = [
{path: '/test', component: Test},
{path: '/test4', component: Test4},
{path: '/video-detail', component: VideoDetail},
{path: '/attention', component: Attention},
{path: '/publish', component: Publish},
@ -149,6 +148,9 @@ const routes = [ @@ -149,6 +148,9 @@ const routes = [
{path: '/home/report', component: Report},
{path: '/home/submit-report', component: SubmitReport},
{path: '/message/share-to-friend', component: Share2Friend},
{path: '/video-detail', name: 'video-detail', component: VideoDetail},
]
export default routes

2
src/store/index.js

@ -74,7 +74,7 @@ const store = Vuex.createStore({ @@ -74,7 +74,7 @@ const store = Vuex.createStore({
store.excludeRoutes.splice(resIndex, 1)
}
}
console.log('store.excludeRoutes', store.excludeRoutes)
console.log('store.excludeRoutes', store.excludeRoutes,val)
},
},
actions: {

11
src/store/pinia.js

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
import {defineStore} from "pinia";
export const useBaseStore = defineStore('base', {
state: () => {
return {
routeData: null
}
},
getters: {},
actions: {},
})

3
src/utils/index.jsx

@ -7,7 +7,7 @@ import Config from '../config' @@ -7,7 +7,7 @@ import Config from '../config'
import NoticeDialog from "../components/dialog/NoticeDialog";
import dayjs from 'dayjs'
import bus, {EVENT_KEY} from "./bus";
import {cloneDeep} from "lodash";
import {cloneDeep} from "lodash-es";
const Utils = {
require2(url) {
@ -453,6 +453,7 @@ export function _checkImgUrl(url) { @@ -453,6 +453,7 @@ export function _checkImgUrl(url) {
export function _duration(num){
return Utils.$duration(num)
}
export function _formatNumber(num) {
return Utils.formatNumber(num)
}

2
src/utils/mixin.js

@ -14,7 +14,7 @@ import BaseButton from "../components/BaseButton"; @@ -14,7 +14,7 @@ import BaseButton from "../components/BaseButton";
import CONST_VAR from "./const_var";
import Dom from "./dom";
import bus, {EVENT_KEY} from "./bus";
import {random} from "lodash";
import {random} from "lodash-es";
import {Icon} from '@iconify/vue'
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";

3
vite.config.js

@ -3,6 +3,7 @@ import Vue from '@vitejs/plugin-vue' @@ -3,6 +3,7 @@ import Vue from '@vitejs/plugin-vue'
import VueJsx from '@vitejs/plugin-vue-jsx'
import VueMacros from 'unplugin-vue-macros/vite'
import {resolve} from 'path'
import DefineOptions from 'unplugin-vue-define-options/vite' // 引入插件
function pathResolve(dir) {
return resolve(__dirname, ".", dir)
@ -28,6 +29,8 @@ export default defineConfig({ @@ -28,6 +29,8 @@ export default defineConfig({
// // exclude: [/node_modules/, /jQuery\.js/]
// // }
// }),
DefineOptions(),
Vue(),
VueJsx(),
],

Loading…
Cancel
Save