小程序左右侧边栏

效果

点击左侧边栏,右侧会定位到对应内容;

右侧滑动,左侧也会显示对应的高亮;

也就是左右联动的效果

项目场景

tocc-app 应急巡检

传入数据:

左侧点击,右侧滚动到对应位置

点击左侧导航条,就计算出右侧要的

js 复制代码
      toggleActive(index) {
        this.isSidebarClick = true
        this.scActiveIndex = index
        // .map返回数组,里面的元素是每个对象中scContentData的长度  [6,6,6,6,6]
        // 然后 .reduce 来求和 计算总的长度
        this.scContentScrollTop =
          this.scDataList
            .slice(0, index)
            .map((item) => item.scContentData.length)
            .reduce((total, length) => total + length, 0) *
            41 +
            // 因为右边除了数据,还要展示小标题,所以要再加上前面的标题
          this.scDataList.slice(0, index).length * 41
      },

完整代码

js 复制代码
<template>
  <view class="sc-tabs">
    <!-- 左侧侧边栏 -->
    <view class="menu-aside-tab-box">
      <scroll-view class="menu-aside-tab" scroll-y>
        <view
          v-for="(item, index) in scDataList"
          :class="scActiveIndex === index ? 'aside-active' : 'aside-line'"
          :key="item.barId"
          class="aside-bar"
          @click="toggleActive(index)">
          <!-- :style="{ 'border-left': scActiveIndex === index ? '3px #3c9cff solid' : 'none' }" -->
          <view
            :style="{
              'border-left': scActiveIndex === index ? '3px #3c9cff solid' : 'none',
              'font-size': scActiveIndex === index ? '15px' : '13px',
              width: '100%',
              height: '12px',
              'line-height': '12px'
            }">
            {{ item.barTitle }}
          </view>
        </view>
      </scroll-view>
    </view>
    <!-- 右侧内容 -->
    <view class="scContent-box">
      <scroll-view class="scContent" scroll-y :scroll-top="scContentScrollTop" @scroll="ScHandleContentScroll">
        <view v-for="(item, index) in scDataList" :key="item.barId" class="content-bar">
          <view class="bar-title">
            <view class="br-title-line"></view>
            <text>{{ item.barTitle }}</text>
          </view>
          <view class="line"></view>
          <!-- 此处为内容栏每行,可以按需将view修改为card或list -->
          <view v-for="subItem in item.scContentData" :key="subItem.id" class="content-bar-item">
            <view style="height: 41px; line-height: 29px">{{ subItem.name }}</view>
            <view class="stateBox">
              <!-- 正常按钮 -->
              <button
                class="state"
                v-show="!subItem.isShowAddButton"
                :style="{ backgroundColor: buttonBgcMap[subItem.state[0]] }">
                {{ subItem.state[0] }}
              </button>

              <!-- 异常按钮 -->
              <button
                class="state"
                @click="errorButtonClick(item.barId, subItem.id)"
                :disabled="subItem.isShowAddButton"
                :style="{ backgroundColor: buttonBgcMap[subItem.state[1]] }">
                {{ subItem.state[1] }}
              </button>

              <!-- 添加按钮 -->
              <button
                class="state"
                v-show="subItem.isShowAddButton"
                @click="addClick"
                :style="{ backgroundColor: buttonBgcMap['添加'] }">
                添加
              </button>
            </view>
          </view>
          <!--  -->
        </view>
      </scroll-view>
    </view>
  </view>
</template>
<script>
  export default {
    name: 'yhuNavigation',
    props: {
      scPassingArray: {
        type: Array,
        required: true
      }
    },
    data() {
      return {
        scActiveIndex: 0,
        scDataList: [], //数据
        scContentScrollTop: 0, // 内容栏滚动位置
        ScContentHeight: 0, // 内容栏高度
        isSidebarClick: false, // 是否通过点击侧边栏触发滚动事件
        buttonBgcMap: {
          异常: '#FF5252',
          添加: '#1484E8',
          正常: '#25BE00'
        }
      }
    },
    created() {
      this.scDataList = [...this.scPassingArray]
    },
    mounted() {
      this.calculateContentHeight()
    },
    methods: {
      calculateContentHeight() {
        this.ScContentHeight =
          this.scDataList.map((item) => item.scContentData.length).reduce((total, length) => total + length, 0) * 30 +
          this.scDataList.length * 40
      },
      toggleActive(index) {
        this.isSidebarClick = true
        this.scActiveIndex = index
        console.log('this.scDataList.slice(0, index)', this.scDataList.slice(0, index))
        console.log(
          'this.scDataList.slice(0, index).map((item) => item.scContentData.length)',
          this.scDataList.slice(0, index).map((item) => item.scContentData.length)
        )

        this.scContentScrollTop =
          this.scDataList
            .slice(0, index)
            .map((item) => item.scContentData.length)
            .reduce((total, length) => total + length, 0) *
            41 +
          this.scDataList.slice(0, index).length * 41
      },
      ScHandleContentScroll(event) {
        // 通过点击侧边栏触发的滚动事件,不执行后续的处理
        if (this.isSidebarClick) {
          this.isSidebarClick = false
          return
        }
        const scrollTop = event.detail.scrollTop
        let ScAccumulatedHeight = 0
        let index = 0
        for (let i = 0; i < this.scDataList.length; i++) {
          const ScitemHeight = this.scDataList[i].scContentData.length * 30 + 40
          if (scrollTop >= ScAccumulatedHeight && scrollTop < ScAccumulatedHeight + ScitemHeight) {
            index = i
            break
          }
          ScAccumulatedHeight += ScitemHeight
        }
        this.scActiveIndex = index
      },

      // 异常按钮点击
      errorButtonClick(itemBarId, subItemId) {
        this.$emit('changeIsShowAddButton', { itemBarId, subItemId })
        // this.isShowAddButton = true
        // console.log('isShowAddButton', this.isShowAddButton)
      },

      //   点击添加按钮
      addClick() {
        console.log('点击了添加按钮!!')
      }
    }
  }
</script>

<style>
  /deep/.uni-scroll-view::-webkit-scrollbar {
    display: none;
    width: 0 !important;
    height: 0 !important;
    overflow: auto !important;
    appearance: auto !important;
    background: transparent;
  }
  .sc-tabs {
    display: flex;
    width: 100%;
    height: 100vh;
    /* margin-top: -5px; */
    border-top: 1px solid #eeeeee;
  }
  .menu-aside-tab-box {
    width: 22%;

    /* width: 88px; */
    height: 100%;
  }
  .menu-aside-tab {
    /* width: 20vh; */
    width: 88px;
    height: 100vh;
    background-color: transparent;
  }
  .aside-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 40px;
    font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
    font-size: 13px;
    font-weight: normal;
    line-height: 18px;
    text-align: center;
  }
  .aside-active {
    position: relative;
    width: 100%;
    height: 40px;
    font-size: 15px;
    font-weight: 600;
    line-height: 40px;
    color: #3c9cff;
    background-color: #ffffff;
  }
  .aside-active-beforecontent {
    position: absolute;
    width: 3px;
    background-color: #008bff;
  }
  .aside-line {
    font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;

    /* width: 95%; */

    /* height: 18px; */

    font-size: 13px;
    font-weight: normal;
    line-height: 18px;
    color: #333333;
  }
  .scContent-box {
    /* width: 80vh; */
    flex: 1;
    height: 100vh;
  }
  .scContent {
    width: 100%;
    height: 100%;
  }
  .content-bar {
    /* padding: 0px 60px; */
    padding-left: 12px;

    /* padding-bottom: 10px; */
    background: #ffffff;
  }
  .content-bar-item {
    display: flex;
    justify-content: space-between;
    width: 96%;
    height: 41px;
    padding-top: 5px;

    /* position: relative; */

    line-height: 30px;
    border-bottom: 1px solid #eeeeee;
    /* border: 1px solid red; */
  }
  .bar-title {
    display: flex;
    align-items: center;

    /* width: 300px; */
    width: 100%;
    height: 40px;
    font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
    font-size: 14px;
    font-weight: 600;
    line-height: 10px;
    color: #333333;
  }
  .br-title-line {
    width: 8px;
    height: 8px;
    margin-right: 6px;
    border: 2px solid #3c9cff;
    border-radius: 4px;
  }
  .line {
    width: calc(100% - 11px);
    height: 1px;
    background: #eeeeee;
  }
  .stateBox {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    width: 90px;
    height: 41px;
    padding-top: 3px;

    /* border: 1px solid red; */
    overflow: hidden;
  }
  .state {
    width: 40px;
    height: 22px;
    padding: 0 6px;
    font-family: Alibaba-PuHuiTi, Alibaba-PuHuiTi;
    font-size: 14px;
    font-weight: normal;
    line-height: 22px;
    color: #ffffff;
    text-align: center;
    border-radius: 2px;
  }
</style>
相关推荐
吃杠碰小鸡36 分钟前
commitlint校验git提交信息
前端
虾球xz1 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇1 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒1 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员2 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐2 小时前
前端图像处理(一)
前端
程序猿阿伟2 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒2 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪2 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背2 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript