Merge branch 'dev'

This commit is contained in:
zyronon 2024-04-19 17:52:44 +08:00
commit bd90294071
16 changed files with 411 additions and 364 deletions

View File

@ -1,36 +1,36 @@
#name: Translate README
#
#on:
# push:
# branches:
# - master
#jobs:
# build:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v2
# - name: Setup Node.js
# uses: actions/setup-node@v1
# with:
# node-version: 12.x
# # ISO Langusge Codes: https://cloud.google.com/translate/docs/languages
# - name: Adding README - English
# uses: dephraiim/translate-readme@main
# with:
# LANG: en
# - name: Adding README - Japanese
# uses: dephraiim/translate-readme@main
# with:
# LANG: ja
# - name: Adding README - German
# uses: dephraiim/translate-readme@main
# with:
# LANG: de
# - name: Adding README - French
# uses: dephraiim/translate-readme@main
# with:
# LANG: fr
# - name: Adding README - Spanish
# uses: dephraiim/translate-readme@main
# with:
# LANG: es
name: Translate README
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
# ISO Langusge Codes: https://cloud.google.com/translate/docs/languages
- name: Adding README - English
uses: dephraiim/translate-readme@main
with:
LANG: en
- name: Adding README - Japanese
uses: dephraiim/translate-readme@main
with:
LANG: ja
- name: Adding README - German
uses: dephraiim/translate-readme@main
with:
LANG: de
- name: Adding README - French
uses: dephraiim/translate-readme@main
with:
LANG: fr
- name: Adding README - Spanish
uses: dephraiim/translate-readme@main
with:
LANG: es

View File

@ -33,11 +33,11 @@
Github pages: [https://zyronon.github.io/douyin/](https://zyronon.github.io/douyin/)
~~Vercel: [http://dy.ttentau.top/](http://dy.ttentau.top/) (中国推荐访问这个)~~
[//]: # (Vercel: [http://dy.ttentau.top/](http://dy.ttentau.top/) (中国推荐访问这个)~~)
~~Netlify: [https://douyins.netlify.app/](https://douyins.netlify.app/) (中国以外地区推荐访问这个)~~
[//]: # (Netlify: [https://douyins.netlify.app/](https://douyins.netlify.app/) (中国以外地区推荐访问这个)~~)
Vercel和Netlify分别送的100G免费流量已经用完了...
Vercel和Netlify分别送的100G免费流量已经用完了...🤣
Android Apk: https://github.com/zyronon/douyin/releases

View File

@ -6,16 +6,16 @@
</keep-alive>
</transition>
</router-view>
<BaseMask v-if="!isMobile" />
<div v-if="!isMobile" class="guide">
<Icon icon="mynaui:danger-triangle" />
<div class="txt">
<h2>切换至手机模式才可正常使用</h2>
<h3>1. F12 调出控制台</h3>
<h3>2. Ctrl+Shift+M或点击下面图标</h3>
</div>
<img src="@/assets/img/guide.png" alt="" />
</div>
<!-- <BaseMask v-if="!isMobile" />-->
<!-- <div v-if="!isMobile" class="guide">-->
<!-- <Icon icon="mynaui:danger-triangle" />-->
<!-- <div class="txt">-->
<!-- <h2>切换至手机模式才可正常使用</h2>-->
<!-- <h3>1. F12 调出控制台</h3>-->
<!-- <h3>2. Ctrl+Shift+M或点击下面图标</h3>-->
<!-- </div>-->
<!-- <img src="@/assets/img/guide.png" alt="" />-->
<!-- </div>-->
<Call />
</template>
<script setup lang="ts">

View File

@ -117,6 +117,7 @@ p {
}
.slide {
touch-action: none;
height: 100%;
width: 100%;
transition: height 0.3s;

View File

@ -351,7 +351,7 @@ function scroll() {
}
}
function touchStart(e) {
function touchStart(e: TouchEvent) {
state.start.x = e.touches[0].pageX
state.start.y = e.touches[0].pageY
state.start.time = Date.now()
@ -362,7 +362,7 @@ function touchStart(e) {
// console.log('touchStart', page.value.scrollTop)
}
function touchMove(e) {
function touchMove(e: TouchEvent) {
state.move.x = e.touches[0].pageX - state.start.x
state.move.y = e.touches[0].pageY - state.start.y
let isNext = state.move.y < 0

View File

@ -102,13 +102,13 @@ import {
watch
} from 'vue'
import {
getSlideDistance,
getSlideOffset,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from './common'
slidePointerMove,
slidePointerDown
} from '@/utils/slide'
import { SlideAlbumOperationStatus, SlideItemPlayStatus, SlideType } from '../../utils/const_var'
import ItemToolbar from './ItemToolbar'
import ItemDesc from './ItemDesc'
@ -243,6 +243,8 @@ const wrapperEl = ref(null)
let lockDatetime = 0
const state = reactive({
type: SlideType.HORIZONTAL,
judgeValue: 20,
name: 'SlideHorizontal',
localIndex: 0,
needCheck: true,
@ -354,7 +356,7 @@ watch(
GM.$setCss(
wrapperEl.value,
'transform',
`translate3d(${getSlideDistance(state, SlideType.HORIZONTAL)}px, 0, 0)`
`translate3d(${getSlideOffset(state, wrapperEl.value)}px, 0, 0)`
)
}
)
@ -408,7 +410,7 @@ function touchStart(e) {
// Utils.$showNoticeDialog('start'+e.touches.length)
console.log('start', e.touches.length)
if (e.touches.length === 1) {
slideTouchStart(e, wrapperEl.value, state)
slidePointerDown(e, wrapperEl.value, state)
} else {
if (state.operationStatus === SlideAlbumOperationStatus.Zooming) {
// state.start.center = Utils.getCenter(state.start.point1, state.start.point2)
@ -451,17 +453,13 @@ function touchMove(e) {
} else {
// console.log('m2')
state.isAutoPlay = false
slideTouchMove(
slidePointerMove(
e,
wrapperEl.value,
state,
judgeValue,
canNext,
() => {
// console.log('move-nextcb')
},
SlideType.HORIZONTAL,
() => {
//TODO
if (state.operationStatus !== SlideAlbumOperationStatus.Normal) {
Utils.$stopPropagation(e)
}
@ -582,7 +580,7 @@ function touchEnd(e) {
startLoop()
}
)
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, null)
slideReset(wrapperEl.value, state)
}
}
}
@ -595,7 +593,7 @@ function setItemRef(el, key) {
el && state[key].push(el)
}
function canNext(isNext) {
function canNext(state, isNext) {
let res = !(
(state.localIndex === 0 && !isNext) ||
(state.localIndex === props.item.imgs.length - 1 && isNext)

View File

@ -2,13 +2,13 @@
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import GM from '../../utils'
import {
getSlideDistance,
getSlideOffset,
slideInit,
slidePointerDown,
slidePointerMove,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from './common'
slideTouchEnd
} from '@/utils/slide'
import { SlideType } from '@/utils/const_var'
const props = defineProps({
@ -31,16 +31,22 @@ const props = defineProps({
const emit = defineEmits(['update:index'])
let ob = null
const judgeValue = 20
const wrapperEl = ref(null)
const state = reactive({
judgeValue: 20,
type: SlideType.HORIZONTAL,
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 }
wrapper: {
width: 0,
height: 0,
//childrenLengthcanNext
childrenLength: 0
}
})
watch(
@ -54,15 +60,17 @@ watch(
GM.$setCss(
wrapperEl.value,
'transform',
`translate3d(${getSlideDistance(state, SlideType.HORIZONTAL, wrapperEl.value)}px, 0, 0)`
`translate3d(${getSlideOffset(state, wrapperEl.value)}px, 0, 0)`
)
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.HORIZONTAL)
slideInit(wrapperEl.value, state)
//
//childrenLengthcanNext
ob = new MutationObserver(() => {
state.wrapper.childrenLength = wrapperEl.value.children.length
})
@ -74,33 +82,16 @@ onUnmounted(() => {
})
function touchStart(e: TouchEvent) {
slideTouchStart(e, wrapperEl.value, state)
slidePointerDown(e, wrapperEl.value, state)
}
function touchMove(e: TouchEvent) {
slideTouchMove(
e,
wrapperEl.value,
state,
judgeValue,
canNext,
null,
SlideType.HORIZONTAL,
null,
null
)
slidePointerMove(e, wrapperEl.value, state)
}
function touchEnd(e: TouchEvent) {
slideTouchEnd(e, state, canNext, () => {})
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, emit)
}
function canNext(isNext: boolean) {
return !(
(state.localIndex === 0 && !isNext) ||
(state.localIndex === state.wrapper.childrenLength - 1 && isNext)
)
slideTouchEnd(e, state)
slideReset(wrapperEl.value, state, emit)
}
</script>

View File

@ -2,13 +2,13 @@
import { onMounted, reactive, ref, watch } from 'vue'
import GM from '../../utils'
import {
getSlideDistance,
getSlideOffset,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from './common'
slidePointerMove,
slidePointerDown
} from '@/utils/slide'
import { SlideType } from '@/utils/const_var'
const props = defineProps({
@ -26,9 +26,10 @@ const props = defineProps({
})
const emit = defineEmits(['update:index'])
const judgeValue = 20
const wrapperEl = ref(null)
const state = reactive({
judgeValue: 20,
type: SlideType.HORIZONTAL,
name: 'SlideVertical',
localIndex: props.index,
needCheck: true,
@ -49,34 +50,27 @@ watch(
GM.$setCss(
wrapperEl.value,
'transform',
`translate3d(0,${getSlideDistance(state, SlideType.VERTICAL)}px, 0)`
`translate3d(0,${getSlideOffset(state, wrapperEl.value)}px, 0)`
)
}
}
)
onMounted(() => {
slideInit(wrapperEl.value, state, SlideType.VERTICAL)
slideInit(wrapperEl.value, state)
})
function touchStart(e) {
slideTouchStart(e, wrapperEl.value, state)
slidePointerDown(e, wrapperEl.value, state)
}
function touchMove(e) {
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, null, SlideType.VERTICAL)
slidePointerMove(e, wrapperEl.value, state)
}
function touchEnd(e) {
slideTouchEnd(e, state, canNext, null, null, SlideType.VERTICAL)
slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
}
function canNext(isNext) {
return !(
(state.localIndex === 0 && !isNext) ||
(state.localIndex === state.wrapper.childrenLength - 1 && isNext)
)
slideTouchEnd(e, state)
slideReset(wrapperEl.value, state, emit)
}
</script>

View File

@ -2,13 +2,13 @@
import { createApp, onMounted, reactive, ref, render as vueRender, watch } from 'vue'
import GM from '../../utils'
import {
getSlideDistance,
getSlideOffset,
slideInit,
slideReset,
slideTouchEnd,
slideTouchMove,
slideTouchStart
} from './common'
slidePointerMove,
slidePointerDown
} from '@/utils/slide'
import { SlideType } from '@/utils/const_var'
import SlideItem from '@/components/slide/SlideItem.vue'
import bus, { EVENT_KEY } from '../../utils/bus'
@ -62,6 +62,8 @@ const appInsMap = new Map()
const itemClassName = 'slide-item'
const wrapperEl = ref(null)
const state = reactive({
judgeValue: 20,
type: SlideType.VERTICAL,
name: props.name,
localIndex: props.index,
needCheck: true,
@ -168,11 +170,7 @@ function insertContent(list = props.list) {
let el = getInsEl(item, start + index, start + index === state.localIndex)
wrapperEl.value.appendChild(el)
})
GM.$setCss(
wrapperEl.value,
'transform',
`translate3d(0px,${getSlideDistance(state, SlideType.VERTICAL)}px, 0px)`
)
GM.$setCss(wrapperEl.value, 'transform', `translate3d(0px,${getSlideOffset(state)}px, 0px)`)
if (state.localIndex > 2 && list.length > 5) {
$(wrapperEl.value)
@ -228,12 +226,12 @@ function getInsEl(item, index, play = false) {
}
function touchStart(e) {
slideTouchStart(e, wrapperEl.value, state)
slidePointerDown(e, wrapperEl.value, state)
}
//TODO 2022-3-28:
function touchMove(e) {
slideTouchMove(e, wrapperEl.value, state, baseStore.judgeValue, canNext, null, SlideType.VERTICAL)
slidePointerMove(e, wrapperEl.value, state, canNext)
}
function touchEnd(e) {
@ -245,89 +243,77 @@ function touchEnd(e) {
) {
emit('refresh')
}
slideTouchEnd(
e,
state,
canNext,
(isNext) => {
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
) {
emit('loadMore')
slideTouchEnd(e, state, canNext, (isNext) => {
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) {
emit('loadMore')
}
let addItemIndex = state.localIndex + 2
let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)
if (state.wrapper.childrenLength < props.virtualTotal) {
if (res.length === 0) {
wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
}
let addItemIndex = state.localIndex + 2
let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)
if (state.wrapper.childrenLength < props.virtualTotal) {
if (res.length === 0) {
wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
}
}
if (
state.wrapper.childrenLength === props.virtualTotal &&
state.localIndex >= (props.virtualTotal + 1) / 2 &&
state.localIndex <= props.list.length - 3
) {
if (res.length === 0) {
wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
appInsMap
.get($(wrapperEl.value).find(`.${itemClassName}:first`).data('index'))
.unmount()
// $(wrapperEl.value).find(".base-slide-item:first").remove()
$(wrapperEl.value)
.find(`.${itemClassName}`)
.each(function () {
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
})
}
}
if (state.wrapper.childrenLength > props.virtualTotal) {
}
if (
state.wrapper.childrenLength === props.virtualTotal &&
state.localIndex >= (props.virtualTotal + 1) / 2 &&
state.localIndex <= props.list.length - 3
) {
if (res.length === 0) {
wrapperEl.value.appendChild(getInsEl(props.list[addItemIndex], addItemIndex))
appInsMap
.get($(wrapperEl.value).find(`.${itemClassName}:first`).data('index'))
.unmount()
// $(wrapperEl.value).find(".base-slide-item:first").remove()
$(wrapperEl.value)
.find(`.${itemClassName}`)
.each(function () {
let index = $(this).data('index')
if (index < state.localIndex - 2) {
appInsMap.get(index).unmount()
}
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
})
}
} else {
let addItemIndex = state.localIndex - 2
let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)
}
if (state.wrapper.childrenLength > props.virtualTotal) {
$(wrapperEl.value)
.find(`.${itemClassName}`)
.each(function () {
let index = $(this).data('index')
if (index < state.localIndex - 2) {
appInsMap.get(index).unmount()
}
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
})
}
} else {
let addItemIndex = state.localIndex - 2
let res = $(wrapperEl.value).find(`.${itemClassName}[data-index=${addItemIndex}]`)
if (state.localIndex > 1 && state.localIndex <= props.list.length - 4) {
if (res.length === 0) {
wrapperEl.value.prepend(getInsEl(props.list[addItemIndex], addItemIndex))
appInsMap
.get($(wrapperEl.value).find(`.${itemClassName}:last`).data('index'))
.unmount()
// $(wrapperEl.value).find(".base-slide-item:last").remove()
$(wrapperEl.value)
.find(`.${itemClassName}`)
.each(function () {
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
})
}
}
if (state.wrapper.childrenLength > props.virtualTotal) {
if (state.localIndex > 1 && state.localIndex <= props.list.length - 4) {
if (res.length === 0) {
wrapperEl.value.prepend(getInsEl(props.list[addItemIndex], addItemIndex))
appInsMap.get($(wrapperEl.value).find(`.${itemClassName}:last`).data('index')).unmount()
// $(wrapperEl.value).find(".base-slide-item:last").remove()
$(wrapperEl.value)
.find(`.${itemClassName}`)
.each(function () {
$(this).css('top', (state.localIndex - 2) * state.wrapper.height)
})
}
}
state.wrapper.childrenLength = wrapperEl.value.children.length
if (state.wrapper.childrenLength > props.virtualTotal) {
appInsMap.get($(wrapperEl.value).find(`.${itemClassName}:last`).data('index')).unmount()
}
}
},
null,
SlideType.VERTICAL
)
slideReset(wrapperEl.value, state, SlideType.VERTICAL, emit)
state.wrapper.childrenLength = wrapperEl.value.children.length
}
})
slideReset(wrapperEl.value, state, emit)
}
function canNext(isNext) {
function canNext(state, isNext) {
return !(
(state.localIndex === 0 && !isNext) ||
(state.localIndex === props.list.length - 1 && isNext)

View File

@ -1,163 +0,0 @@
import bus from '@/utils/bus'
import Utils from '@/utils'
import GM from '@/utils'
import { SlideType } from '@/utils/const_var'
import { nextTick } from 'vue'
export function slideInit(el, state, type) {
state.wrapper.width = GM.$getCss(el, 'width')
state.wrapper.height = GM.$getCss(el, 'height')
nextTick(() => {
state.wrapper.childrenLength = el.children.length
})
let t = getSlideDistance(state, type, el)
let dx1 = 0,
dx2 = 0
if (type === SlideType.HORIZONTAL) dx1 = t
else dx2 = t
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
}
export function slideTouchStart(e, el, state) {
Utils.$setCss(el, 'transition-duration', `0ms`)
state.start.x = e.touches[0].pageX
state.start.y = e.touches[0].pageY
state.start.time = Date.now()
}
//检测能否滑动
export function canSlide(state, judgeValue, type = SlideType.HORIZONTAL) {
if (state.needCheck) {
if (Math.abs(state.move.x) > judgeValue || Math.abs(state.move.y) > judgeValue) {
let angle = (Math.abs(state.move.x) * 10) / (Math.abs(state.move.y) * 10)
state.next = type === SlideType.HORIZONTAL ? angle > 1 : angle <= 1
// console.log('angle', angle, state.next)
state.needCheck = false
} else {
return false
}
}
return state.next
}
/**
* @param slideOtherDirectionCb 滑动其他方向时的回调目前用于图集进于放大模式后上下滑动推出放大模式
* */
export function slideTouchMove(
e,
el,
state,
judgeValue,
canNextCb,
nextCb,
type = SlideType.HORIZONTAL,
notNextCb,
slideOtherDirectionCb = null
) {
state.move.x = e.touches[0].pageX - state.start.x
state.move.y = e.touches[0].pageY - state.start.y
let isNext = type === SlideType.HORIZONTAL ? state.move.x < 0 : state.move.y < 0
let canSlideRes = canSlide(state, judgeValue, type)
if (canSlideRes && state.localIndex === 0 && !isNext && type === SlideType.VERTICAL) {
bus.emit(state.name + '-moveY', state.move.y)
}
if (canSlideRes) {
if (canNextCb?.(isNext, e)) {
nextCb?.()
if (type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-moveX', state.move.x)
}
Utils.$stopPropagation(e)
let t = getSlideDistance(state, type, el) + (isNext ? judgeValue : -judgeValue)
let dx1 = 0
let dx2 = 0
if (type === SlideType.HORIZONTAL) {
dx1 = t + state.move.x
} else {
dx2 = t + state.move.y
}
Utils.$setCss(el, 'transition-duration', `0ms`)
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
} else {
notNextCb?.()
}
} else {
slideOtherDirectionCb?.(e)
}
}
export function slideTouchEnd(
e,
state,
canNextCb,
nextCb,
doNotNextCb,
type = SlideType.HORIZONTAL
) {
let isHorizontal = type === SlideType.HORIZONTAL
let isNext = isHorizontal ? state.move.x < 0 : state.move.y < 0
if (!canNextCb?.(isNext)) return doNotNextCb?.()
if (state.next) {
Utils.$stopPropagation(e)
let endTime = Date.now()
let gapTime = endTime - state.start.time
let distance = isHorizontal ? state.move.x : state.move.y
let judgeValue = isHorizontal ? state.wrapper.width : state.wrapper.height
if (Math.abs(distance) < 20) gapTime = 1000
if (Math.abs(distance) > judgeValue / 3) gapTime = 100
if (gapTime < 150) {
if (isNext) {
state.localIndex++
} else {
state.localIndex--
}
return nextCb?.(isNext)
}
}
doNotNextCb?.()
}
export function slideReset(el, state, type, emit) {
Utils.$setCss(el, 'transition-duration', `300ms`)
let t = getSlideDistance(state, type, el)
let dx1 = 0
let dx2 = 0
if (type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-end', state.localIndex)
dx1 = t
} else {
bus.emit(state.name + '-end')
dx2 = t
}
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
state.start.x = state.start.y = state.start.time = state.move.x = state.move.y = 0
state.next = false
state.needCheck = true
emit?.('update:index', state.localIndex)
}
export function getSlideDistance(state, type = SlideType.HORIZONTAL, el) {
if (type === SlideType.HORIZONTAL) {
//TODO 统一
if (el) {
let widths = []
Array.from(el.children).map((v) => {
widths.push(v.getBoundingClientRect().width)
})
widths = widths.slice(0, state.localIndex)
if (widths.length) {
return -widths.reduce((a, b) => a + b)
}
return 0
}
return -state.localIndex * state.wrapper.width
} else {
return -state.localIndex * state.wrapper.height
}
}

View File

@ -1,6 +1,6 @@
<template>
<div class="test-slide-wrapper" id="home-index">
<SlideHorizontal v-model:index="state.baseIndex">
<SlideHorizontal name="first" v-model:index="state.baseIndex">
<SlideItem class="sidebar">
<div class="header">
<div class="left">下午好</div>
@ -100,13 +100,13 @@
<IndicatorHome
v-if="!state.fullScreen"
:loading="baseStore.loading"
name="main"
name="second"
@showSlidebar="state.baseIndex = 0"
v-model:index="state.navIndex"
/>
<SlideHorizontal
class="first-horizontal-item"
name="main"
name="second"
:change-active-index-use-anim="false"
v-model:index="state.navIndex"
>

View File

@ -11,7 +11,7 @@
</div>
<WaterfallList :list="list" class="list">
<template v-slot="{ item }">
<div class="card" @click="(e) => test(e, item)">
<div class="card" @click="(e) => showDetail(e, item)">
<img class="poster" v-lazy="_checkImgUrl(item.note_card?.cover?.url_default)" />
<div class="bottom">
<div class="title">
@ -127,7 +127,7 @@ function close() {
}, 300)
}
function test(e, item) {
function showDetail(e, item) {
let data = Mock.mock({
'comment_list|3-50': [
{

View File

@ -4,7 +4,7 @@
v-love="props.uniqueId"
:id="props.uniqueId"
:uniqueId="props.uniqueId"
name="main"
name="infinite"
:active="props.active"
:loading="baseStore.loading"
v-model:index="state.index"

View File

@ -21,7 +21,8 @@ export default {
}
export const SlideType = {
HORIZONTAL: 0,
VERTICAL: 1
VERTICAL: 1,
VERTICAL_INFINITE: 2
}
/*图集操作状态*/

View File

@ -6,7 +6,7 @@ export function useNav() {
const router = useRouter()
const store = useBaseStore()
return (path, query = {}, data) => {
return (path, query = {}, data?: any) => {
if (data) {
store.routeData = cloneDeep(data)
}

239
src/utils/slide.js Normal file
View File

@ -0,0 +1,239 @@
import bus from '@/utils/bus'
import Utils from '@/utils/index'
import GM from '@/utils/index'
import { SlideType } from '@/utils/const_var'
import { nextTick } from 'vue'
//初始化信息获取slide dom的长宽、子元素数量用于move事件判断能否滑动
export function slideInit(el, state) {
state.wrapper.width = GM.$getCss(el, 'width')
state.wrapper.height = GM.$getCss(el, 'height')
nextTick(() => {
state.wrapper.childrenLength = el.children.length
})
//获取偏移量
let t = getSlideOffset(state, el)
let dx1 = 0,
dx2 = 0
if (state.type === SlideType.HORIZONTAL) dx1 = t
else dx2 = t
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
}
export function slidePointerDown(e, el, state) {
Utils.$setCss(el, 'transition-duration', `0ms`)
//记录起点坐标用于move事件计算移动距离
state.start.x = e.touches[0].pageX
state.start.y = e.touches[0].pageY
//记录按下时间用于up事件判断滑动时间
state.start.time = Date.now()
}
/**
* 检测能否滑动
* @param state
* @returns {boolean}
*/
export function canSlide(state) {
//每次按下都需要检测up事件会重置为true
if (state.needCheck) {
//判断move x和y的距离是否大于判断值因为距离太小无法判断滑动方向
if (Math.abs(state.move.x) > state.judgeValue || Math.abs(state.move.y) > state.judgeValue) {
//放大再相除根据长宽比判断方向angle大于1就是左右滑动小于是上下滑动
let angle = (Math.abs(state.move.x) * 10) / (Math.abs(state.move.y) * 10)
//根据当前slide的类型判断能否滑动并记录下来后续不再判断直接返回记录值
state.next = state.type === SlideType.HORIZONTAL ? angle > 1 : angle <= 1
// console.log('angle', angle, state.next)
state.needCheck = false
} else {
return false
}
}
return state.next
}
/**
* 能否继续滑动
* @param state
* @param isNext 朝向向右或向下
* @returns {boolean}
*/
function canNext(state, isNext) {
return !(
(state.localIndex === 0 && !isNext) ||
(state.localIndex === state.wrapper.childrenLength - 1 && isNext)
)
}
/**
* move事件
* @param e
* @param el
* @param state
* @param canNextCb 是否能继续滑的回调
* @param notNextCb 不能继续滑的回调
* @param slideOtherDirectionCb 滑动其他方向时的回调目前用于图集进于放大模式后上下滑动推出放大模式
*/
export function slidePointerMove(
e,
el,
state,
canNextCb = null,
notNextCb = null,
slideOtherDirectionCb = null
) {
//计算移动距离
state.move.x = e.touches[0].pageX - state.start.x
state.move.y = e.touches[0].pageY - state.start.y
// console.log('move', state.name)
//检测能否滑动
let canSlideRes = canSlide(state)
//是否是往下(右)滑动
let isNext = state.type === SlideType.HORIZONTAL ? state.move.x < 0 : state.move.y < 0
//特别处理竖直的slide组件在第一页往下滑动时向外发送事件
//用于首页顶部导航栏的刷新动画
if (state.type === SlideType.VERTICAL_INFINITE) {
if (canSlideRes && state.localIndex === 0 && !isNext) {
bus.emit(state.name + '-moveY', state.move.y)
}
}
if (canSlideRes) {
//如果传了就用,没传就用默认的
//无限滑动组件要特别判断所以需要传canNextCb
if (!canNextCb) canNextCb = canNext
if (canNextCb(state, isNext)) {
//能滑动,那就把事件捕获,不能给父组件处理
Utils.$stopPropagation(e)
if (state.type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-moveX', state.move.x)
}
//获取偏移量
let t = getSlideOffset(state, el) + (isNext ? state.judgeValue : -state.judgeValue)
let dx1 = 0,
dx2 = 0
//偏移量加当前手指移动的距离就是slide要偏移的值
if (state.type === SlideType.HORIZONTAL) {
dx1 = t + state.move.x
} else {
dx2 = t + state.move.y
}
Utils.$setCss(el, 'transition-duration', `0ms`)
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
} else {
//SlideAlbum.vue组件在用用于捕获事件阻止事件传递给父slide
notNextCb?.()
}
} else {
slideOtherDirectionCb?.(e)
}
}
/**
* 滑动结束事件
* @param e
* @param state
* @param canNextCb
* @param nextCb
* @param notNextCb
* @returns {*}
*/
export function slideTouchEnd(e, state, canNextCb, nextCb, notNextCb) {
let isHorizontal = state.type === SlideType.HORIZONTAL
let isNext = isHorizontal ? state.move.x < 0 : state.move.y < 0
if (state.next) {
//同move事件
if (!canNextCb) canNextCb = canNext
if (canNextCb(state, isNext)) {
//能滑动,那就把事件捕获,不能给父组件处理
Utils.$stopPropagation(e)
//结合时间、距离来判断是否成功滑动
let endTime = Date.now()
let gapTime = endTime - state.start.time
let distance = isHorizontal ? state.move.x : state.move.y
let judgeValue = isHorizontal ? state.wrapper.width : state.wrapper.height
//1、距离太短直接不通过
if (Math.abs(distance) < 20) gapTime = 1000
//2、距离太长直接通过
if (Math.abs(distance) > judgeValue / 3) gapTime = 100
//3、若不在上面那个情况那么只需要判断时间即可
if (gapTime < 150) {
if (isNext) {
state.localIndex++
} else {
state.localIndex--
}
return nextCb?.(isNext)
}
} else {
return notNextCb?.()
}
} else {
notNextCb?.()
}
}
/**
* 结束后重置变量
* @param el
* @param state
* @param emit
*/
export function slideReset(el, state, emit = null) {
Utils.$setCss(el, 'transition-duration', `300ms`)
let t = getSlideOffset(state, el)
let dx1 = 0
let dx2 = 0
if (state.type === SlideType.HORIZONTAL) {
bus.emit(state.name + '-end', state.localIndex)
dx1 = t
} else {
bus.emit(state.name + '-end')
dx2 = t
}
Utils.$setCss(el, 'transform', `translate3d(${dx1}px, ${dx2}px, 0)`)
state.start.x = state.start.y = state.start.time = state.move.x = state.move.y = 0
state.next = false
state.needCheck = true
emit?.('update:index', state.localIndex)
}
//根据当前index获取slide偏移距离
//如果每个页面的宽度是相同均为100%只需要当前index * wrapper的宽度即可 -state.localIndex * state.wrapper.width
export function getSlideOffset(state, el) {
//横竖判断逻辑基本同理
if (state.type === SlideType.HORIZONTAL) {
let widths = []
//获取所有子元素的宽度
Array.from(el.children).map((v) => {
widths.push(v.getBoundingClientRect().width)
})
//取0到当前index的子元素的宽度
widths = widths.slice(0, state.localIndex)
if (widths.length) {
//累计就是当前index之前所有页面的宽度
return -widths.reduce((a, b) => a + b)
}
return 0
// return -state.localIndex * state.wrapper.width
} else {
if (state.type === SlideType.VERTICAL_INFINITE) {
//同上
let heights = []
Array.from(el.children).map((v) => {
heights.push(v.getBoundingClientRect().height)
})
heights = heights.slice(0, state.localIndex)
if (heights.length) return -heights.reduce((a, b) => a + b)
return 0
} else {
//VERTICAL_INFINITE 列表只需要计算index * 高就行
return -state.localIndex * state.wrapper.height
}
}
}