vue實現列表左右聯(lián)動效果
本文實例為大家分享了vue實現列表左右聯(lián)動效果的具體代碼,供大家參考,具體內容如下
先談需求:左側為分類列表,點擊分類名右側商品列表會滑動對應分類到頂部;右側商品列表滑動到某一分類時左側分類列表對應分類會滑動到頂部高亮顯示。
再來說說思路:
1、引用swiper插件,這種方法沖突和不適配可能性太多,會越改越麻煩所以棄用。
2、使用頁面滑動scroll事件,引入better-scroll組件。這個較為輕便,可自定義性較大,可以使用。
實現步驟:
1、左右兩側均使用v-for循環(huán)列表,使用index來索引目錄。JS中使用數組下標來和列表index對應,實現左右互通功能。
2、左右列表都在循環(huán)列表的父層增加ref綁定,獲取對應的列表滾動,以及對應元素高度,從而根據高度來判斷需要滑動的距離。
效果圖:
頁面基礎代碼:
<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" alt=""/> ? ? ? ? ? ? ? ? ? <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, // 左右聯(lián)動取值 ? ? ? ? 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像素的頂部狀態(tài)欄 ? ? ? ? ? ? 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 // 左右聯(lián)動取值 ? ? ? ? ? ? ? ? // 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 // 左右聯(lián)動取值 ? ? ? ? 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. + 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>
備注:代碼做了二期優(yōu)化
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- vue省市區(qū)三聯(lián)動下拉選擇組件的實現
- vue elementUI使用tabs與導航欄聯(lián)動
- vue基于mint-ui的城市選擇3級聯(lián)動的示例
- vue基于mint-ui實現城市選擇三級聯(lián)動
- 詳解Vue、element-ui、axios實現省市區(qū)三級聯(lián)動
- VUE2 前端實現 靜態(tài)二級省市聯(lián)動選擇select的示例
- Vue.js組件tree實現省市多級聯(lián)動
- vue mint-ui 實現省市區(qū)街道4級聯(lián)動示例(仿淘寶京東收貨地址4級聯(lián)動)
- Vue實現左右菜單聯(lián)動實現代碼
- vue左右側聯(lián)動滾動的實現代碼
相關文章
antd form表單使用setFildesValue 賦值失效的解決
這篇文章主要介紹了antd form表單使用setFildesValue 賦值失效的解決方案,具有很好的參考價值,希望對大家有所幫助。2023-04-04關于iview和elementUI組件樣式覆蓋無效問題及解決
這篇文章主要介紹了關于iview和elementUI組件樣式覆蓋無效問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09VUE2.0+Element-UI+Echarts封裝的組件實例
下面小編就為大家分享一篇VUE2.0+Element-UI+Echarts封裝的組件實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03關于element el-input的autofocus失效的問題及解決
這篇文章主要介紹了關于element el-input的autofocus失效的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12