<scroll-view style="height:500rpx"
                           scroll-y="true"
                           scroll-with-animation="true"
                           scroll-into-view="bottomView{{selectedObj[currentTab.value][1].value}}">
                <view wx:if="{{item.label}}"
                      wx:for="{{ selectedObj[currentTab.value][0].children }}"
                      wx:for-item="item"
                      wx:for-index="index"
                      wx:key="index"
                      bindtap="handleMenuR"
                      data-params="{{ item }}"
                      class="content-category-item {{item.value === selectedObj[currentTab.value][1].value?'active':''}}">
                  <view id="bottomView{{item.value}}"
                        wx:if="{{item.value === selectedObj[currentTab.value][1].value}}">
                    <view> {{item.label || '-'}}</view>
                  </view>
                  <view wx:else> {{item.label || '-'}}</view>
                </view>
              </scroll-view>

重点:scroll-into-view(值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素,如bottomView111)

style="height:500rpx" 高度必须指定,

scroll-y="true"  Y轴   scroll-with-animation="true" 动画过渡

 下面是三层筛选下拉框,(基于小程序框架wepy)

1,新建文件TreeSelect3.wpy,把下面代码复制到这个文件

<template>
  <view class="xx-tree-select">
    <view wx:for="{{tabList}}"
          wx:for-item="item"
          wx:for-index="index"
          wx:key="index"
          class="xx-select-item"
          bind:tap="handleTab"
          data-params="{{item}}"
          data-index="{{index}}">
      <text class="{{currentTabIdx === index ? 'active' : ''}} txt_wid">{{ item.label }}</text>
      <image wx:if="{{ currentTabIdx !== index }}"
             class="default"
             src="https://cdn.ylnhome.com/tuike/triangle.png"></image>
      <image wx:else
             src="https://cdn.ylnhome.com/tuike/triangle_act.png"></image>
    </view>
    <!-- 标签选择弹出框 -->
    <!-- 注: 这样布局目的是为了避免 `catchtouchmove` 属性影响子元素滚动 -->
    <view wx:if="{{ showPopup }}"
          class="xx-wrap {{noSearchbar ? 'no-searchbar' : ''}}">
      <view class="xx-list-wrap"
            bindtap="handleShade"
            catchtouchmove="catchTouch"></view>
      <view class="tree-select-wrap">
        <view class="goods-tree-select">
          <view class="tree-select-menu">
            <scroll-view style="height:500rpx"
                         scroll-with-animation="true"
                         scroll-into-view="bottomView{{selectedObj[currentTab.value][0].value}}"
                         scroll-y="true">
              <view bindtap="handleMenuL"
                    data-params="{{ {value: null, label: ''} }}"
                    class="tree-select-menu-item {{!selectedObj[currentTab.value][0].value ? 'active' : ''}}">
                <view class="tree-select-menu-item-text">{{setAllName || '全部'}}</view>
              </view>
              <view wx:if="{{item.label}}"
                    wx:for="{{ currentTab.children || [] }}"
                    wx:for-item="item"
                    wx:for-index="index"
                    wx:key="index"
                    bindtap="handleMenuL"
                    data-params="{{ item }}"
                    class="tree-select-menu-item {{item.value === selectedObj[currentTab.value][0].value ? 'active' : ''}}">
                <view id="bottomView{{item.value}}"
                      class="tree-select-menu-item"
                      wx:if="{{item.value === selectedObj[currentTab.value][0].value}}">{{item.label || '-'}}</view>
                <view wx:else>{{item.label || '-'}}</view>

              </view>
            </scroll-view>
          </view>

          <view wx:if="{{selectedObj[currentTab.value][0].children}}"
                class="tree-select-content">
            <view class="content-category">
              <scroll-view style="height:500rpx"
                           scroll-y="true"
                           scroll-with-animation="true"
                           scroll-into-view="bottomView{{selectedObj[currentTab.value][1].value}}">
                <view wx:if="{{item.label}}"
                      wx:for="{{ selectedObj[currentTab.value][0].children }}"
                      wx:for-item="item"
                      wx:for-index="index"
                      wx:key="index"
                      bindtap="handleMenuR"
                      data-params="{{ item }}"
                      class="content-category-item {{item.value === selectedObj[currentTab.value][1].value?'active':''}}">
                  <view id="bottomView{{item.value}}"
                        wx:if="{{item.value === selectedObj[currentTab.value][1].value}}">
                    <view> {{item.label || '-'}}</view>
                  </view>
                  <view wx:else> {{item.label || '-'}}</view>
                </view>
              </scroll-view>
            </view>
          </view>

          <view wx:if="{{selectedObj[currentTab.value][1].children}}"
                class="tree-select-content tree-select-content1">
            <view class="content-category">
              <scroll-view style="height:500rpx"
                           scroll-y="true"
                           scroll-with-animation="true"
                           scroll-into-view="bottomView{{selectedObj[currentTab.value][2].value}}">
                <view class="content-category-item {{ selectedMenu.length < 3 ? 'active' : '' }}"
                      bindtap="handleMenuR"
                      data-params="{{ selectedMenu[1] }}">
                  全部
                </view>
                <view wx:if="{{item.label}}"
                      wx:for="{{ selectedObj[currentTab.value][1].children }}"
                      wx:for-item="item"
                      wx:for-index="index"
                      wx:key="index"
                      bindtap="handleMenuR1"
                      data-params="{{ item }}"
                      class="content-category-item {{item.value === selectedObj[currentTab.value][2].value ? 'active' : ''}}">
                  <view id="bottomView{{item.value}}"
                        wx:if="{{item.value === selectedObj[currentTab.value][2].value}}"> {{item.label || '-'}}</view>
                  <view wx:else> {{item.label || '-'}}</view>
                </view>
              </scroll-view>
            </view>
          </view>

        </view>
      </view>
    </view>
  </view>
</template>


<script>
import wepy from 'wepy';
import axios from '@/utils/http';
import { myLogin } from '@/utils/userLogin.js';

export default class XxTreeSelect3 extends wepy.component {
  config = {}

  components = {}

  watch = {
    dataList () {
      if (this.isGetData) return;

      this.isGetData = true;

      this.$apply();
      this._getList();
    }
  }

  props = {
    noSearchbar: Boolean,
    currentObj: Object,
    dataList: Array,
    chenpin: {
      type: Boolean,
      default: false
    }
  }

  mixins = []

  data = {
    isGetData: false,
    currentTabIdx: -1,
    currentTab: {},
    selectedObj: {}, // 每个tabbar当前已选
    selectedMenu: [], // 当前已选
    tabList: [],
    tabListDeep: [],
    showPopup: false, // 选择下拉框
  }

  computed = {
    setAllName () {
      let name = '';
      if (this.currentTab.value === 'sort') {
        return '综合排序'
      } else {
        // 品类
        if (this.selectedMenu.length && (this.currentTab.value === 'category')) {
          name = '品类';
        }
        // 系列
        if (this.selectedMenu.length && (this.currentTab.value === 'series')) {
          name = '系列';
        }
        // 风格
        if (this.selectedMenu.length && (this.currentTab.value === 'style')) {
          name = '风格';
        }
        if (this.selectedMenu.length && (this.currentTab.value === 'sort')) {
          name = '排序';
        }
        return '全部' + name;

      }
    }
  }

  methods = {
    handleTab (data) {
      let params = data.currentTarget.dataset.params;
      let paramsIdx = data.currentTarget.dataset.index;
      this.currentTab = params;
      if (this.currentTabIdx !== paramsIdx) {
        // this.currentTab = params;
        this.currentTabIdx = paramsIdx;
        this.showPopup = true;
      } else {
        // this.currentTab = {};
        this.currentTabIdx = -1;
        this.showPopup = false;
      }

      this.$apply();
      this.$emit('handle-tab', params);
    },
    handleMenuL (data) {
      let params = data.currentTarget.dataset.params;
      this.selectedMenu = [params];
      this.selectedObj[this.currentTab.value] = this.selectedMenu;
      this.tabList.map((item, index) => {
        if (item.value === this.currentTab.value) {
          item.label = params.label || this.tabListDeep[index].label;
        }
      });

      this.$apply();
      this.showPopup = false;//点一下回弹
      this.currentTabIdx = -1;//点一下回弹
      this.$emit('handle-menu', this.selectedObj);
    },
    handleMenuR (data) {
      let params = data.currentTarget.dataset.params;

      this.selectedMenu.length = 2;
      this.selectedMenu[1] = params;
      this.selectedObj[this.currentTab.value] = this.selectedMenu;
      this.tabList.map((item, index) => {
        if (item.value === this.currentTab.value) {
          item.label = params.label || this.tabListDeep[index].label;
        }
      });

      this.$apply();
      this.showPopup = false;//点一下回弹
      this.currentTabIdx = -1;//点一下回弹
      this.$emit('handle-menu', this.selectedObj);
    },
    handleMenuR1 (data) {
      let params = data.currentTarget.dataset.params;

      this.selectedMenu[2] = params;
      this.selectedObj[this.currentTab.value] = this.selectedMenu;
      this.tabList.map((item, index) => {
        if (item.value === this.currentTab.value) {
          item.label = params.label || this.tabListDeep[index].label;
        }
      });

      this.$apply();
      this.showPopup = false;
      this.currentTabIdx = -1;//点一下回弹
      this.$emit('handle-menu', this.selectedObj);
    },

    // 点击框遮罩层
    handleShade () {
      this.showPopup = false;
      // this.currentTab = {};
      this.currentTabIdx = -1;

      this.$apply();
    },

    // 阻止冒泡
    handleContent (evt) {
      return;
    },
    // 阻止滚动穿透
    catchTouch () {
      return;
    },
  }

  events = {}

  /* 生命周期 */
  onLoad () {
    // this._getList();
  }

  /* 函数 */
  _getList () {
    if (!this.dataList) return;

    this.tabList = this.dataList;

    this.tabListDeep = JSON.parse(JSON.stringify(this.dataList));

    if (this.currentObj && JSON.stringify(this.currentObj) !== '{}') {
      this.selectedObj = this.currentObj;
      this.currentTab.value = Object.keys(this.currentObj)[0];
      this.selectedMenu = Object.values(this.currentObj)[0];
      this._setList();
      setTimeout(() => {
        this._setList();
      }, 200);
      setTimeout(() => {
        this._setList();
      }, 500);
      setTimeout(() => {
        this._setList();
      }, 1000);
      setTimeout(() => {
        this._setList();
      }, 2000);
    }

    this.$apply();
  }

  _setList () {
    let tabLabel;
    if (this.chenpin) {
      // 从爆款商品进默认选择成品家具
      this.tabLabel = this.selectedMenu[0].label
      this.currentTabIdx = -1;
      this.tabList[0].label = '成品家具'
      //  this.selectedObj[this.currentTab.value] = this.selectedMenu;
    } else {

      this.tabList.map(item => {
        if (item.value === this.currentTab.value) {
          // 改变 tab 名称
          if (!tabLabel) {
            if (this.selectedMenu[1]) {
              tabLabel = this.selectedMenu[1].label
            }
          }
          item.label = tabLabel;

          // console.log('item', item);
          // 设置当前已选路径

          if (item.children) {
            item.children.map(item1 => {
              if (item1.value === this.selectedObj[this.currentTab.value][0].value) {
                if (this.selectedMenu.length > 2) {
                  tabLabel = this.selectedMenu[2].label
                  item.label = tabLabel;
                }
                this.selectedObj[this.currentTab.value][0].children = item1.children;
                this.$apply();
                if (item1.children) {
                  item1.children.map(item2 => {
                    if (item2.value === this.selectedObj[this.currentTab.value][1].value) {
                      this.selectedObj[this.currentTab.value][1].children = item2.children;
                      this.$apply();
                    }
                  })
                }
              }
            })
          }
        }
        if (item.value === Object.keys(this.currentObj)[1]) {
          item.label = Object.values(this.currentObj)[1][0].label;
          this.$apply();
        }
      });
    }
    this.$apply();
  }
}
</script>


<style lang="less" scoped>
.xx-tree-select {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100rpx;
  .xx-select-item {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40%;
    height: 100%;
    text {
      display: block;
      font-size: 26rpx;
      color: #393939;
      margin-right: 10rpx;
      &.active {
        color: #d8b191;
      }
    }
    image {
      width: 20rpx;
      height: 18rpx;
      &.default {
        transform: rotate(180deg);
      }
    }
  }
  .txt_wid {
    max-width: 200rpx;
    overflow: hidden;
    text-overflow: ellipsis; //超出部分以省略号显示
    white-space: nowrap;
  }
  .xx-wrap {
    position: absolute;
    top: 190rpx;
    width: 100%;
    height: 100vh;
    z-index: 999;
    &.no-searchbar {
      top: 100rpx;
    }
    .xx-list-wrap {
      position: absolute;
      top: 0;
      width: 100%;
      height: 100%;
      background-color: #00000066;
    }
    .tree-select-wrap {
      position: absolute;
      top: 0;
      width: 100%;
      height: 500rpx;
      .goods-tree-select {
        display: flex;
        height: 100%;
        background: #fff;
        border-top: 1px solid #f2f2f2;
        .tree-select-menu {
          width: 100%;
          height: 100%;
          // border-right: 1px solid #f2f2f2;
          overflow-y: auto;
          .tree-select-menu-item {
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 80rpx;
            &.active {
              background: #f2f2f2;
              font-weight: bold;
              &::after {
                position: absolute;
                content: '';
                display: block;
                width: 8rpx;
                height: 100%;
                background-color: #dc143c;
                left: 0;
              }
            }
          }
        }
        .tree-select-content {
          width: 100%;
          background: #fff;
          overflow-y: auto;
          border-left: 1px solid #f2f2f2;
          .content-category {
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 100%;
            // padding: 20rpx;
            .content-category-item {
              text-align: center;
              width: 100%;
              height: 80rpx;
              line-height: 80rpx;
              background: #fff;
              &.active {
                background: #f2f2f2;
                font-weight: bold;
              }
            }
          }
          &.tree-select-content1 {
            background-color: #f2f2f2;
            .content-category-item {
              color: #666;
              background-color: #f2f2f2;
              &.active {
                color: #000;
                font-weight: bold;
              }
            }
          }
        }
      }
    }
  }
}
</style>

2.使用

如果我在b.wpy页面使用,那么在b.wpy页面引用并使用

import wepy from 'wepy';
import XxTreeSelect3 from '@/components/tree-select/TreeSelect3';
components = {
    XxTreeSelect3,
  };
  data = {
    tabList: [
      {
        label: '品类',
        value: 'category'
      },
      {
        label: '系列',
        value: 'series'
      },
      {
        label: '风格',
        value: 'style'
      },
      {
        label: '综合排序',
        value: 'sort'
      }
    ],
  chenpin: false,//可不用
   selectedTab: {},
 }
 <template>
        <view>
            <XxTreeSelect3 :dataList.sync="tabList"
                           :chenpin.sync="chenpin"
                           :currentObj.sync="selectedTab"
                           @handle-menu.user="handleMenu">
            </XxTreeSelect3>
         <view>
</template>
     methods = {
 // 选中标签
    handleMenu (data) {
      this.showLoading = true
      this.currentPage = 1;
      this.dataList = [];
      this.selectedTab = data;
      if (this.selectedTab.sort) {
        this.sort = this.selectedTab.sort.length > 0 ? this.selectedTab.sort[0].value : 3
        if (this.selectedTab.sort.length > 0) {
          if (this.selectedTab.sort[0].value) {
            this.sort = this.selectedTab.sort[0].value
          } else {
            this.sort = 3
          }
        } else {
          this.sort = 3
        }
      }
      this.getStoreGoods();
      this.$apply();
    }
}

tabList数组格式

 可以这么组成需要数组格式

  methods = {  
_getGoodsTress (list) {
    if (!list || !list.length) return [];

    return list.map(item => {
      return {
        label: item.content,
        value: item.id,
        children: this._getGoodsTress(item.subCategories)
      }
    })
  }

  getGoodsCategory () {
      axios.get(`/jzx/jzxStoreSupplier/getGoodsCategory`, {
        params: {
          storeId
        }
      }).then(res => {
        if (res && res.length) {
          this.getCategorylist = res
          this.tabList.map((item, index) => {
            if (item.value === 'category') {
              this.tabList[index].children = this._getGoodsTress(res);
            }
          })
          console.log(this.good_category)
          var good_category = this.good_category
          let category = JSON.parse(good_category.category).category;
          if (good_category.type == 123) {
            // 是首页icon跳转进来的
            var that = this
            this.getCategorylist.forEach(item => {

              if (category[0].value == item.id) {
                that.selectedTab.category[0].value = Number(item.id)
                that.selectedTab.category[0].children = item.subCategories
              }
            })
          }
          // 注意selectedTab.category[0].value只能传Number类型。
          console.log(this.selectedTab, '  this.selectedTab2')

        }

        this.$apply();
      }).catch(err => {
        console.log(err);
      });
    })
  };
// 风格列表
  getStyleList () {
    axios.get(`/article/get-style-tag-list`).then(res => {
      if (res) {
        this.tabList.map(item => {
          if (item.value === 'style') {
            item.children = res.map(item1 => {
              return {
                label: item1.name,
                value: item1.id
              }
            });


          }
        })
      }
      var tabList2 = JSON.stringify(this.tabList)
      wx.setStorage({ key: "tabList2", data: tabList2 })


      this.$apply();
    });
  };
  // 排序列表
  getSortList () {
    // axios.get(`/article/get-style-tag-list`).then(res => {
    //   if (res) {
    var res = [{ name: '价格升序', id: 2 }, { name: '价格降序', id: 1 }]
    this.tabList.map(item => {
      if (item.value === 'sort') {
        item.children = res.map(item1 => {
          return {
            label: item1.name,
            value: item1.id
          }
        });
      }
    })

    // }
    this.$apply();
    // });
  };
}

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐