项目初始化
This commit is contained in:
474
sheep/ui/su-tab/su-tab.vue
Normal file
474
sheep/ui/su-tab/su-tab.vue
Normal file
@@ -0,0 +1,474 @@
|
||||
<template>
|
||||
<view
|
||||
class="ui-tab"
|
||||
ref="tabRef"
|
||||
:id="'tab-' + vm.uid"
|
||||
:class="[
|
||||
props.ui,
|
||||
props.tpl,
|
||||
props.bg,
|
||||
props.align,
|
||||
{ 'ui-tab-inline': props.inline },
|
||||
{ 'ui-tab-scrolls': props.scroll },
|
||||
]"
|
||||
>
|
||||
<block v-if="scroll">
|
||||
<view class="ui-tab-scroll-warp">
|
||||
<scroll-view
|
||||
scroll-x="true"
|
||||
class="ui-tab-scroll"
|
||||
:scroll-left="state.curValue > 1 ? state.tabNodeList[state.curValue - 1].left : 0"
|
||||
scroll-with-animation
|
||||
:style="{ width: `${state.content.width}px` }"
|
||||
>
|
||||
<view class="ss-flex ss-col-center">
|
||||
<su-tab-item
|
||||
v-for="(item, index) in props.tab"
|
||||
:data="item"
|
||||
:index="index"
|
||||
:key="index"
|
||||
@up="upitem"
|
||||
@tap.native="click(index, item)"
|
||||
></su-tab-item>
|
||||
<view
|
||||
class="ui-tab-mark-warp"
|
||||
:class="[{ over: state.over }]"
|
||||
:style="[{ left: state.markLeft + 'px' }, { width: state.markWidth + 'px' }]"
|
||||
>
|
||||
<view
|
||||
class="ui-tab-mark"
|
||||
:class="[props.mark, { 'ui-btn': props.tpl == 'btn' || props.tpl == 'subtitle' }]"
|
||||
:style="[
|
||||
{
|
||||
background:
|
||||
props.tpl == 'btn' || props.tpl == 'subtitle' ? titleStyle.activeBg : 'none',
|
||||
},
|
||||
]"
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<su-tab-item
|
||||
v-for="(item, index) in props.tab"
|
||||
:data="item"
|
||||
:index="index"
|
||||
:key="index"
|
||||
@up="upitem"
|
||||
@tap.native="click(index, item)"
|
||||
></su-tab-item>
|
||||
<view
|
||||
class="ui-tab-mark-warp"
|
||||
:class="[{ over: state.over }]"
|
||||
:style="[{ left: state.markLeft + 'px' }, { width: state.markWidth + 'px' }]"
|
||||
>
|
||||
<view
|
||||
class="ui-tab-mark"
|
||||
:class="[props.mark, { 'ui-btn': props.tpl == 'btn' || props.tpl == 'subtitle' }]"
|
||||
></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SuTab',
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 基础组件 - suTab
|
||||
*/
|
||||
|
||||
import {
|
||||
toRef,
|
||||
ref,
|
||||
reactive,
|
||||
unref,
|
||||
onMounted,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
provide,
|
||||
} from 'vue';
|
||||
const vm = getCurrentInstance();
|
||||
|
||||
// 数据
|
||||
const state = reactive({
|
||||
curValue: 0,
|
||||
tabNodeList: [],
|
||||
scrollLeft: 0,
|
||||
markLeft: 0,
|
||||
markWidth: 0,
|
||||
content: {
|
||||
width: 100,
|
||||
},
|
||||
over: false,
|
||||
});
|
||||
|
||||
const tabRef = ref(null);
|
||||
// 参数
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
ui: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
bg: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
tab: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
// line dot long,subtitle,trapezoid
|
||||
tpl: {
|
||||
type: String,
|
||||
default: 'line',
|
||||
},
|
||||
mark: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
curColor: {
|
||||
type: String,
|
||||
default: 'ui-TC',
|
||||
},
|
||||
defaultColor: {
|
||||
type: String,
|
||||
default: 'ui-TC',
|
||||
},
|
||||
scroll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
titleStyle: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
activeBg: '#DA2B10',
|
||||
activeColor: '#FEFEFE',
|
||||
color: '#D70000',
|
||||
}),
|
||||
},
|
||||
subtitleStyle: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
activeColor: '#333',
|
||||
color: '#C42222',
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
onMounted(() => {
|
||||
state.curValue = props.modelValue;
|
||||
setCurValue(props.modelValue);
|
||||
nextTick(() => {
|
||||
computedQuery();
|
||||
});
|
||||
uni.onWindowResize((res) => {
|
||||
computedQuery();
|
||||
});
|
||||
});
|
||||
|
||||
const computedQuery = () => {
|
||||
uni.createSelectorQuery()
|
||||
.in(vm)
|
||||
.select('#tab-' + vm.uid)
|
||||
.boundingClientRect((data) => {
|
||||
if (data != null) {
|
||||
if (data.left == 0 && data.right == 0) {
|
||||
// setTimeout(() => {
|
||||
computedQuery();
|
||||
// }, 300);
|
||||
} else {
|
||||
state.content = data;
|
||||
setTimeout(() => {
|
||||
state.over = true;
|
||||
}, 300);
|
||||
}
|
||||
} else {
|
||||
console.log('tab-' + vm.uid + ' data error');
|
||||
}
|
||||
})
|
||||
.exec();
|
||||
};
|
||||
|
||||
const setCurValue = (value) => {
|
||||
if (value == state.curValue) return;
|
||||
state.curValue = value;
|
||||
computedMark();
|
||||
};
|
||||
|
||||
const click = (index, item) => {
|
||||
setCurValue(index);
|
||||
emits('update:modelValue', index);
|
||||
emits('change', {
|
||||
index: index,
|
||||
data: item,
|
||||
});
|
||||
};
|
||||
|
||||
const upitem = (index, e) => {
|
||||
state.tabNodeList[index] = e;
|
||||
if (index == state.curValue) {
|
||||
computedMark();
|
||||
}
|
||||
};
|
||||
|
||||
const computedMark = () => {
|
||||
if (state.tabNodeList.length == 0) return;
|
||||
let left = 0;
|
||||
let list = unref(state.tabNodeList);
|
||||
let cur = state.curValue;
|
||||
state.markLeft = list[cur].left - state.content.left;
|
||||
state.markWidth = list[cur].width;
|
||||
};
|
||||
|
||||
const computedScroll = () => {
|
||||
if (state.curValue == 0 || state.curValue == state.tabNodeList.length - 1) {
|
||||
return false;
|
||||
}
|
||||
let i = 0;
|
||||
let left = 0;
|
||||
let list = state.tabNodeList;
|
||||
for (i in list) {
|
||||
if (i == state.curValue && i != 0) {
|
||||
left = left - list[i - 1].width;
|
||||
break;
|
||||
}
|
||||
left = left + list[i].width;
|
||||
}
|
||||
state.scrollLeft = left;
|
||||
};
|
||||
|
||||
provide('suTabProvide', {
|
||||
props,
|
||||
curValue: toRef(state, 'curValue'),
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-tab {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 4em;
|
||||
align-items: center;
|
||||
|
||||
&.ui-tab-scrolls {
|
||||
width: 100%;
|
||||
/* #ifdef MP-WEIXIN */
|
||||
padding-bottom: 10px;
|
||||
/* #endif */
|
||||
.ui-tab-scroll-warp {
|
||||
overflow: hidden;
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
.ui-tab-scroll {
|
||||
position: relative;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
min-height: 4em;
|
||||
line-height: 4em;
|
||||
width: 100% !important;
|
||||
.ui-tab-mark-warp {
|
||||
display: flex;
|
||||
align-items: top;
|
||||
justify-content: center;
|
||||
.ui-tab-mark.ui-btn {
|
||||
/* #ifndef MP-WEIXIN */
|
||||
height: 2em;
|
||||
width: calc(100% - 0.6em);
|
||||
margin-top: 4px;
|
||||
/* #endif */
|
||||
/* #ifdef MP-WEIXIN */
|
||||
height: 2em;
|
||||
width: calc(100% - 0.6em);
|
||||
margin-top: 4px;
|
||||
/* #endif */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-tab-mark-warp {
|
||||
color: inherit;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
|
||||
&.over {
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.ui-tab-mark {
|
||||
color: var(--ui-BG-Main);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.line {
|
||||
.ui-tab-mark {
|
||||
border-bottom: 2px solid currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.topline {
|
||||
.ui-tab-mark {
|
||||
border-top: 2px solid currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&.dot {
|
||||
.ui-tab-mark::after {
|
||||
content: '';
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
background-color: currentColor;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0.3em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.long {
|
||||
.ui-tab-mark::after {
|
||||
content: '';
|
||||
width: 2em;
|
||||
height: 0.35em;
|
||||
background-color: currentColor;
|
||||
border-radius: 5em;
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0.3em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.trapezoid {
|
||||
.ui-tab-mark::after {
|
||||
content: '';
|
||||
width: calc(100% - 2em);
|
||||
height: 0.35em;
|
||||
background-color: currentColor;
|
||||
border-radius: 5em 5em 0 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn {
|
||||
.ui-tab-mark-warp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.ui-tab-mark.ui-btn {
|
||||
height: calc(100% - 1.6em);
|
||||
width: calc(100% - 0.6em);
|
||||
}
|
||||
}
|
||||
|
||||
&.sm .ui-tab-mark.ui-btn {
|
||||
height: calc(100% - 2px);
|
||||
width: calc(100% - 2px);
|
||||
border-radius: #{$radius - 2};
|
||||
}
|
||||
}
|
||||
|
||||
&.subtitle {
|
||||
.ui-tab-mark-warp {
|
||||
display: flex;
|
||||
align-items: top;
|
||||
justify-content: center;
|
||||
padding-top: 0.6em;
|
||||
|
||||
.ui-tab-mark.ui-btn {
|
||||
height: calc(100% - 2.8em);
|
||||
width: calc(100% - 0.6em);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ui-tab-inline {
|
||||
display: inline-flex;
|
||||
height: 3.5em;
|
||||
|
||||
&.ui-tab-scrolls {
|
||||
.ui-tab-scroll {
|
||||
height: calc(3.5em + 17px);
|
||||
line-height: 3.5em;
|
||||
|
||||
.ui-tab-mark-warp {
|
||||
height: 3.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.btn {
|
||||
.ui-tab-mark-warp {
|
||||
.ui-tab-mark.ui-btn {
|
||||
height: calc(100% - 10px);
|
||||
width: calc(100% - 10px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.sm {
|
||||
height: 70rpx !important;
|
||||
|
||||
&.ui-tab-inline {
|
||||
height: 70rpx;
|
||||
|
||||
&.ui-tab-scrolls {
|
||||
.ui-tab-scroll {
|
||||
height: calc(70rpx + 17px);
|
||||
line-height: 70rpx;
|
||||
|
||||
.ui-tab-mark-warp {
|
||||
height: 70rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.btn .ui-tab-mark.ui-btn {
|
||||
height: calc(100% - 2px);
|
||||
width: calc(100% - 2px);
|
||||
border-radius: #{$radius - 2};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user