123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- <template>
- <view class="tm-tabs " :class="[bgColor == 'white' ? (black_tmeme ? 'bk grey-darken-4' : bgColor) : bgColor, 'shadow-' + bgColor + '-' + shadow, black_tmeme ? 'bk' : '']">
- <scroll-view scroll-with-animation :scroll-into-view="toTargetId" @scroll="scrollViesw" scroll-x class="tm-tabs-con ">
- <view
- class="tm-tabs-wk "
- :class="{
- 'text-align-left': align == 'left',
- 'text-align-right': align == 'right',
- 'text-align-center': align == 'center',
- 'flex-between': align == 'split'
- }"
- >
- <view
- @click.stop.prevent="acitveItemClick(index, true, $event)"
- class="tm-tabs-con-item d-inline-block "
- :class="[
- `tm-tabs-con-item-${index}`,
- model == 'rect' ? 'border-' + color_tmeme + '-a-1' : '',
- index !== list.length - 1 && model == 'rect' ? 'tm-tabs-con-item-rborder' : '',
- active == index && model == 'rect' ? color_tmeme : ''
- ]"
- :style="{
- height: barheight + 'px',
- lineHeight: barheight + 'px'
- }"
- v-for="(item, index) in list"
- :key="index"
- :id="guid + '_' + index"
- >
- <view
- class="tm-tabs-con-item-text px-24"
- :style="{
- fontSize: active == index ? active_font_size : font_size
- }"
- :class="[
- (model == 'line' || model == 'none') && active == index ? 'text-' + color_tmeme : 'text-'+fontColor,
- (model == 'line' || model == 'none') && active == index ? 'text-weight-b' : '',
- model == 'fill' && active == index ? color_tmeme: '',
- ]"
- >
- <slot name="default" :data="item">{{ item[rangeKey] || item }}</slot>
- </view>
- </view>
- </view>
- <view
- v-if="model == 'line'"
- class="tm-tabs-con-item-border"
- :class="[borderColor, `shadow-${color_tmeme}-4`, isOnecLoad == false ? 'tm-tabs-con-item-border-trans' : '']"
- :style="{
- transform: `translateX(${activePos.left})`,
- width: activePos.width
- }"
- ></view>
- </scroll-view>
- </view>
- </template>
- <script>
- /**
- * 选项卡切换
- * @property {String} model = [line|rect|fill] 默认:line,样式,线和框两种
- * @property {String} color = [] 默认:primary,主题文字颜色。
- * @property {String} active-border-color = [] 默认:'',底下指示线的颜色主题。
- * @property {String} bg-color = [] 默认:white,主题背景颜色。
- * @property {Number} value = [] 默认:0,当前激活的项。双向绑定使用value.sync或者v-model
- * @property {Number} font-size = [] 默认:28,默认字体大小,单位upx
- * @property {Number} font-color = [] 默认:'',默认文字颜色,默认为空,使用主题自动匹配文字色。
- * @property {Number} active-font-size = [] 默认:28,激活后字体大小,单位upx
- * @property {String} align = [center|left|right|split] 默认:center,居中,左,右,均分对齐
- * @property {String|Number} height = [90|100] 默认:90,高度。单位 upx
- * @property {Array} list = [] 默认:[],数据数组,可以是字符串数组,也可以是对象数组,需要提供rangKey
- * @property {String} range-key = [] 默认:'',数据数组,需要提供rangKey以显示文本。
- * @property {Function} change 返回当前选中的index值同v-model一样的值
- * @property {String} active-key-value = [] 默认:'',当前激活项(和value一样的功能),如果提供对象数组,则可以提供当前选项list[index][activeKey]的对象数据来自动解析当前选择的index项
- */
- export default {
- name: 'tm-tabs',
- model: {
- prop: 'value',
- event: 'input'
- },
- props: {
- // 样式,
- model: {
- type: String,
- default: 'line' //line|rect|fill
- },
- // 主题色包括文字颜色
- color: {
- type: String,
- default: 'primary'
- },
- activeBorderColor: {
- type: String,
- default: ''
- },
- // 背景颜色。
- bgColor: {
- type: String,
- default: 'white'
- },
- // 当前激活的项。
- value: {
- type: Number,
- default: 0
- },
- // 项目对齐方式。
- align: {
- type: String,
- default: 'center' // center|left|right|split
- },
- // 单位为upx
- height: {
- type: String | Number,
- default: 90
- },
- black: {
- type: Boolean | String,
- default: null
- },
- // 投影。
- shadow: {
- type: String | Number,
- default: 3
- },
- list: {
- type: Array,
- default: () => {
- // { title: '标签1', value: '' }, { title: '标签2标签标签', value: '' }, { title: '标签3', value: '' }
- return [];
- }
- },
- rangeKey: {
- type: String,
- default: ''
- },
- // 当前激活项,如果提供对象数组,则可以提供当前选项的对象数据来自动解析当前选择的index项
- activeKeyValue: {
- type: String,
- default: ''
- },
- fontSize: {
- type: Number,
- default: 28
- },
- //默认文字颜色,默认为空,使用主题自动匹配文字色。
- fontColor: {
- type: String,
- default: ''
- },
- activeFontSize: {
- type: Number,
- default: 28
- },
- // 跟随主题色的改变而改变。
- fllowTheme: {
- type: Boolean | String,
- default: true
- }
- },
- watch: {
- activeKeyValue: function() {
- this.setActiveIndex();
- },
- value: async function(val) {
- this.active = val;
- this.acitveItemClick(val,false);
- },
- active: async function(val) {
- this.$emit('input', val);
- this.$emit('update:value', val);
- this.$emit('change', val);
- },
- list: {
- deep: true,
- async handler() {
- await this.inits();
- }
- }
- },
- computed: {
- font_size: function() {
- return uni.upx2px(this.fontSize) + 'px';
- },
- active_font_size: function() {
- return uni.upx2px(this.activeFontSize) + 'px';
- },
- black_tmeme: function() {
- if (this.black !== null) return this.black;
- return this.$tm.vx.state().tmVuetify.black;
- },
- color_tmeme: function() {
- if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this.fllowTheme) {
- return this.$tm.vx.state().tmVuetify.color;
- }
- return this.color;
- },
- borderColor: function() {
- if (this.$tm.vx.state().tmVuetify.color !== null && this.$tm.vx.state().tmVuetify.color && this.fllowTheme) {
- return this.$tm.vx.state().tmVuetify.color;
- }
- return this.activeBorderColor || this.color;
- },
- barheight: function() {
- let h = parseInt(this.height);
- if (isNaN(h) || !h) h = 90;
- return uni.upx2px(h);
- }
- },
- data() {
- return {
- active: 0,
- old_active: 0,
- guid: '',
- scrollObj: null,
- activePos: {
- left: 0,
- width: 0
- },
- preantObjinfo: null,
- tid: 88855565656,
- isOnecLoad: true,
- toTargetId: ''
- };
- },
- created() {
- this.guid = uni.$tm.guid();
- this.active = this.value;
- },
- mounted() {
- let t= this;
- uni.$tm.sleep(50).then(()=>{
- t.inits();
- })
- },
- methods: {
- inits() {
- let t = this;
- this.setActiveIndex(this.active);
- let pqu = uni.createSelectorQuery().in(t)
- pqu.select('.tm-tabs')
- .boundingClientRect().exec(function (pd) {
- t.preantObjinfo = pd[0];
-
- t.$nextTick(function() {
- t.acitveItemClick(t.active, false);
- });
- })
-
- },
- scrollViesw(e) {
- this.scrollObj = e;
- },
- setLabelLeft(indexObj_now, callback) {
- let t = this;
- let e = this.scrollObj;
- let escroolet = 0;
- if (e) {
- escroolet = e.detail.scrollLeft;
- }
- let pqu = uni.createSelectorQuery().in(t)
- let ychi = this.activeFontSize==this.fontSize?0:160;
- uni.$tm.sleep(ychi).then(fs=>{
- pqu.select(`.tm-tabs-con-item-${indexObj_now}`)
- .boundingClientRect().select(`.tm-tabs-con-item-0`).boundingClientRect().exec(
- function(res) {
-
- let now_Item_obj = res[0];
- let now_Item_one = res[1];
-
- if(now_Item_obj.id==now_Item_one.id){
-
- // now_Item_obj.right = Math.abs(now_Item_one.left)+now_Item_one.right;
- // now_Item_one.right = Math.abs(now_Item_one.left)+now_Item_one.right;
- // now_Item_obj.left=0;
- // now_Item_one.left=0;
- }
- let nowId = t.guid + '_' + t.active;
- let dleft = now_Item_obj.left;
- let preventLeft = t.preantObjinfo.left;
- let acLeft = 0;
- let lftc = 0;
- let ch = (now_Item_obj.width - 24 - uni.upx2px(24) * 2) / 2;
- if (dleft <= 0) {
- dleft = escroolet + now_Item_obj.left;
- if (now_Item_obj.left == 0 && escroolet == 0) {
- lftc = (now_Item_obj.width - 24 - uni.upx2px(24) * 2) / 2 + 12 + 'px';
-
- } else {
- lftc = dleft + ch + 12 + 'px';
- if(now_Item_obj.id==now_Item_one.id){
- let ptch = (now_Item_obj.width) / 2;
- lftc = ptch-12+'px'
- }
-
- }
- } else {
- acLeft = Math.abs(now_Item_one.left >= 0 ? 0 : now_Item_one.left) + Math.abs(dleft);
-
- lftc = acLeft + uni.upx2px(24) - (now_Item_one.left >= 0 ? t.preantObjinfo.left : 0) + ch + 'px';
- }
- t.activePos = {
- left: lftc,
- // left:nowPage_x + itemObj.width + 'px',
- width: 24 + 'px'
- };
- t.old_active = t.active;
- callback();
- })
- })
-
-
- },
- setActiveIndex() {
- let t = this;
- if (typeof this.list[0] === 'object' && this.rangeKey) {
- let index = this.list.findIndex(item => {
- return item[t.rangeKey] == t.activeKeyValue;
- });
- if (index > -1) {
- this.active = index;
- }
- }
- },
- acitveItemClick(indx, etype, e) {
- let t = this;
- if (etype !== false) {
- this.isOnecLoad = false;
- }
- if (this.list.length <= 0) return;
- if (typeof this.list[indx] == 'undefined') return;
- t.active = indx;
- t.setLabelLeft(indx, function() {
- let nowScrollToid = '';
- let pqu = uni.createSelectorQuery().in(t)
- pqu.select('#' + t.guid + '_' + indx)
- .boundingClientRect().exec(function (pd) {
- let itemObj = pd[0];
- if (itemObj.left <= 0) {
- t.toTargetId = itemObj.id;
- } else if (itemObj.right > t.preantObjinfo.right) {
- t.toTargetId = itemObj.id;
- } else {
- t.toTargetId = null;
- }
- })
-
- });
- }
- }
- };
- </script>
- <style lang="scss" scoped>
- .tm-tabs {
- .tm-tabs-con {
- position: relative;
- width: 100%;
- .tm-tabs-con-item-border {
- height: 4px;
- border-radius: 4px;
- position: absolute;
- margin-top: -4px;
- width: 10px;
- &.tm-tabs-con-item-border-trans {
- transition: all 0.15s linear;
- }
- }
- .tm-tabs-wk {
- position: relative;
- left: 0;
- white-space: nowrap;
- width: 100%;
- .tm-tabs-con-item {
- flex-shrink: 0;
- display: inline-block;
- .tm-tabs-con-item-text {
- // transition: all 0.1s;
- }
- &.tm-tabs-con-item-rborder {
- border-right: 0;
- }
- }
- }
- }
- }
- </style>
|