uniapp+vue3 实现菜单左右关联(类似vue中的better-scroll插件)

效果如图:
在这里插入图片描述

上代码:

<script setup lang="ts">
import { onShow } from '@dcloudio/uni-app'
import { nextTick, getCurrentInstance } from 'vue'
import ClassifySkeleton from './ClassifySkeleton'
import { isH5 } from '@/utils/is'

const instance = getCurrentInstance()
const list = ref([])
/** 每个锚点与到顶部距离 */
const listItemTops = ref([])
/** 左侧选中id */
const leftMenuId = ref(0)
/** 是否是滑动右侧 */
const isRightScroll = ref(true)
/** 锚点 */
const scrollInto = ref('')
const loading = ref(false)

const commonConfig = useCommonConfig()

onMounted(async () => {
  await getGoodsCategory()

  await nextTick(() => {
    getElementTop()
  })
})

onShow(() => {
  setTabBarBadge()
})

/**
 * 获取商品分类
 */
const getGoodsCategory = async () => {
  try {
    loading.value = true

    const data = await commonConfig.getCategory()

    list.value = data
    leftMenuId.value = data?.[0]?.id
  } finally {
    loading.value = false
  }
}

/**
 * 获取距离顶部的高度
 *
 * @param selector
 */
const getScrollTop = (selector) => {
  return new Promise((resolve) => {
    const query = uni.createSelectorQuery().in(instance)
    query
      .select(selector)
      .boundingClientRect((data) => {
        resolve(data.top)
      })
      .exec()
  })
}

/**
 * 获取元素顶部距离
 */
const getElementTop = async () => {
  const eTops = toRaw(list.value).map(async ({ id }) => {
    const top = await getScrollTop(`#leftMenu-${id}`)

    return top - 80
  })

  Promise.all(eTops).then((data) => {
    listItemTops.value = data
  })
}

/**
 * 右侧滚动监听
 *
 * @param e
 */
const onRightScroll = (e) => {
  if (!isRightScroll.value) return

  const top = e.detail.scrollTop
  const index = listItemTops.value.findIndex((item, index) => listItemTops.value[index + 1] >= top)

  leftMenuId.value = list.value[Math.max(0, index)].id
}

/**
 * 点击左侧菜单
 *
 * @param id 左侧菜单id
 */
const handleClickLeftMenu = (id) => {
  isRightScroll.value = false

  leftMenuId.value = id
  scrollInto.value = `leftMenu-${id}`
}

/**
 * 页面跳转 产品中心
 */
const toPage = (item, data) => {
  item = toRaw(item)
  data = toRaw(data)

  nav.navigateTo({
    url: 'ProductCenter',
    data: {
      id: data.id,
      name: data.name,
      pId: item.id,
      pName: item.name,
    },
  })
}

/**
 * scroll-view样式
 */
const scrollViewStyle = {
  height: isH5 ? 'calc(100vh - 94px)' : '100vh',
}
</script>

<template>
  <ClassifySkeleton v-if="loading" :skeletonStyle="scrollViewStyle" />
  <view v-else class="flex">
    <!-- 左侧分类列表 -->
    <scroll-view
      class="w-24 bg-[#f8f8f8]"
      :style="scrollViewStyle"
      scroll-y
      :scroll-with-animation="true"
    >
      <view
        v-for="item in list"
        :key="item.id"
        :data-index="item.id"
        :class="`px-2 py-4 text-sm ${item.id == leftMenuId ? 'font-bold bg-white' : ''}`"
        @click="handleClickLeftMenu(item.id)"
      >
        {{ item.name }}
      </view>
    </scroll-view>

    <!-- 右侧商品列表 -->
    <scroll-view
      class="flex-1 px-2"
      :style="scrollViewStyle"
      scroll-y
      :scroll-into-view="scrollInto"
      :scroll-with-animation="true"
      @touchstart="isRightScroll = true"
      @scroll="onRightScroll"
      enhanced
      :show-scrollbar="false"
    >
      <view class="mb-10 py-4" :id="`leftMenu-${item.id}`" v-for="item in list" :key="item.id">
        <view class="text-md mb-2 font-bold">{{ item.name }}</view>
        <view class="pt-5 grid grid-cols-3">
          <view
            class="text-center pb-6"
            v-for="i in item.children"
            :key="i.id"
            @click="() => toPage(item, i)"
          >
            <image class="w-8 h-8" :src="i.appImage" />
            <view class="text-xs">{{ i.name }}</view>
          </view>
        </view>
      </view>
    </scroll-view>
  </view>
</template>
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue是一种用于构建用户界面的渐进式JavaScript框架,它可以帮助开发者更高效地构建单页面应用程序。而vue-better-scroll是基于Vue的一款优秀的滚动插件,它能够实现更流畅的滚动效果,并且支持上下左右的滚动和联动效果。 如果需要实现左右菜单的联动效果,我们可以通过使用vue-better-scrollscrollToElement方法来实现。首先,我们需要在Vue引入vue-better-scroll插件并进行配置。 在Vue实例的data,我们可以定义左右两个菜单的数据,例如leftMenu和rightMenu,并在created生命周期初始化数据。然后,在mounted生命周期,我们可以通过refs属性获取到两个菜单容器的DOM元素。 接下来,我们需要监听左边菜单的点击事件,当点击左边菜单的某个选项时,我们可以通过调用vue-better-scrollscrollToElement方法,将右边菜单滚动到对应的位置。通过传递目标元素的选择器或具体的DOM元素,我们可以实现左右菜单的联动效果。 具体实现时,我们可以在左边菜单的点击事件,使用this.$refs来访问右边菜单容器,并调用scrollToElement方法,将目标元素滚动到可视区域。通过传递选择器或具体DOM元素作为参数,我们可以精确控制滚动的位置。 同时,为了视觉上更好的效果,我们还可以给目标元素添加样式,如高亮当前选项,以提升用户体验。 最后,通过一系列的事件处理和样式设置,我们就可以实现左右菜单的联动demo了。 以上就是使用Vuevue-better-scroll实现左右菜单联动demo的大致思路和步骤。通过合理运用这两个工具,我们可以轻松地实现出一个流畅、友好的用户界面效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值