| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 | <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>
 |