uniapp 滚动tab

发布于:2025-07-03 ⋅ 阅读:(17) ⋅ 点赞:(0)

uniapp + woui +unibest

<route lang="json5">
	{
	style: {
	navigationBarTitleText: '知识产权',
	navigationBarBackgroundColor: '#C80F06',
	navigationBarTextStyle: 'white',
	backgroundColorTop: '#C80F06',
	},
	}
</route>
<template>
  <view class="bgc-b w100">
    <!-- 导航栏 -->
    <NavTabScroll
      :tabs="tabs"
      :current-tab="currentTab"
      :scroll-left="scrollLeft"
      :show-nav-bar="showNavBar"
      @update:currentTab="handleTabClick"
    />
    <scroll-view
      class="content-scroll"
      id="my-scroll"
      :scroll-y="true"
      :scroll-x="false"
      :scroll-into-view="currentAnchor"
      :scroll-top="scrollTop"
      :scroll-with-animation="true"
      @scroll="handleScroll"
    >
      <view class="section" id="patent">
        <SubTitle
          :title="tabs[0].title"
          :toggleName="tabs[0].key"
          :show="patentParam.show"
          ref="title1"
          @toggle="handleToggle('patent')"
        ></SubTitle>
        <view
          class="sec_item"
          v-for="(item, index) in patentList"
          :key="index"
          v-show="patentParam.show"
        >
          <Patent :data="item"></Patent>
        </view>
        <view class="load-more-list">
          <!-- v-if="+patentParam.totalCount > patentList.length" -->
          <view class="load-more-btn" @click="handleViewMore('patent')">
            <text>查看更多</text>
          </view>

          <view class="is-loading" v-if="patentParam.loading">
            <text>加载中</text>
          </view>
        </view>
      </view>
      <view class="section" id="brand">
        <SubTitle
          :title="tabs[1].title"
          :toggleName="tabs[1].key"
          :show="brandParam.show"
          ref="title1"
          @toggle="handleToggle('brand')"
        ></SubTitle>
        <view
          class="sec_item"
          v-for="(item, index) in brandList"
          :key="index"
          v-show="brandParam.show"
        >
          <Brand :data="item"></Brand>
        </view>
        <view class="load-more-list">
          <!-- v-if="+brandParam.totalCount > brandList.length" -->
          <view class="load-more-btn" @click="handleViewMore('brand')">
            <text>查看更多</text>
          </view>

          <view class="is-loading" v-if="brandParam.loading">
            <text>加载中</text>
          </view>
        </view>
      </view>
      <view class="section" id="softwareCopyright">
        <SubTitle
          :title="tabs[2].title"
          :toggleName="tabs[2].key"
          :show="showBrand"
          ref="title1"
          @toggle="handleToggle('softwareCopyright')"
        ></SubTitle>
        <view
          class="sec_item"
          v-for="(item, index) in softwareCopyrightList"
          :key="index"
          v-show="softwareCopyrightParam.show"
        >
          <SoftwareCopyright :data="item"></SoftwareCopyright>
        </view>

        <view class="load-more-list">
          <!-- v-if="+softwareCopyrightParam.totalCount > softwareCopyrightParam.length" -->
          <view class="load-more-btn" @click="handleViewMore('softwareCopyright')">
            <text>查看更多</text>
          </view>

          <view class="is-loading" v-if="softwareCopyrightParam.loading">
            <text>加载中</text>
          </view>
        </view>
      </view>
      <view class="section" id="workCopyright">
        <SubTitle
          :title="tabs[3].title"
          :toggleName="tabs[3].key"
          :show="workCopyrightParam.show"
          ref="title1"
          @toggle="handleToggle('workCopyright')"
        ></SubTitle>
        <view
          class="sec_item"
          v-for="(item, index) in workCopyrightList"
          :key="index"
          v-show="workCopyrightParam.show"
        >
          <WorkCopyright :data="item"></WorkCopyright>
        </view>

        <view class="load-more-list">
          <!-- v-if="+workCopyrightParam.totalCount > workCopyrightList.length" -->
          <view class="load-more-btn" @click="handleViewMore('workCopyright')">
            <text>查看更多</text>
          </view>

          <view class="is-loading" v-if="workCopyrightParam.loading">
            <text>加载中</text>
          </view>
        </view>
      </view>
      <view class="section" id="network">
        <SubTitle
          :title="tabs[4].title"
          :toggleName="tabs[4].key"
          :show="networkParam.show"
          ref="title1"
          @toggle="handleToggle('network')"
        ></SubTitle>
        <view
          class="sec_item"
          v-for="(item, index) in networkList"
          :key="index"
          v-show="networkParam.show"
        >
          <Network :data="item"></Network>
        </view>

        <view class="load-more-list">
          <!-- <view
            class="load-more-btn"
            v-if="+networkParam.totalCount > networkList.length"
            @click="handleViewMore('network')"
          >
            <text>查看更多</text>
          </view> -->

          <view class="is-loading" v-if="networkParam.loading">
            <text>加载中</text>
          </view>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<script lang="ts" setup>
import { ref, onMounted, nextTick, onUnmounted, computed } from 'vue'
import { debounce } from '@/uni_modules/wot-design-uni/components/common/util'
import {
  listPatentApplicationListAll,
  listTrademarkListAll,
  listSoftwareCopyrightInfoAll,
  listCopyrightInfoAll,
  listWebsiteInfoAll,
} from '@/api/enterprise'
import NavTabScroll from '@/components/NavTabScroll/NavTabScroll.vue' //滚动锚点组件
import SubTitle from '@/components/Property/title.vue'
import Patent from '@/components/Property/patent.vue'
import Brand from '@/components/Property/brand.vue'
import SoftwareCopyright from '@/components/Property/softwareCopyright.vue'
import WorkCopyright from '@/components/Property/workCopyright.vue'
import Network from '@/components/Property/network.vue'

const tabs = [
  { key: 'patent', title: '专利', top: 0 },
  { key: 'brand', title: '商标', top: 0 },
  { key: 'softwareCopyright', title: '软件著作权', top: 0 },
  { key: 'workCopyright', title: '作品著作权', top: 0 },
  { key: 'network', title: '网络备案', top: 0 },
]
const scrollLeft = ref(0)
const showNavBar = ref(true)
const currentTab = ref('patent')
const currentAnchor = ref('')
const scrollTop = ref(0)

const id = ref(null)

const topList = ref([])

const patentList = ref([])
const patentParam = ref({
  applicationDate: '',
  applicationNumber: [],
  companyId: '960f87c242e8ad867a066cbaa5f78e1',
  companyName: '',
  name: '',
  pageNo: 0,
  pageSize: 0,
  publicationDate: '',

  totalCount: 0,
  totalPage: 0,
  loading: false,
  show: true,
})

const brandList = ref([])
const brandParam = ref({
  appDate: '',
  companyId: '960cf87c242e8ad867a066cbaa5f78e1',
  companyName: '',
  flowStatusDesc: '',
  intClsDesc: '',
  name: '',
  pageNo: 1,
  pageSize: 5,
  regDate: '',

  totalCount: 0,
  totalPage: 0,
  loading: false,
  show: true,
})

const softwareCopyrightList = ref([])
const softwareCopyrightParam = ref({
  companyId: '848f94014224e0999b52c45e02ad1164',
  companyName: '',
  name: '',
  pageNo: 1,
  pageSize: 5,
  registerAperDate: '',

  totalCount: 0,
  totalPage: 0,
  loading: false,
  show: true,
})
const workCopyrightList = ref([])
const workCopyrightParam = ref({
  companyId: 'a6faee7453d06561b7e6bb6cc3235c4f',
  companyName: '',
  pageNo: 1,
  pageSize: 5,
  registerDate: '',

  totalCount: 0,
  totalPage: 0,
  loading: false,
  show: true,
})

const networkList = ref([])
const networkParam = ref({
  companyId: '95113c19bd54fee0155438311aac5af6',
  companyName: '',
  pageNo: 1,
  pageSize: 5,

  totalCount: 0,
  totalPage: 0,
  loading: false,
  show: true,
})

onLoad((options) => {
  id.value = options.companyId

  // 如果有 currentTab 参数,设置初始标签并滚动
  if (options.currentTab) {
    currentTab.value = options.currentTab
  }
  // networkParam.value.companyId = id.value

  Promise.all([getPatent(), getBrand(), getSoftware(), getWorkCopyright(), getNetwork()]).then(
    (res) => {
      setTimeout(() => {
        calcPosition()
        currentAnchor.value = options.currentTab
      }, 400)
    },
  )
})
function getPatent() {
  return new Promise((resolve) => {
    const params = JSON.parse(JSON.stringify(patentParam.value))
    delete params.totalCount
    delete params.totalPage
    delete params.loading
    delete params.show
    patentParam.value.loading = true
    listPatentApplicationListAll(params)
      .then((res) => {
        if (res.status === '0') {
          if (res.data && res.data.length) {
            patentList.value = [...patentList.value, ...res.data]
          }
          patentParam.value.totalCount = +res.totalCount || 0
          patentParam.value.totalPage = +res.totalPage || 0
        }
        resolve(patentList.value)
      })
      .finally(() => {
        patentParam.value.loading = false
      })
  })
}
function getBrand() {
  return new Promise((resolve) => {
    const params = JSON.parse(JSON.stringify(brandParam.value))
    delete params.totalCount
    delete params.totalPage
    delete params.loading
    delete params.show
    brandParam.value.loading = true
    listTrademarkListAll(params)
      .then((res) => {
        if (res.status === '0') {
          if (res.data && res.data.length) {
            brandList.value = [...brandList.value, ...res.data]
          }
          brandParam.value.totalCount = +res.totalCount || 0
          brandParam.value.totalPage = +res.totalPage || 0
        }
        resolve(brandList.value)
      })
      .finally(() => {
        brandParam.value.loading = false
      })
  })
}
function getSoftware() {
  return new Promise((resolve) => {
    const params = JSON.parse(JSON.stringify(softwareCopyrightParam.value))
    delete params.totalCount
    delete params.totalPage
    delete params.loading
    delete params.show
    softwareCopyrightParam.value.loading = true
    listSoftwareCopyrightInfoAll(params)
      .then((res) => {
        if (res.status === '0') {
          if (res.data && res.data.length) {
            softwareCopyrightList.value = [...softwareCopyrightList.value, ...res.data]
          }
          softwareCopyrightParam.value.totalCount = +res.totalCount || 0
          softwareCopyrightParam.value.totalPage = +res.totalPage || 0
        }
        resolve(softwareCopyrightList.value)
      })
      .finally(() => {
        softwareCopyrightParam.value.loading = false
      })
  })
}
function getWorkCopyright() {
  return new Promise((resolve) => {
    const params = JSON.parse(JSON.stringify(workCopyrightParam.value))
    delete params.totalCount
    delete params.totalPage
    delete params.loading
    delete params.show
    workCopyrightParam.value.loading = true
    listCopyrightInfoAll(params)
      .then((res) => {
        if (res.status === '0') {
          if (res.data && res.data.length) {
            workCopyrightList.value = [...workCopyrightList.value, ...res.data]
          }
          workCopyrightParam.value.totalCount = +res.totalCount || 0
          workCopyrightParam.value.totalPage = +res.totalPage || 0
        }
        resolve(workCopyrightList.value)
      })
      .finally(() => {
        workCopyrightParam.value.loading = false
      })
  })
}

function getNetwork() {
  return new Promise((resolve) => {
    const params = JSON.parse(JSON.stringify(networkParam.value))
    delete params.totalCount
    delete params.totalPage
    delete params.loading
    delete params.show
    networkParam.value.loading = true
    listWebsiteInfoAll(params)
      .then((res) => {
        if (res.status === '0') {
          if (res.data && res.data.length) {
            networkList.value = [...networkList.value, ...res.data]
          }
          networkParam.value.totalCount = +res.totalCount || 0
          networkParam.value.totalPage = +res.totalPage || 0
        }
        resolve(networkList.value)
      })
      .finally(() => {
        networkParam.value.loading = false
      })
  })
}

function handleToggle(type) {
  if (type === 'patent') {
    patentParam.value.show = !patentParam.value.show
  } else if (type === 'brand') {
    brandParam.value.show = !brandParam.value.show
  } else if (type === 'softwareCopyright') {
    softwareCopyrightParam.value.show = !softwareCopyrightParam.value.show
  } else if (type === 'workCopyright') {
    workCopyrightParam.value.show = !workCopyrightParam.value.show
  } else if (type === 'network') {
    networkParam.value.show = !networkParam.value.show
  }
  setTimeout(() => {
    calcPosition()
  }, 300)
}

async function handleTabClick(key: string, index: number) {
  currentTab.value = key
  currentAnchor.value = key
}

// 一进入页面且数据渲染完成后 或 展开收起的时候判断 页面元素的高度
function calcPosition() {
  const query = uni.createSelectorQuery()
  query.select('.content-scroll').boundingClientRect()
  tabs.forEach((key) => {
    query.select(`#${key.key}`).boundingClientRect()
  })
  query.exec((res) => {
    // 第一个参数是外层滚动框距离顶部的高度
    topList.value = res.map((item) => {
      return item.top
    })

    tabs.map((item, index) => {
      item.top = topList.value[index + 1] - topList.value[0]
    })
  })
}

// 滚动判断高度
function handleScroll(e: any) {
  debouncedScrollEnd(e)
}

const debouncedScrollEnd = debounce(async (e) => {
  const scrollTop = e.detail.scrollTop

  // 遍历sectionTops,找到当前所在的section
  for (let i = 0; i < tabs.length; i++) {
    if (scrollTop >= tabs[i].top && scrollTop <= tabs[i + 1].top && i < tabs.length - 1) {
      currentTab.value = tabs[i].key
      break
    } else if (i === tabs.length - 1) {
      // 最后一个元素
      currentTab.value = tabs[i - 1].key
      break
    }
  }
}, 500)

// 随机颜色生成
function getRandomColor(index: number): string {
  const colors = [
    '#53C89C',
    '#4EBCDE',
    '#2E8AF0',
    '#588BEA',
    '#6875E4',
    '#9370DB',
    '#FC9682',
    '#F5A882',
    '#F8BF7F',
    '#F5D678',
    '#63D5D2',
  ]
  return colors[index % colors.length]
}

function handleViewMore(type) {
  uni.navigateTo({
    url: `/pages-sub/property/${type}?companyId=${id.value}`,
  })
}
</script>
<style lang="scss" scoped>
.section {
  background: #fff;
  margin-bottom: 16rpx;
}
.content-scroll {
  height: calc(100vh - 30rpx);
}
</style>



网站公告

今日签到

点亮在社区的每一天
去签到