清除测试组件
This commit is contained in:
parent
da4ad7e130
commit
7e18fe228d
@ -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
132
pnpm-lock.yaml
@ -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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
/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:
|
||||
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
|
||||
|
||||
@ -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.querySelectorAll,找不到dom,必须用$refs的方式
|
||||
this.marqueeText = new Dom(this.$refs.marqueeText)
|
||||
//必须在nextTick在调用,不然后新生成dom,获取不到width
|
||||
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>
|
||||
@ -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 @@
|
||||
</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>
|
||||
|
||||
@ -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({
|
||||
type: Object,
|
||||
default: {
|
||||
author: DefaultUser,
|
||||
isRequest: false,
|
||||
aweme_list: [],
|
||||
}
|
||||
},
|
||||
@ -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)
|
||||
})
|
||||
//去年保存的老数据有id。现在去网页版复制数据没id了。。。
|
||||
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) {
|
||||
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) {
|
||||
}
|
||||
let endTime = Date.now()
|
||||
state.isAutoScaleCover = (endTime - state.start.time) < 100
|
||||
console.log('touchEnd')
|
||||
// console.log('touchEnd')
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@ -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 @@
|
||||
|
||||
<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
|
||||
},
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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({
|
||||
</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({
|
||||
.content {
|
||||
color: #fff;
|
||||
width: 75vw;
|
||||
//display: flex;
|
||||
//flex-direction: column;
|
||||
text-align: left;
|
||||
|
||||
.location-wrapper {
|
||||
display: flex;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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([
|
||||
|
||||
@ -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(
|
||||
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) {
|
||||
start = end - props.virtualTotal
|
||||
}
|
||||
if (start < 0) start = 0
|
||||
console.log('start', start, end)
|
||||
list.slice(start, end).map(
|
||||
(item, index) => {
|
||||
//自动播放,当前条(可能是0,可能是其他),试了下用jq来找元素,然后trigger play事件,要慢点样
|
||||
@ -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) {
|
||||
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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 {
|
||||
//这里先加个1,保持if表达式一致
|
||||
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,重新加载。但未经测试
|
||||
@ -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, {
|
||||
app.use(VueMasonryPlugin)
|
||||
app.use(router)
|
||||
app.use(store)
|
||||
app.use(pinia)
|
||||
app.mount('#app')
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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";
|
||||
|
||||
|
||||
@ -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 @@
|
||||
<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'
|
||||
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) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -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";
|
||||
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) {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.active, n => {
|
||||
if (!state.list.length && n) {
|
||||
store.commit('setLoading', false)
|
||||
getData()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
})
|
||||
|
||||
@ -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({
|
||||
type: Function,
|
||||
default: void 0
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
})
|
||||
|
||||
const store = useStore()
|
||||
@ -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,
|
||||
|
||||
@ -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 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>
|
||||
<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>
|
||||
</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 @@
|
||||
</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 @@
|
||||
</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
|
||||
defineOptions({
|
||||
name: 'VideoDetail'
|
||||
})
|
||||
const store = useBaseStore()
|
||||
const data = reactive({
|
||||
dialog: {
|
||||
shareToFriend: false,
|
||||
permissionDialog: false,
|
||||
test: false,
|
||||
},
|
||||
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'}
|
||||
},
|
||||
},
|
||||
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 {
|
||||
width: 100%;
|
||||
|
||||
.search-wrapper {
|
||||
height: @header-height;
|
||||
z-index: 9;
|
||||
position: fixed;
|
||||
top: 10rem;
|
||||
@ -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;
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
//用于改变zindex的层级到上层,反正比slide高就行。不然摸不到subType.
|
||||
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>
|
||||
@ -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: '',
|
||||
|
||||
@ -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
|
||||
// 如果通过修改宽高或使用transform缩放,但将transform-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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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() {
|
||||
//计算出正确的开始下标和结束下标
|
||||
// 情况一,数据是推荐的,默认取前面virtualTotal(5)条
|
||||
// 情况二,数据是固定的,当前要播放的视频在中间,那么取前2,后2
|
||||
// 情况二,数据是固定的,当前要播放的视频在后面,那么往前取,直到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.virtualTotal,只有总条数在不少this.virtualTotal条数的情况下用top
|
||||
//this.index > 1 和setTop保持统一,这里其实可以用this.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) , 如果当前是最后两条,那么要多减去N个height
|
||||
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')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 = [
|
||||
{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
|
||||
@ -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
Normal file
11
src/store/pinia.js
Normal file
@ -0,0 +1,11 @@
|
||||
import {defineStore} from "pinia";
|
||||
|
||||
export const useBaseStore = defineStore('base', {
|
||||
state: () => {
|
||||
return {
|
||||
routeData: null
|
||||
}
|
||||
},
|
||||
getters: {},
|
||||
actions: {},
|
||||
})
|
||||
@ -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) {
|
||||
export function _duration(num){
|
||||
return Utils.$duration(num)
|
||||
}
|
||||
|
||||
export function _formatNumber(num) {
|
||||
return Utils.formatNumber(num)
|
||||
}
|
||||
|
||||
@ -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,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({
|
||||
// // exclude: [/node_modules/, /jQuery\.js/]
|
||||
// // }
|
||||
// }),
|
||||
DefineOptions(),
|
||||
|
||||
Vue(),
|
||||
VueJsx(),
|
||||
],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user