Skip to content

Commit

Permalink
feat: 完善pi-tab导航组件
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzhenfei committed Sep 3, 2020
1 parent eb9874f commit e7cc5c9
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 16 deletions.
19 changes: 7 additions & 12 deletions components/pi-select/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,7 @@
:mask-background="maskBackground"
@close="handlePopupClose"
>
<view
class="pi-select"
:style="[
customStyle,
{
height: $pi.common.addUnit(height)
}
]"
:class="[customClass]"
>
<view class="pi-select" :style="[customStyle, { getHeight }]" :class="[customClass]">
<!-- 标题栏 -->
<view
v-if="showTitle"
Expand All @@ -47,9 +38,9 @@
<!-- 选择区域 -->
<scroll-view class="pi-scroll" scroll-y scroll-with-animation>
<view
v-for="(item, index) in getItems"
v-for="item in getItems"
:id="`id-${item[keyField]}`"
:key="index"
:key="item[keyField]"
:style="[itemStyle, getItemStyle]"
:class="{ 'pi-solid-bottom-1': showItemBottomBorder }"
class="pi-justify-between pi-align-center pi-fz-30 pi-pd-lr-32"
Expand Down Expand Up @@ -271,6 +262,9 @@ export default {
.join('-')
return options
},
getHeight() {
return this.$pi.common.addUnit(this.height)
},
getTitlePadding() {
return this.$pi.common.addUnit(this.titlePadding)
},
Expand All @@ -295,6 +289,7 @@ export default {
}
},
watch: {
// ! 因为使用对象,在H5端watch的时候,就算没有发生改变,也会触发,这里直接监听toString后的值
options(val) {
this.init()
}
Expand Down
294 changes: 294 additions & 0 deletions components/pi-tabs/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
<template>
<view class="pi-tabs">
<!-- 选择区域 -->
<scroll-view class="pi-scroll" :scroll-left="scrollLeft" scroll-x scroll-with-animation>
<view class="scroll-wrap" :style="[scrollWrapStyle]">
<view
v-for="item in items"
:id="`id-${item[keyField]}`"
:key="item[keyField]"
:style="[getItemStyle, itemStyle]"
class="pi-tab pi-align-center pi-fz-30"
@tap="handleSelectItem(item)"
>
<!-- slot slot-scoped只支持app,h5,微信小程序平台 -->
<!-- <template slot="item" slot-scope="{ item }">{{ item.tag }}</template> -->
<slot name="item" :item="item">
{{ item[displayField] }}
</slot>
</view>
<view
class="slider-bar-guide"
:style="[{ 'background-color': showSliderBarGuide ? '#e4e7ed' : 'unset' }]"
>
<view :style="[getSliderBarStyle]" class="slider-bar" />
</view>
</view>
</scroll-view>
</view>
</template>

<script>
import ValueSync from '../../mixin/value-sync'
import { getConfig } from '../../config'
const TAG = 'PiTabs'
const { tabs } = getConfig()
export default {
name: TAG,
// 混入v-model
mixins: [ValueSync],
props: {
// 初始值
value: {
required: false
},
// 自定义样式,对象形式(默认值:{})
customStyle: {
type: Object,
default() {
return tabs.customStyle
}
},
// 自定义样式类,字符串形式('')
customClass: {
type: String,
default() {
return tabs.customClass
}
},
// 选项列表,默认([])
items: {
type: Array,
default() {
return tabs.items
}
},
// 选项id字段,默认为id
keyField: {
type: String,
default: tabs.keyField
},
// 选项显示字段,默认为text
displayField: {
type: String,
default: tabs.displayField
},
// 选项两边的padding,单位rpx
itemPadding: {
type: [String, Number],
default() {
return tabs.itemPadding
}
},
// 标签是否自动撑开,(当scrollable时候生效)
stretch: {
type: Boolean,
default() {
return tabs.stretch
}
},
// 动画执行时间(毫秒)
duration: {
type: [String, Number],
default() {
return tabs.duration
}
},
// 激活颜色(不设置,默认主题色)
activeColor: {
type: String,
default() {
return tabs.activeColor
}
},
// 是否显示底部的滑块
showSliderBar: {
type: Boolean,
default() {
return tabs.showSliderBar
}
},
// 是否显示底部滑块导轨
showSliderBarGuide: {
type: Boolean,
default() {
return tabs.showSliderBarGuide
}
},
// 底部的滑块的宽度,单位rpx(如果不设置,默认按照当前item文字的宽度去适配)
sliderBarWidth: {
type: [String, Number],
default() {
return tabs.sliderBarWidth
}
},
// 底部的滑块的高度,单位rpx
sliderBarHeight: {
type: [String, Number],
default() {
return tabs.sliderBarHeight
}
},
// 导航栏的高度,单位rpx
height: {
type: [String, Number],
default() {
return tabs.height
}
},
// 选项样式(默认:'{}')
itemStyle: {
type: Object,
default() {
return tabs.itemStyle
}
},
// 底部滑块样式(默认:'{}')
sliderBarStyle: {
type: Object,
default() {
return tabs.sliderBarStyle
}
},
// 激活选项样式(默认:'{}')
activeItemStyle: {
type: Object,
default() {
return tabs.activeItemStyle
}
}
},
data() {
return {
tabsWidth: 0, // 组件区域宽度
tabsLeft: 0, // 组件区域离屏幕左边的距离
tabRects: [] // 标签节点信息
}
},
computed: {
activeIndex() {
if (!this.val) return 0
return this.items.findIndex(i => i[this.keyField] === this.val[this.keyField])
},
getHeight() {
return this.$pi.common.addUnit(this.height)
},
getSliderBarWidth() {
const sliderBarWidth = this.$pi.common.addUnit(this.sliderBarWidth) || 'auto'
return sliderBarWidth
},
getSliderBarHeight() {
return this.$pi.common.addUnit(this.sliderBarHeight)
},
getItemPadding() {
return this.$pi.common.addUnit(this.itemPadding)
},
getItemStyle() {
const style = {
padding: `0 ${this.getItemPadding}`
}
style.height = this.getHeight
style.lineHeight = this.getHeight
if (this.stretch) style.flex = '1'
return style
},
scrollLeft() {
if (!this.tabRects.length) return
// 计算当前激活item移动到容器中心距离左边距离
const activeRect = this.tabRects[this.activeIndex]
const activeRectWidth = activeRect.width
const activeRectLeft = activeRect.left
const scrollLeft = activeRectLeft - this.tabsLeft - this.tabsWidth / 2 + activeRectWidth / 2
return scrollLeft < 0 ? 0 : scrollLeft
},
getSliderBarStyle() {
const style = {
width: this.getSliderBarWidth,
height: this.getSliderBarHeight,
transitionDuration: `${this.duration / 1000}s`
}
if (!this.tabRects.length) return style
const activeRect = this.tabRects[this.activeIndex]
const activeRectWidth = activeRect.width
const activeRectLeft = activeRect.left
let sliderScrollLeft = activeRectLeft - this.tabsLeft
if (style.width !== 'auto') {
// 如果width设置了固定的宽度,将滑块移动到对应激活下的中心
const sliderBarWidth = uni.upx2px(parseInt(this.sliderBarWidth))
sliderScrollLeft = sliderScrollLeft + (activeRectWidth - sliderBarWidth) / 2
style.transform = `translateX(${sliderScrollLeft}px)`
}
if (style.width === 'auto') {
// 如果width设定了auto,根据当前激活项文字动态计算宽度
const itemPadding = uni.upx2px(parseInt(this.itemPadding))
style.width = `${activeRectWidth - itemPadding * 2}px`
style.transform = `translateX(${sliderScrollLeft + itemPadding}px)`
}
if (this.activeColor) style.backgroundColor = this.activeColor
return style
},
scrollWrapStyle() {
const style = {}
if (this.stretch) style.display = 'flex'
return style
}
},
mounted() {
this.init()
},
methods: {
async init() {
const srollWrapRect = await this.$pi.common.queryRect(this, '.pi-tabs', false)
if (srollWrapRect) {
this.tabsWidth = srollWrapRect.width
this.tabsLeft = srollWrapRect.left
}
this.tabRects = await this.$pi.common.queryRect(this, '.pi-tab', true)
},
handleSelectItem(item) {
this.val = item
this.handleEmitChange()
}
}
}
</script>

<style lang="scss" scoped>
.pi-tabs {
// 不显示滚动条
::v-deep ::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
.scroll-wrap {
position: relative;
display: inline-block;
white-space: nowrap;
.pi-tab {
display: inline-block;
text-align: center;
}
.slider-bar-guide {
position: absolute;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 4rpx;
.slider-bar {
width: 80rpx;
height: 100%;
background-color: $pi-primary-color;
transition-delay: $pi-animation-duration;
transition-timing-function: ease-in-out;
transition-property: all;
}
}
}
}
</style>
19 changes: 19 additions & 0 deletions config/tabs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default {
customClass: '', // 自定义样式类,字符串形式('')
customStyle: {}, // 自定义样式,对象形式(默认值:{})
items: [], // 选项列表,默认([])
keyField: 'id', // 选项id字段,默认为id
displayField: 'text', // 选项显示字段,默认为text
itemPadding: 30, // 选项两边的padding,单位rpx
stretch: false, // 标签是否自动撑开,(当scrollable时候生效)
duration: 300, // 动画执行时间(毫秒)
activeColor: '', // 激活颜色(不设置,默认主题色)
showSliderBar: true, // 是否显示底部的滑块
showSliderBarGuide: false, // 是否显示底部滑块导轨
sliderBarWidth: '', // 底部的滑块的宽度,单位rpx(如果不设置,默认按照当前item文字的宽度去适配)
sliderBarHeight: 4, // 底部的滑块的高度,单位rpx
height: 80, // 导航栏的高度,单位rpx
itemStyle: {}, // 选项样式(默认:'{}')
sliderBarStyle: {}, // 滑块样式(默认:'{}')
activeItemStyle: {} // 激活选项样式(默认:'{}')
}

0 comments on commit e7cc5c9

Please sign in to comment.