提取通用的indicator成为组件
This commit is contained in:
parent
218cca80a1
commit
bd2ff39713
137
src/components/Indicator.vue
Normal file
137
src/components/Indicator.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<div class="indicator-ctn" :class="fixed?'fixed':''">
|
||||||
|
<div class="tabs" ref="tabs">
|
||||||
|
<div class="tab"
|
||||||
|
:style="{width : tabStyleWidth}"
|
||||||
|
v-for="(item,index) in tabTexts"
|
||||||
|
:class="currentSlideItemIndex === index?'active':''"
|
||||||
|
@click="changeIndex(index)">
|
||||||
|
<span>{{ item }}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="indicator"
|
||||||
|
ref="indicator"
|
||||||
|
:style="{width : tabStyleWidth}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import bus from "../utils/bus";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Indicator",
|
||||||
|
props: {
|
||||||
|
fixed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false
|
||||||
|
},
|
||||||
|
activeIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: () => 0
|
||||||
|
},
|
||||||
|
tabStyleWidth: {
|
||||||
|
type: String,
|
||||||
|
default: () => '50%'
|
||||||
|
},
|
||||||
|
tabTexts: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
indicatorFixed: false,
|
||||||
|
currentSlideItemIndex: this.activeIndex,
|
||||||
|
tabIndicatorRelationActiveIndexLefts: [],//指标和slideItem的index的对应left,
|
||||||
|
indicatorSpace: 0,//indicator之间的间距
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {},
|
||||||
|
mounted() {
|
||||||
|
this.initTabs()
|
||||||
|
bus.on('move', this.move)
|
||||||
|
bus.on('end', this.end)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
changeIndex(index) {
|
||||||
|
this.currentSlideItemIndex = index
|
||||||
|
this.$attrs['onUpdate:active-index'] && this.$emit('update:active-index', this.currentSlideItemIndex)
|
||||||
|
this.$setCss(this.indicatorRef, 'transition-duration', `300ms`)
|
||||||
|
this.$setCss(this.indicatorRef, 'left', this.tabIndicatorRelationActiveIndexLefts[this.currentSlideItemIndex] + 'px')
|
||||||
|
},
|
||||||
|
initTabs() {
|
||||||
|
let tabs = this.$refs.tabs
|
||||||
|
this.indicatorRef = this.$refs.indicator
|
||||||
|
for (let i = 0; i < tabs.children.length; i++) {
|
||||||
|
let item = tabs.children[i]
|
||||||
|
this.tabWidth = this.$getCss(item, 'width')
|
||||||
|
this.tabIndicatorRelationActiveIndexLefts.push(
|
||||||
|
item.getBoundingClientRect().x - tabs.children[0].getBoundingClientRect().x + (this.indicatorType === 'home' ? this.tabWidth * 0.15 : 0))
|
||||||
|
}
|
||||||
|
this.indicatorSpace = this.tabIndicatorRelationActiveIndexLefts[1] - this.tabIndicatorRelationActiveIndexLefts[0]
|
||||||
|
this.$setCss(this.indicatorRef, 'transition-duration', `0ms`)
|
||||||
|
this.$setCss(this.indicatorRef, 'left', this.tabIndicatorRelationActiveIndexLefts[this.currentSlideItemIndex] + 'px')
|
||||||
|
},
|
||||||
|
move(e) {
|
||||||
|
this.$setCss(this.indicatorRef, 'left',
|
||||||
|
this.tabIndicatorRelationActiveIndexLefts[this.currentSlideItemIndex] -
|
||||||
|
e.x.distance / (this.$store.state.bodyWidth / this.indicatorSpace) + 'px')
|
||||||
|
},
|
||||||
|
end(index) {
|
||||||
|
console.log(index)
|
||||||
|
this.currentSlideItemIndex = index
|
||||||
|
this.$setCss(this.indicatorRef, 'transition-duration', `300ms`)
|
||||||
|
this.$setCss(this.indicatorRef, 'left',
|
||||||
|
this.tabIndicatorRelationActiveIndexLefts[this.currentSlideItemIndex] + 'px')
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$setCss(this.indicatorRef, 'transition-duration', `0ms`)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../assets/scss/index";
|
||||||
|
|
||||||
|
.indicator-ctn {
|
||||||
|
width: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
background: $main-bg;
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
height: 40px;
|
||||||
|
width: 45%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: gray;
|
||||||
|
transition: color .3s;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
height: 2px;
|
||||||
|
background: gold;
|
||||||
|
width: 45%;
|
||||||
|
position: relative;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-ctn.fixed {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -20,25 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="loading" :style="loadingStyle">AA</div>
|
<div class="loading" :style="loadingStyle">AA</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="indicator-me" :class="indicatorFixed?'fixed':''" v-if="showIndicator && indicatorType === 'me'">
|
<slot name="indicator"></slot>
|
||||||
<div class="tabs" ref="tabs">
|
|
||||||
<div class="tab"
|
|
||||||
:class="currentSlideItemIndex === 0?'active':''"
|
|
||||||
@click="changeIndex(false,0)">
|
|
||||||
<span>作品</span></div>
|
|
||||||
<div class="tab"
|
|
||||||
:class="currentSlideItemIndex === 1?'active':''"
|
|
||||||
@click.stop="changeIndex(false,1)">
|
|
||||||
<span>私密</span>
|
|
||||||
</div>
|
|
||||||
<div class="tab"
|
|
||||||
:class="currentSlideItemIndex === 2?'active':''"
|
|
||||||
@click="changeIndex(false,2,$event)">
|
|
||||||
<span>喜欢</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="indicator" ref="indicator"></div>
|
|
||||||
</div>
|
|
||||||
<div id="base-slide-list" ref="slideList"
|
<div id="base-slide-list" ref="slideList"
|
||||||
:style="{'flex-direction':'row',marginTop:indicatorFixed?'42px':'0'}"
|
:style="{'flex-direction':'row',marginTop:indicatorFixed?'42px':'0'}"
|
||||||
@touchstart="touchStart($event)"
|
@touchstart="touchStart($event)"
|
||||||
@ -50,7 +32,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {nextTick} from 'vue'
|
import bus from "../../utils/bus";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "BaseSlideList",
|
name: "BaseSlideList",
|
||||||
@ -155,6 +137,7 @@ export default {
|
|||||||
await this.checkChildren(true)
|
await this.checkChildren(true)
|
||||||
this.showIndicator && this.initTabs()
|
this.showIndicator && this.initTabs()
|
||||||
this.changeIndex(true)
|
this.changeIndex(true)
|
||||||
|
console.log(this.$slots.indicator)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changeIndex(init = false, index = null, e) {
|
changeIndex(init = false, index = null, e) {
|
||||||
@ -218,7 +201,6 @@ export default {
|
|||||||
//todo 太卡了,后面考虑用原生js来写
|
//todo 太卡了,后面考虑用原生js来写
|
||||||
// this.$attrs['onMove'] && this.$emit('move', {
|
// this.$attrs['onMove'] && this.$emit('move', {
|
||||||
// x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
|
// x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
|
||||||
// y: {distance: this.moveYDistance, isDrawDown: this.isDrawDown},
|
|
||||||
// })
|
// })
|
||||||
|
|
||||||
//多重判断,this.isCanDownWiping 这个判断是为了,只能在一个方向上,进行页面更新,比如说,我斜着画,就会出现toolbar又在下移,
|
//多重判断,this.isCanDownWiping 这个判断是为了,只能在一个方向上,进行页面更新,比如说,我斜着画,就会出现toolbar又在下移,
|
||||||
@ -233,6 +215,10 @@ export default {
|
|||||||
//禁止在最后页面的时候,向右划
|
//禁止在最后页面的时候,向右划
|
||||||
if (this.currentSlideItemIndex === this.slideItems.length - 1 && this.isDrawRight) return
|
if (this.currentSlideItemIndex === this.slideItems.length - 1 && this.isDrawRight) return
|
||||||
|
|
||||||
|
bus.emit('move', {
|
||||||
|
x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
|
||||||
|
})
|
||||||
|
|
||||||
this.$stopPropagation(e)
|
this.$stopPropagation(e)
|
||||||
this.$setCss(this.slideList, 'transform', `translate3d(${-this.getWidth(this.currentSlideItemIndex) +
|
this.$setCss(this.slideList, 'transform', `translate3d(${-this.getWidth(this.currentSlideItemIndex) +
|
||||||
this.moveXDistance +
|
this.moveXDistance +
|
||||||
@ -242,14 +228,7 @@ export default {
|
|||||||
this.moveXDistance / (this.$store.state.bodyWidth / this.indicatorSpace) + 'px')
|
this.moveXDistance / (this.$store.state.bodyWidth / this.indicatorSpace) + 'px')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getData() {
|
|
||||||
this.loading = true
|
|
||||||
setTimeout(() => {
|
|
||||||
this.loading = false
|
|
||||||
}, 1500)
|
|
||||||
},
|
|
||||||
touchEnd(e) {
|
touchEnd(e) {
|
||||||
this.$attrs['onEnd'] && this.$emit('end')
|
|
||||||
if (this.useHomeLoading) {
|
if (this.useHomeLoading) {
|
||||||
if (this.homeLoadingMoveYDistance > 60) {
|
if (this.homeLoadingMoveYDistance > 60) {
|
||||||
this.getData()
|
this.getData()
|
||||||
@ -289,6 +268,8 @@ export default {
|
|||||||
}
|
}
|
||||||
this.resetConfig()
|
this.resetConfig()
|
||||||
this.$attrs['onUpdate:active-index'] && this.$emit('update:active-index', this.currentSlideItemIndex)
|
this.$attrs['onUpdate:active-index'] && this.$emit('update:active-index', this.currentSlideItemIndex)
|
||||||
|
this.$attrs['onEnd'] && this.$emit('end')
|
||||||
|
bus.emit('end', this.currentSlideItemIndex)
|
||||||
},
|
},
|
||||||
resetConfig() {
|
resetConfig() {
|
||||||
this.isCanRightWiping = false
|
this.isCanRightWiping = false
|
||||||
@ -296,6 +277,12 @@ export default {
|
|||||||
this.moveXDistance = 0
|
this.moveXDistance = 0
|
||||||
this.moveYDistance = 0
|
this.moveYDistance = 0
|
||||||
},
|
},
|
||||||
|
getData() {
|
||||||
|
this.loading = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loading = false
|
||||||
|
}, 1500)
|
||||||
|
},
|
||||||
getWidth(index) {
|
getWidth(index) {
|
||||||
return this.slideItemsWidths.reduce((p, c, i) => {
|
return this.slideItemsWidths.reduce((p, c, i) => {
|
||||||
if (i < index) {
|
if (i < index) {
|
||||||
@ -417,47 +404,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator-me {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 999;
|
|
||||||
background: $main-bg;
|
|
||||||
|
|
||||||
.tabs {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
.tab {
|
|
||||||
height: 40px;
|
|
||||||
width: 33%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
color: gray;
|
|
||||||
transition: color .3s;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator {
|
|
||||||
height: 2px;
|
|
||||||
background: gold;
|
|
||||||
width: 33%;
|
|
||||||
position: relative;
|
|
||||||
transition: all .3s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator-me.fixed {
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="Me">
|
<div class="Me">
|
||||||
<SlideRowList style="width: 100vw;"
|
<SlideRowList style="width: 100vw;"
|
||||||
@first="first"
|
@first="first"
|
||||||
@end="end"
|
@end="end"
|
||||||
v-model:active-index="baseActiveIndex"
|
v-model:active-index="baseActiveIndex"
|
||||||
>
|
>
|
||||||
<SlideItem style="overflow:auto;" :style="contentStyle" @scroll="scroll" @click="click">
|
<SlideItem style="overflow:auto;" :style="contentStyle" @scroll="scroll" @click="click">
|
||||||
<div ref="desc" class="desc">
|
<div ref="desc" class="desc">
|
||||||
@ -58,11 +58,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="content" style="margin-bottom: 60px;">
|
<div ref="content" style="margin-bottom: 60px;">
|
||||||
|
<Indicator
|
||||||
|
:fixed="indicatorFixed"
|
||||||
|
tabStyleWidth="33%"
|
||||||
|
:tabTexts="['作品','私密','喜欢']"
|
||||||
|
v-model:active-index="contentIndex">
|
||||||
|
</Indicator>
|
||||||
<SlideRowList
|
<SlideRowList
|
||||||
:show-indicator="true"
|
|
||||||
:indicator-fixed="indicatorFixed"
|
|
||||||
indicator-type="me"
|
|
||||||
@end="end"
|
@end="end"
|
||||||
|
:indicator-fixed="indicatorFixed"
|
||||||
v-model:active-index="contentIndex">
|
v-model:active-index="contentIndex">
|
||||||
<SlideItem>
|
<SlideItem>
|
||||||
<div ref="tab-content1">
|
<div ref="tab-content1">
|
||||||
@ -198,10 +202,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import Posters from '../../components/Posters'
|
import Posters from '../../components/Posters'
|
||||||
import Footer from "../../components/Footer";
|
import Footer from "../../components/Footer";
|
||||||
|
import Indicator from '../../components/Indicator'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Me",
|
name: "Me",
|
||||||
components: { Posters, Footer},
|
components: {Posters, Footer, Indicator},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
serviceEl: {},
|
serviceEl: {},
|
||||||
@ -459,6 +464,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@ -1,6 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="FindAcquaintance">
|
<div class="FindAcquaintance">
|
||||||
<SlideRowList>
|
<div class="header">
|
||||||
|
<img src="../../assets/img/icon/back.png" alt="" class="back">
|
||||||
|
<Indicator
|
||||||
|
tabStyleWidth="40%"
|
||||||
|
:tabTexts="['熟人列表','发现熟人']"
|
||||||
|
v-model:active-index="currentSlideItemIndex">
|
||||||
|
</Indicator>
|
||||||
|
<img src="../../assets/img/icon/back.png" alt="" class="option">
|
||||||
|
</div>
|
||||||
|
<SlideRowList v-model:active-index="currentSlideItemIndex">
|
||||||
<SlideItem>
|
<SlideItem>
|
||||||
<Search class="vue"></Search>
|
<Search class="vue"></Search>
|
||||||
<People v-for="item in list " :people="item"></People>
|
<People v-for="item in list " :people="item"></People>
|
||||||
@ -10,7 +19,6 @@
|
|||||||
<Search class="vue" @click="findAddressListDialog = true"></Search>
|
<Search class="vue" @click="findAddressListDialog = true"></Search>
|
||||||
</SlideItem>
|
</SlideItem>
|
||||||
</SlideRowList>
|
</SlideRowList>
|
||||||
|
|
||||||
<div v-if="findAddressListDialog" class="dialog find-address-list">
|
<div v-if="findAddressListDialog" class="dialog find-address-list">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="body">
|
<div class="body">
|
||||||
@ -34,16 +42,20 @@
|
|||||||
<script>
|
<script>
|
||||||
import People from './components/People'
|
import People from './components/People'
|
||||||
import Search from '../../components/Search'
|
import Search from '../../components/Search'
|
||||||
|
import Indicator from '../../components/Indicator'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "FindAcquaintance",
|
name: "FindAcquaintance",
|
||||||
components: {
|
components: {
|
||||||
People,
|
People,
|
||||||
Search
|
Search,
|
||||||
|
Indicator
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
findAddressListDialog: false,
|
findAddressListDialog: false,
|
||||||
|
indicatorFixed: false,
|
||||||
|
currentSlideItemIndex: 1,
|
||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
type: 1,
|
type: 1,
|
||||||
@ -60,11 +72,11 @@ export default {
|
|||||||
{
|
{
|
||||||
type: 5,
|
type: 5,
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
created() {
|
mounted() {
|
||||||
},
|
},
|
||||||
methods: {}
|
methods: {}
|
||||||
}
|
}
|
||||||
@ -85,6 +97,49 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-ctn {
|
||||||
|
width: 50%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
background: $main-bg;
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
height: 40px;
|
||||||
|
width: 45%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: gray;
|
||||||
|
transition: color .3s;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
height: 2px;
|
||||||
|
background: gold;
|
||||||
|
width: 45%;
|
||||||
|
position: relative;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.dialog {
|
.dialog {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
18
src/utils/bus.js
Normal file
18
src/utils/bus.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export default {
|
||||||
|
eventMap: new Map(),
|
||||||
|
on(eventType, cb) {
|
||||||
|
let cbs = this.eventMap.get(eventType)
|
||||||
|
if (cbs) {
|
||||||
|
cbs.push(cb)
|
||||||
|
} else {
|
||||||
|
cbs = [cb]
|
||||||
|
}
|
||||||
|
this.eventMap.set(eventType, cbs)
|
||||||
|
},
|
||||||
|
emit(eventType, val) {
|
||||||
|
let cbs = this.eventMap.get(eventType)
|
||||||
|
if (cbs) {
|
||||||
|
cbs.map(cb => cb(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -103,6 +103,7 @@ export default {
|
|||||||
return parseFloat(val)
|
return parseFloat(val)
|
||||||
},
|
},
|
||||||
$setCss(el, key, value) {
|
$setCss(el, key, value) {
|
||||||
|
// console.log(value)
|
||||||
if (key === 'transform') {
|
if (key === 'transform') {
|
||||||
//直接设置不生效
|
//直接设置不生效
|
||||||
el.style.webkitTransform = el.style.MsTransform = el.style.msTransform = el.style.MozTransform = el.style.OTransform = el.style.transform = value;
|
el.style.webkitTransform = el.style.MsTransform = el.style.msTransform = el.style.MozTransform = el.style.OTransform = el.style.transform = value;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user