优化me页面

This commit is contained in:
zyronon 2021-08-12 01:18:46 +08:00
parent faa165b07b
commit cb3b44572e
17 changed files with 403 additions and 108 deletions

22
package-lock.json generated
View File

@ -2683,6 +2683,14 @@
"integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
"dev": true
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz",
@ -3707,8 +3715,7 @@
"commander": {
"version": "2.20.3",
"resolved": "https://registry.nlark.com/commander/download/commander-2.20.3.tgz",
"integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=",
"dev": true
"integrity": "sha1-/UhehMA+tIgcIHIrpIA16FMa6zM="
},
"commondir": {
"version": "1.0.1",
@ -5836,8 +5843,7 @@
"follow-redirects": {
"version": "1.14.1",
"resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz",
"integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M=",
"dev": true
"integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M="
},
"for-in": {
"version": "1.0.2",
@ -8060,6 +8066,14 @@
"integrity": "sha1-Hcuei0G7RlJXm8XUyOumFwO7RX8=",
"dev": true
},
"mockjs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mockjs/-/mockjs-1.1.0.tgz",
"integrity": "sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==",
"requires": {
"commander": "*"
}
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz",

View File

@ -8,9 +8,11 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5",
"lodash": "^4.17.21",
"mitt": "^2.1.0",
"mockjs": "^1.1.0",
"pinyin": "^2.9.0",
"swiper": "^6.7.5",
"vue": "^3.0.0",

5
src/api/index.js Normal file
View File

@ -0,0 +1,5 @@
import videos from './videos'
export default {
videos,
}

19
src/api/videos.js Normal file
View File

@ -0,0 +1,19 @@
import request from "../utils/request";
export default {
me(params, data) {
return request({url: '/me', method: 'post', params, data})
},
my(params, data) {
return request({url: '/my', method: 'post', params, data})
},
private(params, data) {
return request({url: '/private', method: 'post', params, data})
},
like(params, data) {
return request({url: '/like', method: 'post', params, data})
},
collect(params, data) {
return request({url: '/collect', method: 'post', params, data})
},
}

View File

@ -1,12 +1,18 @@
<template>
<div class="Loading">
<div class="Loading" :class="isFullScreen?'full':'normal'">
<div class="circle blue"></div>
<div class="circle red"></div>
</div>
</template>
<script>
export default {
name: "Loading"
name: "Loading",
props: {
isFullScreen: {
type: Boolean,
default: true
}
}
}
</script>
@ -14,13 +20,25 @@ export default {
@import "../assets/scss/index";
.Loading {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: space-between;
width: 2.2rem;
&.normal {
width: 100%;
height: 4rem;
display: flex;
justify-content: center;
align-items: center;
}
&.full {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: space-between;
width: 2.2rem;
}
.circle {
width: 1rem;

View File

@ -27,7 +27,7 @@ export default {
if (num < 1000) {
return num
} else {
return num / 10000 + 'w'
return parseInt(num / 10000) + 'w'
}
}
}

View File

@ -204,8 +204,8 @@ export default {
&& 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(res)
let videos = $(`#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()

View File

@ -186,6 +186,8 @@ export default {
this.startTime = Date.now()
},
touchMove(e) {
// this.$stopPropagation(e)
if (!this.canMove) return;
this.moveXDistance = e.touches[0].pageX - this.startLocationX
this.moveYDistance = e.touches[0].pageY - this.startLocationY

3
src/config/index.js Normal file
View File

@ -0,0 +1,3 @@
export default {
baseUrl: 'http://test.test.com'
}

View File

@ -1,45 +1,17 @@
import * as Vue from 'vue'
import App from './App.vue'
import mitt from 'mitt'
import './assets/scss/index.scss'
import BaseHeader from "./components/BaseHeader.vue"
import SlideList from "./components/slide/SlideList";
import SlideItem from "./components/slide/SlideItem";
import Video from "./components/Video";
import Footer from "./components/Footer";
import './mock'// 导入 mock 数据处理
import api from './api'
import router from "./router";
import store from "./store";
import globalMethods from './utils/global-methods'
import SlideRowList from "./components/slide/SlideRowList";
import SlideColumnList from "./components/slide/SlideColumnList";
import Mask from "./components/Mask";
import NoMore from "./components/NoMore";
import Indicator from "./components/Indicator";
import Back from "./components/Back";
import mixin from "./utils/mixin";
const mixin = {
methods: {
...globalMethods
}
}
const app = Vue.createApp(App)
app.config.globalProperties.$api = {...api}
app.provide('mitt', mitt())
app.component('BaseHeader', BaseHeader)
app.component('SlideList', SlideList)
app.component('SlideRowList', SlideRowList)
app.component('SlideColumnList', SlideColumnList)
app.component('SlideItem', SlideItem)
app.component('Indicator', Indicator)
app.component('Video1', Video)
app.component('Footer', Footer)
app.component('Mask', Mask)
app.component('NoMore', NoMore)
app.component('back', Back)
app.mixin(mixin)
app.use(router)
app.use(store)

74
src/mock/index.js Normal file
View File

@ -0,0 +1,74 @@
import Mock from 'mockjs'
Mock.setup({
timeout: '500-1000'
})
Mock.Random.extend({
imgs: function (date) {
return this.pick([
require('../assets/img/poster/1.jpg'),
require('../assets/img/poster/2.jpg'),
require('../assets/img/poster/3.jpg'),
require('../assets/img/poster/4.jpg'),
require('../assets/img/poster/5.jpg'),
require('../assets/img/poster/6.jpg'),
require('../assets/img/poster/7.jpg'),
require('../assets/img/poster/8.jpg'),
require('../assets/img/poster/9.jpg'),
require('../assets/img/poster/10.jpg'),
require('../assets/img/poster/11.jpg'),
])
}
})
!(function me() {
let my = {total: Mock.Random.natural(1, 20)}
my[`list|${my.total > 10 ? 10 : my.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
let private1 = {total: Mock.Random.natural(1, 20)}
private1[`list|${private1.total > 10 ? 10 : private1.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
let like = {total: Mock.Random.natural(1, 20)}
like[`list|${like.total > 10 ? 10 : like.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
let collect = {total: Mock.Random.natural(1, 20)}
collect[`list|${collect.total > 10 ? 10 : collect.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
const data = Mock.mock({
'data': {
my,
private: private1,
like,
collect
},
code: 200,
msg: '',
})
Mock.mock('me', data)
}())
let pageSize = 15
!(function my() {
// let data = {total: Mock.Random.natural(1, 20)}
// data[`list|${data.total > pageSize ? pageSize : data.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
let data = {total: 8}
data[`list|${data.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
Mock.mock(/my/, Mock.mock({data, code: 200, msg: '',}))
}())
!(function private1() {
let data = {total: Mock.Random.natural(1, 20)}
data[`list|${data.total > pageSize ? pageSize : data.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
Mock.mock(/private/, Mock.mock({data, code: 200, msg: '',}))
}())
!(function like() {
let data = {total: Mock.Random.natural(1, 20)}
data[`list|${data.total > pageSize ? pageSize : data.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
Mock.mock(/like/, Mock.mock({data, code: 200, msg: '',}))
}())
!(function collect() {
let data = {total: Mock.Random.natural(1, 20)}
data[`list|${data.total > pageSize ? pageSize : data.total}`] = [{'like|10000-990000': 1000000, src: '@imgs'}]
Mock.mock(/collect/, Mock.mock({data, code: 200, msg: '',}))
}())

View File

@ -65,50 +65,47 @@
</div>
</div>
<Indicator
:class="indicatorFixed?'fffffffff':''"
name="videoList"
tabStyleWidth="25%"
:tabTexts="['作品','私密','喜欢','收藏']"
v-model:active-index="contentIndex">
</Indicator>
<SlideRowList
ref="videoSlideRowList"
name="videoList"
style="height: calc(100vh - 13.5rem);"
:style="videoSlideRowListStyle"
v-model:active-index="contentIndex">
<SlideItem class="SlideItem"
@touchmove="move"
:style="isScroll?'overflow: auto;':''">
<Posters :list="res.my.list"></Posters>
<div class="no-more">暂时没有更多了</div>
<Posters v-if="videos.my.total !== -1" :list="videos.my.list"></Posters>
<Loading v-else :is-full-screen="false"></Loading>
<no-more/>
</SlideItem>
<SlideItem class="SlideItem"
@touchmove="move"
:style="isScroll?'overflow: auto;':''">
<Posters :list="res.private.list"></Posters>
<div class="no-more">暂时没有更多了</div>
<Posters v-if="videos.private.total !== -1" :list="videos.private.list"></Posters>
<Loading v-else :is-full-screen="false"></Loading>
<no-more/>
</SlideItem>
<SlideItem class="SlideItem"
@touchmove="move"
:style="isScroll?'overflow: auto;':''">
<Posters :list="res.like.list"></Posters>
<div class="no-more">暂时没有更多了</div>
<Posters v-if="videos.like.total !== -1" :list="videos.like.list"></Posters>
<Loading v-else :is-full-screen="false"></Loading>
<no-more/>
</SlideItem>
<SlideItem class="SlideItem"
@touchmove="move"
:style="isScroll?'overflow: auto;':''">
<Posters :list="res.collect.list"></Posters>
<div class="no-more">暂时没有更多了</div>
<Posters v-if="videos.collect.total !== -1" :list="videos.collect.list"></Posters>
<Loading v-else :is-full-screen="false"></Loading>
<no-more/>
</SlideItem>
</SlideRowList>
</div>
<!-- <Indicator-->
<!-- style="margin-top: 4.6rem;"-->
<!-- v-if="indicatorFixed"-->
<!-- name="videoList"-->
<!-- :fixed="true"-->
<!-- tabStyleWidth="25%"-->
<!-- :tabTexts="['作品','私密','喜欢','收藏']"-->
<!-- v-model:active-index="contentIndex">-->
<!-- </Indicator>-->
<Footer v-bind:init-tab="5"/>
</SlideItem>
<SlideItem style="min-width: 70vw; overflow:auto;">
@ -238,79 +235,96 @@ export default {
header: null,
headerHeight: 0,
descHeight: 0,
videoSlideRowListHeight: 0,
defaultVideoSlideRowListHeight: 0
},
videoItemHeight: 0,
startLocationY: 0,
fixedLocationY: 0,
moveYDistance: 0,
startTime: 0,
floatHeight: 46,
res: {
videos: {
my: {
list: [],
total: 0
total: -1
},
private: {
list: [],
total: 0
total: -1
},
like: {
list: [],
total: 0
total: -1
},
collect: {
list: [],
total: 0
total: -1
},
}
},
}
},
computed: {
bodyHeight() {
return this.$store.state.bodyHeight
},
bodyWidth() {
return this.$store.state.bodyWidth
},
videoSlideRowListStyle() {
return {height: this.refs.videoSlideRowListHeight !== 0 ? this.refs.videoSlideRowListHeight + 'px' : 'calc(100vh - 14.6rem)'}
}
},
watch: {
contentIndex(newVal, oldVal) {
this.changeIndex(newVal, oldVal)
},
},
mounted() {
setTimeout(() => {
this.refs.header = this.$refs.header
this.refs.headerHeight = this.$refs.header.offsetHeight
this.refs.descHeight = this.$refs.desc.offsetHeight
this.refs.defaultVideoSlideRowListHeight = this.$refs.videoSlideRowList.wrapperHeight
// this.refs.videoSlideRowListHeight = this.$refs.videoSlideRowList.wrapperHeight
this.changeIndex(0, null)
})
this.getData()
this.videoItemHeight = this.bodyWidth / 3 * 1.2 + 2
},
methods: {
getData() {
this.res.my.total = this.$randomNum(15, 30)
for (let i = 0; i < this.res.my.total; i++) {
this.res.my.list.push({
src: require(`../../assets/img/poster/${this.$randomNum(11)}.jpg`),
like: this.$randomNum(99) * 10000
})
}
this.res.private.total = this.$randomNum(10)
for (let i = 0; i < this.res.private.total; i++) {
this.res.private.list.push({
src: require(`../../assets/img/poster/${this.$randomNum(11)}.jpg`),
like: this.$randomNum(99) * 10000
})
}
this.res.like.total = this.$randomNum(15, 100)
for (let i = 0; i < this.res.like.total; i++) {
this.res.like.list.push({
src: require(`../../assets/img/poster/${this.$randomNum(11)}.jpg`),
like: this.$randomNum(99) * 10000
})
}
this.res.collect.total = this.$randomNum(5)
for (let i = 0; i < this.res.collect.total; i++) {
this.res.collect.list.push({
src: require(`../../assets/img/poster/${this.$randomNum(11)}.jpg`),
like: this.$randomNum(99) * 10000
})
}
},
changeIndex() {
async changeIndex(newVal, oldVal) {
let res
if (this.videos[Object.keys(this.videos)[newVal]].total !== -1) return
switch (newVal) {
case 0:
res = await this.$api.videos.my()
if (res.code === this.SUCCESS_CODE) this.videos.my = res.data
this.$console(this.videos)
let posterHeight = Math.ceil(this.videos.my.total / 3) * this.videoItemHeight
if (posterHeight < this.refs.defaultVideoSlideRowListHeight) {
// this.$setCss(this.$refs.videoSlideRowList, 'height', posterHeight + 'px')
this.refs.videoSlideRowListHeight = posterHeight + 60
} else {
this.refs.videoSlideRowListHeight = this.refs.defaultVideoSlideRowListHeight
}
break
case 1:
res = await this.$api.videos.private()
if (res.code === this.SUCCESS_CODE) this.videos.private = res.data
this.$console(this.videos)
break
case 2:
res = await this.$api.videos.like()
if (res.code === this.SUCCESS_CODE) this.videos.like = res.data
this.$console(this.videos)
break
case 3:
res = await this.$api.videos.collect()
if (res.code === this.SUCCESS_CODE) this.videos.collect = res.data
this.$console(this.videos)
break
}
},
touchStart(e) {
this.$refs.scroll.style.transition = 'none'
@ -367,7 +381,18 @@ export default {
}
// console.log('indicatorFixed', this.indicatorFixed)
// console.log('distance', distance)
this.$refs.scroll.style.transform = `translate3d(0,${distance}px,0)`
// if (this.indicatorFixed){
// this.$refs.scroll.style.transform = `translate3d(0,${this.indicatorFixed ? -offsetTop : distance}px,0)`
// }
//todo
if (this.refs.defaultVideoSlideRowListHeight > this.refs.videoSlideRowListHeight) {
let endTransformY = Math.abs(offsetTop) - (this.refs.defaultVideoSlideRowListHeight - this.refs.videoSlideRowListHeight)
this.$refs.scroll.style.transform = `translate3d(0,${
distance > -endTransformY ? distance : -endTransformY
}px,0)`
} else {
this.$refs.scroll.style.transform = `translate3d(0,${this.indicatorFixed ? -offsetTop : distance}px,0)`
}
}
},
touchEnd(e) {
@ -388,7 +413,7 @@ export default {
return
}
console.log('header-height', this.refs.descHeight - this.floatHeight)
// console.log('header-height', this.refs.descHeight - this.floatHeight)
// this.isScroll = Math.abs(this.moveYDistance) > this.refs.descHeight - this.floatHeight
//
//
@ -459,9 +484,10 @@ export default {
this.indicatorFixed = this.floatShowName = this.floatFixed = this.isScroll = true
}
}
} else {
this.isScroll = true
}
// console.log('end-isScroll', this.isScroll)
},
getTransform(el) {
let transform = el.style.transform

View File

@ -212,7 +212,7 @@ export default {
},
computed: {
selectFriends() {
let res = this.friends.filter(v => v.select)
let videos = this.friends.filter(v => v.select)
return res.length
}
},

13
src/utils/const_var.js Normal file
View File

@ -0,0 +1,13 @@
export default {
REDIRECT: 'redirect',
// 请求方法
POST: 'post',
GET: 'get',
PATCH: 'patch',
DELETE: 'delete',
PUT: 'put',
PAGE_NUMBER: 1,
PAGE_SIZE: 10,
DELAY_TIME: 250,
SUCCESS: 200,
}

View File

@ -149,6 +149,7 @@ export default {
return JSON.parse(JSON.stringify(v))
},
$console(v) {
return
return console.log(JSON.stringify(v, null, 4))
},
$randomNum(minNum,maxNum){

38
src/utils/mixin.js Normal file
View File

@ -0,0 +1,38 @@
import globalMethods from "./global-methods";
import BaseHeader from "../components/BaseHeader";
import SlideList from "../components/slide/SlideList";
import SlideRowList from "../components/slide/SlideRowList";
import SlideColumnList from "../components/slide/SlideColumnList";
import SlideItem from "../components/slide/SlideItem";
import Indicator from "../components/Indicator";
import Video from "../components/Video";
import Footer from "../components/Footer";
import Mask from "../components/Mask";
import NoMore from "../components/NoMore";
import Back from "../components/Back";
import Loading from "../components/Loading";
export default {
components: {
BaseHeader,
SlideList,
SlideRowList,
SlideColumnList,
SlideItem,
Indicator,
'Video1':Video,
Footer,
Mask,
NoMore,
Back,
Loading
},
data() {
return {
SUCCESS_CODE: 200
}
},
methods: {
...globalMethods
}
}

108
src/utils/request.js Normal file
View File

@ -0,0 +1,108 @@
import axios from 'axios'
import config from '@/config'
import store from '../store'
import globalMethods from './global-methods'
//这里必须使用axios实例因为已经有一个没有创建实例而直接使用的axio了
// 在request.js这里如果直接使用axios的话request.js里面的拦截器也会执行
//创建一个实例再去使用这个实例请求request.js里面的axios配置就不会生效
const instance = axios.create({
baseURL: config.baseUrl,
timeout: 60000,
withCredentials: true
})
// request拦截器
instance.interceptors.request.use((config) => {
// 如果没有设置Content-Type默认application/json
if (!config.headers['Content-Type']) {
config.headers['Content-Type'] = 'application/json'
}
return config
}, error => {
return Promise.reject(error)
})
/*
* 响应拦截器目前的处理是无论失败或者成功都会返回{ code: xxx, data: xxx }这种类型的数据没有reject和抛error
* 如果有问题拦截器里会进行提示然后返回{ code: Xxx, data:xxx }这种数据在then里面总是会接收到
* */
instance.interceptors.response.use(
response => {
// console.log('response',response)
/*
* 响应成功的拦截器主要是对data作处理如果没有返回data那么会添加一个data字段并把response.data的内容合并到data里面然后返回
* */
let {data} = response
// console.log(response)
if (data === undefined || data === null || data === '') {
globalMethods.$notice('请求失败,请稍后重试!')
return {code: 500, data: []}
} else if (typeof data === 'string') {
return {code: 200, data}
} else {
if (data.data === undefined || data.data === null) {
data.data = {...data}
}
let resCode = data.code
if (resCode) {
try {
resCode = Number(resCode)
} catch (e) {
data.code = resCode = 500
}
if (resCode === 0) {
data.code = resCode = 200
}
if (resCode !== 200) {
globalMethods.$notice(response.data.message || '请求失败,请稍后重试!')
}
} else {
data.code = 200
}
return data
}
},
error => {
// console.log('error', error)
// console.log(error.response)
// console.log(error.response.status)
if (error.response === undefined) {
globalMethods.$notice('服务器响应超时')
return {code: 500, msg: '服务器响应超时', data: []}
}
if (error.response.status >= 500) {
globalMethods.$notice('服务器出现错误')
return {code: 500, msg: '服务器出现错误', data: []}
}
if (error.response.status === 404) {
globalMethods.$notice('接口不存在')
return {code: 404, msg: '接口不存在', data: []}
}
if (error.response.status === 400) {
globalMethods.$notice('接口报错')
return {code: 400, msg: '接口报错', data: []}
}
if (error.response.status === 401) {
return {code: 401, msg: '用户名或密码不正确', data: []}
} else {
let {data} = error.response
if (data === null || data === undefined) {
globalMethods.$notice('请求失败,请稍后重试!')
return {code: 200, data: []}
} else {
let resCode = data.code
if (data.data === undefined || data.data === null) {
data.data = {...data}
}
if (resCode && typeof resCode == 'number' && resCode !== 200) {
globalMethods.$notice('请求失败,请稍后重试!')
} else {
data.code = 200
}
return data
}
}
})
export default instance