This article has shared with you the specific code for Vue to realize sliding and scrolling effects for your reference. The specific content is as follows
The panel sliding effect, the parent component is resultPanel, and the child component is resultOption, which simulates the writing of the Select component in the iView.
<template> <div v-if="visiable"> <div class="transparent" :class="{active:resultPanelStatus==='top'}"></div> <div class="mapbox-result" ref="resultPanel" style="z-index: 101;" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd" :style="slideEffect" > <div class="mapbox-result-content"> <a class="mapbox-result-close" v-if="closable" @click="close"></a> <div class="mapbox-result-header"> <slot name="header"> <div class="mapbox-result-header-title">Found in total【{{header}}】Related{{total}}result</div> </slot> </div> <div class="mapbox-result-body" ref="resultBody" > <result-option ref="option" v-for="(item, index) in data" :index="index+1" :name="" :meter="?:0" :floor-name="" :key="index" v-show="visiable" @on-click-gohere="handleNavigate(index)" @on-click-item="focusResultOnMap(index)" ></result-option> </div> </div> </div> </div> </template> <script> import resultOption from './resultOption'; export default { name: 'result-panel', components: {resultOption}, props: { header: { type: String }, // value: { // type: Boolean, // default: true // }, closable: { type: Boolean, default: true }, data: { type: Array, default: [] } }, data() { return { // visiable: true, resultPanelStatus: 'normal', //'normal'、'top' cloneData: (), startY: 0, // Start touching the point on the screen endY: 0, // The point leaving the screen moveY: 0, // Distance when sliding disY: 0, // Moving distance slideEffect: '' //Sliding effect } }, mounted() { // this.$ = `${ - 60}px`; // this.$ = 'hidden'; }, computed: { total() { return ; }, defaultHeight() { return > 3 ? 240 : * 60 + 60 // When the result is greater than 3, only three are displayed by default }, visiable() { = 'normal'; = `transform: translateY(-${}px); transition: all .5s`; return this.$; } }, methods: { /** * Finger touches the screen */ onTouchStart(ev) { ev = ev || event; // (); if ( === 1) { = [0].clientY; } }, /** * Finger sliding */ onTouchMove(ev) { ev = ev || event; (": ", ); // (); if ( === 1) { let resultPanel = this.$; = [0].clientY; = - ; if ( < 0 && - + > -resultPanel && === 'normal') { //Swipe up = `transform: translateY(${- + }px); transition: all 0s;`; //The content appears as the content slides on the panel this.$ = 'all .5s'; this.$ = `${this.$ - 60}px`; } else if ( === 'top' && < 0) { (); } else if ( > 0 && === 'top') { //Swipe down/*When the finger slides down, if the start point of the slide is not in the non-content area and the scrollTop is not 0, it is scrolling, otherwise the panel will slide with the finger and hide the scrollbar to prevent the data from being scrolled during the slide*/ if (this.$ > 0 && !== ("mapbox-result-header")[0]) { (); } else { = `transform: translateY(${-resultPanel + }px); transition: all 0s`; this.$ = 'hidden'; } //When in normal state, fingers slide down, then slide down } else if ( > 0 && === 'normal') { = `transform: translateY(${- + }px); transition: all 0s`; } } }, /** * Leave the screen */ onTouchEnd(ev) { ev = ev || event; // (); if ( === 1) { = [0].clientY; = - ; if ( > 0 && === 'top') { //Swipe down /*When the finger slides down, if the start point of the slide is not in the non-content area and the scrollTop is not 0, it is scrolling, otherwise the panel will slide to the default position*/ if (this.$ > 0 && !== ("mapbox-result-header")[0]) { (); } else { (); } // When the finger leaves, a scroll bar appears. It has solved the problem that the scroll bar will not slide when the content is first sliding. } else if ( < 0 && === 'normal') { //Swipe up (); (); } else if ( < 0 && === 'top') { (); } else if ( > 0 && === 'normal') { (); //Slide in normal state, fingers leave the screen, return to normal state } } }, // When reaching the default height, set the status to normal state, and hide the scrollbar and set scrollTop 0 to avoid the previous content being hidden normal() { // this.$ = 'hidden'; = `transform: translateY(${-}px); transition: all .5s;`; = 'normal'; this.$ = 0; }, top() { = 'transform: translateY(-100%); transition: all .5s;'; = 'top'; }, move() { // this.$ = `${- + }px`; this.$ = 'auto'; }, scroll() { this.$ = 'auto'; }, close(ev) { // The click event will conflict with the touchstart event //When the panel is in the highest state and is closed, return to normal height state to avoid the next time it is open to the highest point (); // this.$ = 0; // this.$ = 'hidden'; this.$ = false; this.$emit('on-cancel'); }, handleNavigate(_index) { // this.$emit("on-item-click", (([_index])), _index); //This is the element of the row, and the index this.$emit("on-click-gohere", _index); // This is to get the index }, focusResultOnMap(_index) { this.$emit("on-click-item", _index); // This is to get the index }, // deepCopy deepCopy(data) { const t = (data); let o; if (t === 'array') { o = []; } else if (t === 'object') { o = {}; } else { return data; } if (t === 'array') { for (let i = 0; i < ; i++) { ((data[i])); } } else if (t === 'object') { for (let i in data) { o[i] = (data[i]); } } return o; }, typeOf(obj) { const toString = ; const map = { '[object Boolean]': 'boolean', '[object Number]': 'number', '[object String]': 'string', '[object Function]': 'function', '[object Array]': 'array', '[object Date]': 'date', '[object RegExp]': 'regExp', '[object Undefined]': 'undefined', '[object Null]': 'null', '[object Object]': 'object' }; return map[(obj)]; } } } </script> <style type="text/less" scoped> //scoped means that this style can only be used for the current component .transparent { bottom: 0; left: 0; position: absolute; right: 0; top: 0; background-color: rgba(0, 0, 0, 0.3); opacity: 0; transition: opacity .3s; z-index: -1000000000; } . { opacity: 1; z-index: 0; } .mapbox-result { height: calc(100% - 2.8vw); background: #fff; position: absolute; font-family: PingFangSC-Regular; font-size: 12px; color: #4A4A4A; bottom: 0; width: 94.4vw; margin: 0 2.8vw; outline: 0; overflow: auto; box-sizing: border-box; top: 100%; overflow: hidden; border-radius: 5px 5px 0 0; box-shadow: 0 0 12px 0px rgba(153, 153, 153, 0.25); } .mapbox-result-content { position: relative; background-color: #fff; border: 0; } .mapbox-result-header { padding: 24px 10vw; line-height: 1; text-align: center; } .mapbox-result-header-title { white-space: nowrap; } .mapbox-result-close { position: absolute; width: 16px; height: 16px; background: url('../../assets/close-black@'); background-size: 100% 100%; background-repeat: no-repeat; right: 5.6vw; top: 22px } .mapbox-result-body { height: auto; } </style>
<template> <div class="mapbox-result-option"> <div class="mapbox-result-option-content"> <!--<button class="mapbox-btn mapbox-btn-primary mapbox-result-option-btn mapbox-btn-right" @click="handleClick"> <i class="mapbox-result-option-icon"></i> </button>--> <a class="mapbox-result-option-nav" @click="handleClick"></a> <div class="mapbox-result-option-item" @click="resultItemClick"> <div class="mapbox-result-option-item-main"> <p class="mapbox-result-option-title"> <span class="mapbox-result-option-order">{{index}}</span> {{name}} </p> <p class="mapbox-result-option-note"> {{floorName}},Distance from the current location{{meter}}rice </p> </div> </div> </div> </div> </template> <script> export default { name: 'result-option', props: { value: { type: Boolean, default: true }, index: { type: Number }, name: { type: String }, meter: { type: Number }, floorName: { type: String } }, data() { return { } }, methods: { handleClick() { this.$emit("on-click-gohere"); }, resultItemClick() { this.$emit("on-click-item"); } } } </script> <style type="text/less" scoped> .mapbox-result-option { height: 60px; width: calc(100% - 8.3vw); display: block; border-bottom: 1px solid #dbd6d6; box-sizing: border-box; margin: 0 auto; overflow: hidden; } .mapbox-result-option-content { padding: 0; margin: 0; font-family: PingFangSC-Regular; font-size: 12px; color: #4A4A4A; position: relative; display: inline-block; width: 100%; } .mapbox-btn { display: inline-block; margin-bottom: 0; font-weight: 400; text-align: center; vertical-align: middle; touch-action: manipulation; background-image: none; border: 1px solid transparent; white-space: nowrap; line-height: 1.5; } .mapbox-result-option-btn { position: relative; border-radius: 50%; height: 30px; width: 8.3vw; padding: 0; outline: none; margin: 15px 4.2vw 15px 0; z-index: 1; /*Avoid text blocking the button*/ } .mapbox-btn-primary { color: #fff; background-color: #2A70FE; border-color: #2A70FE; } .mapbox-btn-right { float: right; margin-right: 4.2vw; } .mapbox-result-option-icon { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-size: 100% 100%; width: 2.9vw; height: 18px; background: url("../../../static/image/icon_nav3.png") no-repeat; } .mapbox-result-option-nav { background: url("../../assets/btn_route_planning_normal.png"); width: 30px; height: 30px; background-size: 100% 100%; background-repeat: no-repeat; float: right; display: block; position: absolute; right: 0; top: 15px; z-index: 1; } .mapbox-result-option-item { display: block; position: relative; margin: 10px auto; } .mapbox-result-option-item-main { display: block; vertical-align: middle; font-size: 16px; color: #4A4A4A; } .mapbox-result-option-title { font: 15px/21px PingFangSC-Regular; position: relative; } .mapbox-result-option-order { font: 15px/21px PingFangSC-Medium; position: relative; margin-left: 1.9vw; margin-right: 4.6vw; } .mapbox-result-option-note { font: 12px/16px PingFangSC-Regular; color: #9B9B9B; white-space: normal; position: relative; margin-left: 12.5vw; margin-top: 3px; } </style>
ev = ev || event, this is written to be compatible with various browsers. In Firefox browser, the event-bound function obtains the event itself, which is passed into the function, while in browsers such as IE, the function itself can be obtained through or event.
Resolve the conflict between touchstart and click events: Remove the (); in touchstart, touchmove and touchend events; it will prevent the triggering of the subsequent events; but removing the preventDefault event will cause problems. Opening this web page in the WeChat web page and sliding down will trigger the WeChat drop-down event, but applying this component in the App will not have this problem. There is a way to solve the problem that the WeChat drop-down refresh event is triggered by sliding down on a WeChat web page, which is to use setTimeout.
setTimeout(() => {(); }, 200);
This way, after the click event occurs, the subsequent default event can be triggered.
Scroll Event: The scroll event is triggered in touchmove and touchend, and the slide event of the panel and the scroll event are not performed at the same time.
When sliding up, determine the panel status. If it is in the top state, the scroll event will be triggered. When the finger leaves the panel, it will still be a scroll event; if it is in the normal state, it will be a slide panel. When the finger leaves the panel, set the panel to the top state and set the scroll bar of the content to be visible; when the initial panel slides to the top, the second time the panel is sliding upwards, the scroll bar will be touched, and the content can be scrolled;
When sliding, determine whether it is in the top state. If it is in the top state, when the scrollTop in the content area is greater than 0 and the initial position of the finger is in the content area, then scrolling is triggered, otherwise the panel will slide down; when sliding, it can be done without triggering any event, or it can slide down, but when the finger leaves the screen, it returns to the default position. The latter method is used here.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.