当前位置:首页 > 开发教程 > js/jQuery教程 >

vue实现列表左右联动效果

时间:2022-04-15 12:32 来源:未知 作者:独拥你 收藏

这篇文章主要为大家详细介绍了vue实现列表左右联动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了vue实现列表左右联动效果的具体代码,供大家参考,具体内容如下

先谈需求:左侧为分类列表,点击分类名右侧商品列表会滑动对应分类到顶部;右侧商品列表滑动到某一分类时左侧分类列表对应分类会滑动到顶部高亮显示。

再来说说思路:

1、引用swiper插件,这种方法冲突和不适配可能性太多,会越改越麻烦所以弃用。
2、使用页面滑动scroll事件,引入better-scroll组件。这个较为轻便,可自定义性较大,可以使用。

实现步骤:

1、左右两侧均使用v-for循环列表,使用index来索引目录。JS中使用数组下标来和列表index对应,实现左右互通功能。
2、左右列表都在循环列表的父层增加ref绑定,获取对应的列表滚动,以及对应元素高度,从而根据高度来判断需要滑动的距离。

效果图:

vue实现列表左右联动效果

页面基础代码:

<template>
 <div class="wrap">
  <!-- 顶部搜索 -->
  <div class="topMenu">
   <img class="back_l" @click="goBack" src="./img/backicon@2x.png">
   <div class="section">
    <img class="saleR" src="./img/sub.png">
    <input placeholder="搜索商家和商品" auto-focus @keyup.enter="submitTop"/>
   </div>
   <img class="saleR" @click="goMap" src="./img/citydw.png">
  </div>
  <div class='no_sroll' v-if="navList">
   <aside class="tabNav" ref="l_list">
    <ul>
     <li ref="l_item" class="nav_li" :class="(TabNavList == index)  'checkIn' : ''" :index="index" :id="index" @click="checkNavList(item, index)" v-for="(item, index) in navList" :key="index">
      <img class="imgLi" src="./img/shu@2x.png" v-if="TabNavList == index" />{{item.gcName}}
     </li>
    </ul>
   </aside>
   <!-- 增加浮动层 -->
   <div class="theFixed" :class="(TabNavList == index)  'isFixed' : 'isHide'" v-if="scrollTrue">
    <div class="leftName">{{scrollTrue.gcName}}</div>
    <div class="rightBtn" @click="goTwoClass(scrollTrue)">全部分类<img class="r_img_btn" src="./img/jiantou.png"></div>
   </div>
   <section class="newHeight" ref="r_list">
    <div >
     <div class="proList" v-for="(item, index) in navList" :key="index" ref="good">
      <div class="r_top">
       <div class="leftName">{{item.gcName}}</div>
       <div class="rightBtn" @click="goTwoClass(item)">全部分类<img class="r_img_btn" src="./img/jiantou.png"></div>
      </div>
      <div class="r_cont">
       <div class="cu-items" v-for="(item, index) in (item.childList)" :key="index" @click="goThreeCalss(item)">
        <div class="storeL">
         <img v-if="item.classImg" :src="item.classImg" />
         <img v-else src="../../carManage/img/zwt.png"/>
        </div>
        <div class="text">{{item.gcName}}</div>
       </div>
      </div>
     </div>
    </div>
   </section>
  </div>
 </div>
</template>
<script>
 // import {baseUrl} from '@/common/js/paths'
 import Better from 'better-scroll'
 export default {
  name: 'allStoreClass',
  components: {
   Better
  },
  data () {
   return {
    loadStatus: true,
    bodyHeight: window.innerHeight + 'px',
    storeName: '',
    distance: '',
    positionArea: '',
    positionPoint: {
     lng: '',
     lat: ''
    },
    center: {
     lng: '',
     lat: ''
    },
    zoom: 15,
    index: 0,
    gcName: '',
    gcParentId: '',
    searchBarFixed: false,
    scrollY: 0, // 定义的Y滚动轴及初始值
    TabNavList: 0, // 左右联动取值
    scrollTrue: '', // 右侧吸顶
    navList: [], // 全局列表
    isScroll: false,
    pageIndex: 1,
    pageSize: 20,
    markerPoint: {
     'lng': '',
     'lat': ''
    },
    arr: [0],
    flag: true,
    obj: null,
    show: false,
    ios: /iphone os/g.test(window.navigator.userAgent.toLowerCase())
   }
  },
  computed: {
   // 001
  },
  created () {
   // this.$store.commit('setTopDisplay', false)
   // this.$store.commit('setPageTitle', '分类列表')
   if (this.$store.state.platform === 'app') {
    // eslint-disable-next-line no-undef
    let location = JSON.parse(native.getLocation())
    this.positionPoint.lng = location.longitude
    this.positionPoint.lat = location.latitude
    this.positionArea = location.city
    this.getList()
   } else if (this.$store.state.from === 'bjsh') { // 更改北京石化来源
    this.getList()
   } else {
    this.getPositionJs()
    this.getList()
   }
  },
  mounted () {
   this.$nextTick(() => {
    this._initScroll()
    this._getHeight()
   })
   if (this.$store.state.platform === 'app') {
    // eslint-disable-next-line no-undef
    native.ifShowTitleBarView(false)
   } else if (this.$store.state.platform === 'web') {
    this.$store.commit('setTopDisplay', false)
   }
  },
  methods: {
   goBack () {
    if (this.$store.state.platform === 'app') {
     // eslint-disable-next-line no-undef
     native.goBack()
    } else if (this.$store.state.from === 'hnsh') { // 更改与北京石化交互
     // 河南石化交互
     let params = {
      type: 'turnback',
      index: -1
     }
     this.$bridge.callhandler('phonebridge', params, (data) => {
     })
    } else {
     history.go(-1)
    }
   },
   _initScroll () {
    this.left = new Better(this.$refs.l_list, {
     click: true,
     probeType: 3
    })
    this.rgt = new Better(this.$refs.r_list, {
     probeType: 3,
     click: true
    })
    this.rgt.on('scroll', (res) => {
     if (this.flag) {
      this.scrollY = Math.abs(res.y) + 16 // 页面内有一个16像素的顶部状态栏
      for (let i = 0; i < this.arr.length; i++) {
       if (this.scrollY > this.arr[i] && this.scrollY < this.arr[i + 1]) {
        this.TabNavList = i - 1 // 左右联动取值
        // console.log(this.navList[this.TabNavList].gcName) // 取出元素的gcName
        this.scrollTrue = this.navList[this.TabNavList]
        this.isScroll = true
        // document.getElementById(this.TabNavList).scrollIntoView()
        this.left.scrollToElement(this.$refs.l_list, 100, 0, this.TabNavList * 60)
       }
      }
     }
    })
    this.left.on('scroll', (res) => {
     if (this.flag) {
      this.scrollY = Math.abs(res.y) + 16
      this.left.scrollToElement(this.$refs.l_list[this.TabNavList], 100, 0, 0)
     }
    })
   },
   _getHeight () {
    // // 开始改造
    let rightItems = this.$refs.r_list.getElementsByClassName('proList')
    setTimeout(() => { // 根据betterScroll定义滚动
     console.log(rightItems) // 右侧列表数组内容
     console.log(rightItems.length) // 右侧列表数组长度
     if (rightItems && (rightItems.length > 0)) {
      let height = 0
      this.arr.push(height)
      for (let i = 0; i < rightItems.length; i++) {
       let item = rightItems[i]
       height += item.clientHeight
       this.arr.push(height)
      }
     }
    }, 600)
   },
   getList (e) {
    this.axios.get(`v4/goodsManage/goodsClass`, {
     params: {
      keywords: e || '', // 关键词
      pageNo: this.pageIndex,
      pageSize: this.pageSize
     }
    }).then((res) => {
     if (res.data.isSuccess) {
      // console.log(res.data.resultData)
      this.navList = res.data.resultData
      // this.scrollTrue = res.data.resultData[0]
     } else {
      this.$toast(res.data.message)
     }
    }).catch(err => {
     console.log(err)
     this.$toast('请求失败,请稍后重试')
    })
   },
   getPositionJs () {
    let _this = this
    // eslint-disable-next-line no-undef
    var geolocation = new BMap.Geolocation()
    geolocation.getCurrentPosition(function (r) {
     // eslint-disable-next-line no-undef
     if (this.getStatus() === BMAP_STATUS_SUCCESS) {
      console.log('是否成功定位')
      _this.positionPoint.lng = r.point.lng
      _this.positionPoint.lat = r.point.lat
      _this.positionArea = r.address.city
     } else {
      var info = '未能获取当前地理定位, 请检查手机是否已打开位置服务! ' + '\n' + '失败: ' + this.getStatus()
      alert(info)
     }
    }, {enableHighAccuracy: true})
   },
   getDetails (it) {
    this.show = !this.show
    this.obj = it
   },
   // 顶部搜索
   submitTop (e) {
    console.log(e.target.value)
    let obj = e.target.value
    this.getList(obj)
   },
   // 顶部跳地图
   goMap () {
    this.$router.push({name: 'nearStore', query: {from: 'storeIndex', sortFlag: this.curSort, gcName: this.gcName, gcParentId: this.gcParentId, lat1: this.positionPoint.lat, lon1: this.positionPoint.lng}})
   },
   // 左侧选择TAB
   checkNavList (e, v) {
    console.log(e, v)
    this.gcName = e.gcName
    this.gcParentId = e.gcParentId
    this.flag = false
    this.TabNavList = v // 左右联动取值
    this.rgt.scrollToElement(this.$refs.good[v], 100, 0, 0)
    setTimeout(() => {
     this.flag = true
    }, 100)
    // document.getElementById(v).scrollIntoView()
    // this.searchBarFixed = true
   },
   // 一级分类查看全部
   goTwoClass (e) {
    console.log(e)
    this.$router.push({name: 'classProList', query: {gcName: e.gcName, gcParentId: e.gcId, gcId: ''}})
   },
   // 去二级分类详情
   goThreeCalss (e) {
    console.log(e)
    this.$router.push({name: 'classProList', query: {gcName: e.gcName, gcParentId: '', gcId: e.gcId}})
   },
   mapClick (item) { // item.storeName, item.distance, item.storeWd, item.storeJd
    let lng = item.storeJd
    let lat = item.storeWd
    let name = item.storeName
    if (this.$store.state.platform === 'app') {
     if (typeof (native) !== 'undefined') {
      // eslint-disable-next-line no-undef
      native.daoHangWithLat(lat, lng, name)
     }
    } else if (this.$store.state.from === 'hnsh') {
     let params = {
      startlat: this.positionPoint.lat,
      startlong: this.positionPoint.lng,
      endlat: lat,
      endlong: lng,
      type: 'nav'
     }
     this.$bridge.callhandler('phonebridge', params, (data) => {
     })
    } else {
     location.href = 'https://api.map.baidu.com/markerlocation=' + lat + ',' + lng + '&title=目的位置&content=' + name + '&output=html&hidjhnavigation=1&jhWebView=1'
    }
   },
   mapModalClick (lng, lat, name, distance, address) {
    this.mapModal = true
    this.$router.push({name: 'bdMap', query: {lng: lng, lat: lat, name: name, distance: distance, address: address}})
    /* this.center.lng = lng
    this.center.lat = lat
    this.markerPoint.lng = lng
    this.markerPoint.lat = lat
    this.storeName = name */
    /* var opts = {
     width: 380,
     height: 180,
     opacity: 0.5,
     // eslint-disable-next-line no-undef
     offset: new BMap.Size(0, -30),
     title: '<p style="font-size: 20px;color: #2ca90e;margin:0;margin-bottom: 20px;">这里是内容</p>',
     enableMessage: false
    }
    // eslint-disable-next-line no-undef
    var map = new BMap.Map('canvasMap')
    // eslint-disable-next-line no-undef
    var infoWindow = new BMap.InfoWindow('', opts)
    // eslint-disable-next-line no-undef
    map.openInfoWindow(infoWindow, new BMap.Point('0', '0')) */
    // eslint-disable-next-line no-undef
    map.centerAndZoom(new BMap.Point(lng, lat), 18)
   },
   syncCenterAndZoom (e) {
    const {lng, lat} = e.target.getCenter()
    this.center.lng = lng
    this.center.lat = lat
    this.zoom = e.target.getZoom()
   },
   draw ({el, BMap, map}) {
    const pixel = map.pointToOverlayPixel(new BMap.Point(116.404, 39.915))
    el.style.left = pixel.x - 60 + 'px'
    el.style.top = pixel.y - 20 + 'px'
   },
   destroyed () {
    window.removeEventListener('scroll', this.handleScroll, true)
   }
  }
 }
</script>
<style scoped>
.wrap{ margin: 0 auto; width: 100%;height:100%;overflow:hidden;}
.topMenu{
 width: 100%;
 position: absolute;
 margin: 0 auto;
 padding:7.5px 15px;
 background:#fff;
 z-index:19;
 display: flex;
 justify-content: space-between;
}
.section {
 width:80%;
 height:30px;
 background:rgba(242,242,242,1);
 border-radius:15px;
 display: flex;
 margin-left:15px;
 margin-right:15px;
}
.section input{
 font-size:12px;
 font-weight:400;
 color:rgba(153,153,153,1);
 line-height:20px;
 border: none;
 background:rgba(242,242,242,1);
 outline:none;
}
.back_l{
 width:30px;
 height:30px;
}
.saleR{
 width:30px;
 height:30px;
}
.no_sroll {margin:0 auto; width:100%;height:100%;padding-top:45px; overflow:hidden; position:relative; display:flex;}
.main { display: -webkit-flex; display: flex; flex-flow: column nowrap;justify-content: center;align-items: center; height: 100%;text-align: center;margin-bottom: 20px;}
.top_top { margin-top:-50px; position:relative; z-index:999;}
.marginTop{margin-top:45px;}
.goback {position: absolute; left: 0; top: 0; width: .9rem; padding-left: .3rem; text-align: left;}
.newHeight {display:block; overflow: hidden; background:#fff; position:relative; width:75%;padding:0 10px;overflow-y:scroll;overflow-x:hidden;-webkit-overflow-scrolling: touch;}
.newHeight .cu-items { position: relative; display: flex; float:left; flex-direction:column; align-items: center; width:30%; height:110px; margin-left: 4.5%; margin-bottom:10px;}
.newHeight .cu-items:nth-of-type(3n-2) { margin-left:0;}
.cu-items .storeL { width: 80px; height: 80px; position: relative; border-radius: 4px; }
.cu-items .storeL img { width: 80px; height: 80px;}
.cu-items .text {font-size:14px; line-height:18px; margin-top:5px; color:#666;}
.newHeight .proList { width:100%; display:flex; flex-direction:column; position:relative;}
.newHeight .proList .r_top { height:60px;display:flex;justify-content:space-between;align-items:center;}
.newHeight .proList .r_top .leftName { line-height:60px; font-size:16px; text-align:left; color:#666; margin-left:10px;}
.newHeight .proList .r_top .rightBtn {font-size:12px;line-height:60px;color:#2CBF64;}
.newHeight .proList .r_top .rightBtn .r_img_btn {width:11px;height:11px;margin-left:5px;transform:rotate(270deg);}
.theFixed {height:60px;display:flex;justify-content:space-between;align-items:center;}
.theFixed .rightBtn {font-size:12px;line-height:60px;color:#2CBF64;}
.theFixed .rightBtn .r_img_btn {width:11px;height:11px;margin-left:5px;transform:rotate(270deg);}
.theFixed .leftName {line-height:60px; font-size:16px; text-align:left; color:#666; margin-left:10px;}

.tabNav { display: block;width:25%; background:#F5F5F2;overflow: hidden; position:relative; overflow-y:scroll; overflow-x:hidden; -webkit-overflow-scrolling: touch;}
.tabNav::-webkit-scrollbar { display:none;}
.tabNav::scrollbar { display:nonel}
.tabNav .nav_list { display:flex; width:100%;}
.tabNav .nav_li { font-size:16px; line-height:20px; color:#666; text-align:center; height: 60px; width:100%; flex-shrink: 0; position:relative; display: flex; justify-content: center; align-items: center;}
.tabNav .nav_li .imgLi { height:16px; position: absolute; left:0; top: 22px;}
.checkIn { color:#2CBF64!important; background:#fff!important; font-weight:bold;}
.isFixed {
 height:60px;
 line-height:60px;
 font-size:16px;
 text-align:left;
 color:#666;
 position:fixed;
 width:70%;
 left:27%;
 background: #fff;
 z-index: 19;
}
.isHide {
 position: fixed;
 height:60px;
 line-height:60px;
 font-size:16px;
 text-align:left;
 color:#666;
 width:70%;
 left:27%;
 background: #fff;
 z-index: 19;
}
</style>
<style>
 .BMap_cpyCtrl { display: none; }
 .anchorBL { display: none; }
 .BMap_noprint.anchorBL { display: block; bottom: 259px!important; }
 .BMap_stdMpCtrl { display: block; bottom: 269px!important; }
 .BMap_pop { position: absolute;}
</style>

备注:代码做了二期优化

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持源码搜藏网。


下一篇:没有了

js/jQuery教程阅读排行

最新文章