提取通用的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 class="loading" :style="loadingStyle">AA</div>
|
||||
</div>
|
||||
<div class="indicator-me" :class="indicatorFixed?'fixed':''" v-if="showIndicator && indicatorType === 'me'">
|
||||
<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>
|
||||
<slot name="indicator"></slot>
|
||||
<div id="base-slide-list" ref="slideList"
|
||||
:style="{'flex-direction':'row',marginTop:indicatorFixed?'42px':'0'}"
|
||||
@touchstart="touchStart($event)"
|
||||
@ -50,7 +32,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {nextTick} from 'vue'
|
||||
import bus from "../../utils/bus";
|
||||
|
||||
export default {
|
||||
name: "BaseSlideList",
|
||||
@ -155,6 +137,7 @@ export default {
|
||||
await this.checkChildren(true)
|
||||
this.showIndicator && this.initTabs()
|
||||
this.changeIndex(true)
|
||||
console.log(this.$slots.indicator)
|
||||
},
|
||||
methods: {
|
||||
changeIndex(init = false, index = null, e) {
|
||||
@ -218,7 +201,6 @@ export default {
|
||||
//todo 太卡了,后面考虑用原生js来写
|
||||
// this.$attrs['onMove'] && this.$emit('move', {
|
||||
// x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
|
||||
// y: {distance: this.moveYDistance, isDrawDown: this.isDrawDown},
|
||||
// })
|
||||
|
||||
//多重判断,this.isCanDownWiping 这个判断是为了,只能在一个方向上,进行页面更新,比如说,我斜着画,就会出现toolbar又在下移,
|
||||
@ -233,6 +215,10 @@ export default {
|
||||
//禁止在最后页面的时候,向右划
|
||||
if (this.currentSlideItemIndex === this.slideItems.length - 1 && this.isDrawRight) return
|
||||
|
||||
bus.emit('move', {
|
||||
x: {distance: this.moveXDistance, isDrawRight: this.isDrawRight},
|
||||
})
|
||||
|
||||
this.$stopPropagation(e)
|
||||
this.$setCss(this.slideList, 'transform', `translate3d(${-this.getWidth(this.currentSlideItemIndex) +
|
||||
this.moveXDistance +
|
||||
@ -242,14 +228,7 @@ export default {
|
||||
this.moveXDistance / (this.$store.state.bodyWidth / this.indicatorSpace) + 'px')
|
||||
}
|
||||
},
|
||||
getData() {
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 1500)
|
||||
},
|
||||
touchEnd(e) {
|
||||
this.$attrs['onEnd'] && this.$emit('end')
|
||||
if (this.useHomeLoading) {
|
||||
if (this.homeLoadingMoveYDistance > 60) {
|
||||
this.getData()
|
||||
@ -289,6 +268,8 @@ export default {
|
||||
}
|
||||
this.resetConfig()
|
||||
this.$attrs['onUpdate:active-index'] && this.$emit('update:active-index', this.currentSlideItemIndex)
|
||||
this.$attrs['onEnd'] && this.$emit('end')
|
||||
bus.emit('end', this.currentSlideItemIndex)
|
||||
},
|
||||
resetConfig() {
|
||||
this.isCanRightWiping = false
|
||||
@ -296,6 +277,12 @@ export default {
|
||||
this.moveXDistance = 0
|
||||
this.moveYDistance = 0
|
||||
},
|
||||
getData() {
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 1500)
|
||||
},
|
||||
getWidth(index) {
|
||||
return this.slideItemsWidths.reduce((p, c, i) => {
|
||||
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>
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="Me">
|
||||
<SlideRowList style="width: 100vw;"
|
||||
@first="first"
|
||||
@end="end"
|
||||
v-model:active-index="baseActiveIndex"
|
||||
@first="first"
|
||||
@end="end"
|
||||
v-model:active-index="baseActiveIndex"
|
||||
>
|
||||
<SlideItem style="overflow:auto;" :style="contentStyle" @scroll="scroll" @click="click">
|
||||
<div ref="desc" class="desc">
|
||||
@ -58,11 +58,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<div ref="content" style="margin-bottom: 60px;">
|
||||
<Indicator
|
||||
:fixed="indicatorFixed"
|
||||
tabStyleWidth="33%"
|
||||
:tabTexts="['作品','私密','喜欢']"
|
||||
v-model:active-index="contentIndex">
|
||||
</Indicator>
|
||||
<SlideRowList
|
||||
:show-indicator="true"
|
||||
:indicator-fixed="indicatorFixed"
|
||||
indicator-type="me"
|
||||
@end="end"
|
||||
:indicator-fixed="indicatorFixed"
|
||||
v-model:active-index="contentIndex">
|
||||
<SlideItem>
|
||||
<div ref="tab-content1">
|
||||
@ -198,10 +202,11 @@
|
||||
<script>
|
||||
import Posters from '../../components/Posters'
|
||||
import Footer from "../../components/Footer";
|
||||
import Indicator from '../../components/Indicator'
|
||||
|
||||
export default {
|
||||
name: "Me",
|
||||
components: { Posters, Footer},
|
||||
components: {Posters, Footer, Indicator},
|
||||
data() {
|
||||
return {
|
||||
serviceEl: {},
|
||||
@ -459,6 +464,7 @@ export default {
|
||||
}
|
||||
|
||||
ul {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0;
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<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>
|
||||
<Search class="vue"></Search>
|
||||
<People v-for="item in list " :people="item"></People>
|
||||
@ -10,7 +19,6 @@
|
||||
<Search class="vue" @click="findAddressListDialog = true"></Search>
|
||||
</SlideItem>
|
||||
</SlideRowList>
|
||||
|
||||
<div v-if="findAddressListDialog" class="dialog find-address-list">
|
||||
<div class="content">
|
||||
<div class="body">
|
||||
@ -34,16 +42,20 @@
|
||||
<script>
|
||||
import People from './components/People'
|
||||
import Search from '../../components/Search'
|
||||
import Indicator from '../../components/Indicator'
|
||||
|
||||
export default {
|
||||
name: "FindAcquaintance",
|
||||
components: {
|
||||
People,
|
||||
Search
|
||||
Search,
|
||||
Indicator
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
findAddressListDialog: false,
|
||||
indicatorFixed: false,
|
||||
currentSlideItemIndex: 1,
|
||||
list: [
|
||||
{
|
||||
type: 1,
|
||||
@ -60,11 +72,11 @@ export default {
|
||||
{
|
||||
type: 5,
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
mounted() {
|
||||
},
|
||||
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 {
|
||||
z-index: 10;
|
||||
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)
|
||||
},
|
||||
$setCss(el, key, value) {
|
||||
// console.log(value)
|
||||
if (key === 'transform') {
|
||||
//直接设置不生效
|
||||
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