Use vue to create an instance code for probe, slide, and stack components.

Source: Internet
Author: User

Use vue to create an instance code for probe, slide, and stack components.

As follows:

 

Preface

Hi, I think you should be familiar with all the procedures (after all, there are many sisters). The slide sign on the top plays a key role in exploring the stacked slide component, next let's take a look at how to use vue to write a probe stack component.

I. Function Analysis

In simple use, the probe will find that the stack sliding function is very simple. The following figure is a summary:

 

The basic functions are as follows:

  • Image Stack
  • Sliding of the first image
  • Slide out after the condition is successful, and rebound after the condition fails
  • Slide out and stack the next image to the top.
  • Experience Optimization
  • Based on different touch points, the first image has different angle offsets during sliding.
  • Determines whether the offset area is successfully slid out.

II. Specific implementation

With the summarized functions, our idea of implementing components will be clearer.

1. Stack Effect

Stack image effects have a large number of instances on the Internet, and the implementation method is similar, mainly by setting the perspective and perspective-origin on the parent layer to realize the perspective of the Child layer, the sub-layer can simulate the stacking effect by setting the value of the translate3d Z axis. The Code is as follows:

// Stack the image dom <! -- Opacity: 0 hide the stack-item level we don't want to see --> <! -- Z-index:-1 adjust the stack-item level "--> <ul class =" stack "> <li class =" stack-item "style =" transform: translate3d (0px, 0px, 0px); opacity: 1; z-index: 10; ">  </li> <li class = "stack-item" style = "transform: translate3d (0px, 0px, -60px); opacity: 1; z-index: 1 ">  </li> <li class = "stack-item" style = "transform: translate3d (0px, 0px, -120px); opacity: 1; z-index: 1 ">  </li> <li class = "stack-item" style = "transform: translate3d (0px, 0px, -180px); opacity: 0; z-index: -1 ">  </li> <li class = "stack-item" style = "transform: translate3d (0px, 0px, -180px); opacity: 0; z-index:-1 ">  </li> </ul> <style>. stack {width: 100%; height: 100%; position: relative; perspective: 1000px; // sub-element line of sight perspective-origin: 50% 150%; // sub-element perspective position-webkit-perspective: 1000px;-webkit-perspective-origin: 50% 150%; margin: 0; padding: 0 ;}. stack-item {background: # fff; height: 100%; width: 100%; border-radius: 4px; text-align: center; overflow: hidden ;}. stack-item img {width: 100%; display: block; pointer-events: none ;}</style>

The above is just a set of static code. We want to get the vue component, so we need to create a component template stack first. vue. In the template, we can use v-for to traverse the stack node and use: style to modify the style of each item. The Code is as follows:

<Template> <ul class = "stack"> <li class = "stack-item" v-for = "(item, index) in pages ": style = "[transform (index)]">  </li> </ul> </template> <script> export default {props: {// pages data contains the basic image data pages: {type: Array, default: [] }}, data () {return {// basicdata contains the basic data of the component basicdata: {currentPage: 0 // The sequence of the default first graph }, // temporaryData contains temporary data of the component temporaryData: {opacity: 1, // record opacity zIndex: 10, // record zIndex visible: 3 // The default number of stacks is displayed for the record visible }}, methods: {// The traversal style transform (index) {if (index> = this. basicdata. currentPage) {let style = {} let visible = this. temporaryData. visible let perIndex = index-this. basicdata. currentPage // visible number before the slider style if (index <= this. basicdata. currentPage + visible-1) {style ['opacity '] = '1' style ['transform'] = 'translate3d, '+-1 * perIndex * 60 + 'px' + ')' style ['zindex'] = visible-index + this. basicdata. currentPage style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} else {style ['zindex'] = '-1' style [' transform '] = 'translate3d (0, 0, '+-1 * visible * 60 + 'px' + ')'} return style }}</script>

Key Points

: Style can bind objects or arrays and functions, which is useful during traversal.
The most basic dom structure has been built. The next step is to "move" the first image.

2. Image sliding

The image sliding effect has appeared in many scenarios. The principle is to listen to the touchs event, get the displacement, and then change the target displacement through translate3D. The steps we need to achieve are as follows:

  • Binding a stack touchs event
  • Monitor and store the number of changes in the gesture position
  • Change the x and y values of translate3D In the css attribute of the first image.

#### Specific implementation

In the vue framework, it is not recommended to directly operate nodes, but to bind elements using the command v-on. Therefore, we write all bindings in the v-for traversal, use index to determine whether it is the first graph and then use: style to modify the homepage style. The Code is as follows:

<Template> <ul class = "stack"> <li class = "stack-item" v-for = "(item, index) in pages ": style = "[transformIndex (index), transform (index)]" @ touchstart. stop. capture = "touchstart" @ touchmove. stop. capture = "touchmove" @ touchend. stop. capture = "touchend" @ mousedown. stop. capture = "touchstart" @ mouseup. stop. capture = "touchend" @ mousemove. stop. capture = "touchmove">  </li> </ul> </template> <script> Export default {props: {// pages data contains basic image data pages: {type: Array, default: [] }}, data () {return {// basicdata contains the basic data of the component basicdata: {start :{}, // record start position end :{}, // record end position currentPage: 0 // default sequence of the first graph}, // temporaryData contains the temporary data of the component temporaryData: {poswidth: '', // records the displacement of posheight :'', // recording displacement tracking: false // whether to slide to prevent multiple operations from affecting the user experience }}, methods: {touchstart (e) {if (this. temporaryData. trackin G) {return} // whether it is touch if (e. type = 'touchstart') {if (e. touches. length> 1) {this. temporaryData. tracking = false return} else {// record start position this. basicdata. start. t = new Date (). getTime () this. basicdata. start. x = e.tar getTouches [0]. clientX this. basicdata. start. y = e.tar getTouches [0]. clientY this. basicdata. end. x = e.tar getTouches [0]. clientX this. basicdata. end. y = e.tar getTouches [0]. clientY }/ /Pc operation} else {this. basicdata. start. t = new Date (). getTime () this. basicdata. start. x = e. clientX this. basicdata. start. y = e. clientY this. basicdata. end. x = e. clientX this. basicdata. end. y = e. clientY} this. temporaryData. tracking = true}, touchmove (e) {// record the sliding position if (this. temporaryData. tracking &&! This. temporaryData. animation) {if (e. type = 'touchmove ') {this. basicdata. end. x = e.tar getTouches [0]. clientX this. basicdata. end. y = e.tar getTouches [0]. clientY} else {this. basicdata. end. x = e. clientX this. basicdata. end. y = e. clientY} // calculates the sliding value this. temporaryData. poswidth = this. basicdata. end. x-this. basicdata. start. x this. temporaryData. posheight = this. basicdata. end. y-this. basicdata. start. y }}, touchend (e) {this. temporaryData. tracking = false // sliding ends, trigger judgment}, // non-homepage style switch transform (index) {if (index> this. basicdata. currentPage) {let style = {} let visible = 3 let perIndex = index-this. basicdata. currentPage // visible number before the slider style if (index <= this. basicdata. currentPage + visible-1) {style ['opacity '] = '1' style ['transform'] = 'translate3d, '+-1 * perIndex * 60 + 'px' + ')' style ['zindex'] = visible-index + this. basicdata. currentPage style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} else {style ['zindex'] = '-1' style [' transform '] = 'translate3d (0, 0, '+-1 * visible * 60 + 'px' + ')'} return style}, // switch the homepage style to transformIndex (index) {// process the 3D effect if (index = this. basicdata. currentPage) {let style = {} style ['transform'] = 'translate3d ('+ this. temporaryData. poswidth + 'px '+', '+ this. temporaryData. posheight + 'px '+', 0px) 'style ['opacity '] = 1 style ['zindex'] = 10 return style }}</script>

3. Slide out after the condition is successful, and rebound after the condition fails

The trigger judgment of a condition is performed after touchend/mouseup. Here we use a simple condition to determine the effect of the first graph pop-up and rebound. The Code is as follows:

<Template> <ul class = "stack"> <li class = "stack-item" v-for = "(item, index) in pages ": style = "[transformIndex (index), transform (index)]" @ touchmove. stop. capture = "touchmove" @ touchstart. stop. capture = "touchstart" @ touchend. stop. capture = "touchend" @ mousedown. stop. capture = "touchstart" @ mouseup. stop. capture = "touchend" @ mousemove. stop. capture = "touchmove">  </li> </ul> </template> <script> Export default {props: {// pages data contains basic image data pages: {type: Array, default: [] }}, data () {return {// basicdata contains the basic data of the component basicdata: {start :{}, // record start position end :{}, // record end position currentPage: 0 // default sequence of the first graph}, // temporaryData contains the temporary data of the component temporaryData: {poswidth: '', // records the displacement of posheight :'', // recording displacement tracking: false, // whether to slide to prevent multiple operations from affecting the experience of animation: false, // whether the animation effect is enabled for the first image. The default value is no opacity: 1 // record the transparency of the first image }}}, Methods: {touchstart (e) {if (this. temporaryData. tracking) {return} // whether it is touch if (e. type = 'touchstart') {if (e. touches. length> 1) {this. temporaryData. tracking = false return} else {// record start position this. basicdata. start. t = new Date (). getTime () this. basicdata. start. x = e.tar getTouches [0]. clientX this. basicdata. start. y = e.tar getTouches [0]. clientY this. basicdata. end. x = e.tar getTouches [0]. c LientX this. basicdata. end. y = e.tar getTouches [0]. clientY} // pc operation} else {this. basicdata. start. t = new Date (). getTime () this. basicdata. start. x = e. clientX this. basicdata. start. y = e. clientY this. basicdata. end. x = e. clientX this. basicdata. end. y = e. clientY} this. temporaryData. tracking = true this. temporaryData. animation = false}, touchmove (e) {// record the sliding position if (this. temporaryData. tracking &&! This. temporaryData. animation) {if (e. type = 'touchmove ') {this. basicdata. end. x = e.tar getTouches [0]. clientX this. basicdata. end. y = e.tar getTouches [0]. clientY} else {this. basicdata. end. x = e. clientX this. basicdata. end. y = e. clientY} // calculates the sliding value this. temporaryData. poswidth = this. basicdata. end. x-this. basicdata. start. x this. temporaryData. posheight = this. basicdata. end. y-this. basicdata. start. y }}, Touchend (e) {this. temporaryData. tracking = false this. temporaryData. animation = true // trigger judgment when sliding ends. // trigger judgment when sliding width exceeds 100 pixels. if (Math. abs (this. temporaryData. poswidth)> = 100) {// The final displacement is set to the offset of X axis 200 pixels. let ratio = Math. abs (this. temporaryData. posheight/this. temporaryData. poswidth) this. temporaryData. poswidth = this. temporaryData. poswidth> = 0? This. temporaryData. poswidth + 200: this. temporaryData. poswidth-200 this. temporaryData. posheight = this. temporaryData. posheight> = 0? Math. abs (this. temporaryData. poswidth * ratio):-Math. abs (this. temporaryData. poswidth * ratio) this. temporaryData. opacity = 0 // slide into} else {this. temporaryData. poswidth = 0 this. temporaryData. posheight = 0 }}, // non-homepage style switch transform (index) {if (index> this. basicdata. currentPage) {let style = {} let visible = 3 let perIndex = index-this. basicdata. currentPage // visible number before the slider style if (index <= this. basicdata. currentPage + visible-1) {style ['opacity '] = '1' style ['transform'] = 'translate3d, '+-1 * perIndex * 60 + 'px' + ')' style ['zindex'] = visible-index + this. basicdata. currentPage style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} else {style ['zindex'] = '-1' style [' transform '] = 'translate3d (0, 0, '+-1 * visible * 60 + 'px' + ')'} return style}, // switch the homepage style to transformIndex (index) {// process the 3D effect if (index = this. basicdata. currentPage) {let style = {} style ['transform'] = 'translate3d ('+ this. temporaryData. poswidth + 'px '+', '+ this. temporaryData. posheight + 'px '+', 0px) 'style ['opacity '] = this. temporaryData. opacity style ['zindex'] = 10 if (this. temporaryData. animation) {style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} return style }}</script>

4. Slide out and stack the next image to the top.

Restacking is the last and most important and complex feature of components. In our code, the sorting dependency of stack-item is bound to the transformIndex and transform functions of the style. The condition in the function is currentPage. Does it change currentPage to + 1, can the stack be re-stacked?

The answer is not that simple, because we slide out the animation effect, it will take ms, and the currentPage change will immediately change and interrupt the animation. Therefore, we need to modify the sorting condition of the transform function and then change currentPage.

#### Specific implementation

  • Modify the sorting condition of the transform function
  • Make currentPage + 1
  • Add an onTransitionEnd event and place it in the stack list after the slide-out ends.

The Code is as follows:

<Template> <ul class = "stack"> <li class = "stack-item" v-for = "(item, index) in pages ": style = "[transformIndex (index), transform (index)]" @ touchmove. stop. capture = "touchmove" @ touchstart. stop. capture = "touchstart" @ touchend. stop. capture = "touchend" @ mousedown. stop. capture = "touchstart" @ mouseup. stop. capture = "touchend" @ mousemove. stop. capture = "touchmove" @ webkit-transition-end = "onTransitionEnd" @ transitione Nd = "onTransitionEnd">  </li> </ul> </template> <script> export default {props: {// pages data contains the basic image data pages: {type: Array, default: [] }}, data () {return {// basicdata contains the basic data of the component basicdata: {start :{}, // record start position end :{}, // record the destination position currentPage: 0 // default sequence of the first graph}, // temporaryData contains the temporary component data temporaryData: {poswidth: '', // record displacement posheight: '', // record displacement lastPosWidth:'', // record the last final Shift lastPosHeight: '', // record the last final shift tracking: false, // whether it is sliding, prevent multiple operations, affect the experience of animation: false, // whether to enable the animation effect on the first image. The default value is no opacity: 1. // record the transparency of the first image. swipe: false // onTransition judgment condition }}, methods: {touchstart (e) {if (this. temporaryData. tracking) {return} // whether it is touch if (e. type = 'touchstart') {if (e. touches. length> 1) {this. temporaryData. tracking = false return} else {// record start position this. basicdata. start. t = New Date (). getTime () this. basicdata. start. x = e.tar getTouches [0]. clientX this. basicdata. start. y = e.tar getTouches [0]. clientY this. basicdata. end. x = e.tar getTouches [0]. clientX this. basicdata. end. y = e.tar getTouches [0]. clientY} // pc operation} else {this. basicdata. start. t = new Date (). getTime () this. basicdata. start. x = e. clientX this. basicdata. start. y = e. clientY this. basicdata. end. x = e. clientX this. Basicdata. end. y = e. clientY} this. temporaryData. tracking = true this. temporaryData. animation = false}, touchmove (e) {// record the sliding position if (this. temporaryData. tracking &&! This. temporaryData. animation) {if (e. type = 'touchmove ') {this. basicdata. end. x = e.tar getTouches [0]. clientX this. basicdata. end. y = e.tar getTouches [0]. clientY} else {this. basicdata. end. x = e. clientX this. basicdata. end. y = e. clientY} // calculates the sliding value this. temporaryData. poswidth = this. basicdata. end. x-this. basicdata. start. x this. temporaryData. posheight = this. basicdata. end. y-this. basicdata. start. y }}, Touchend (e) {this. temporaryData. tracking = false this. temporaryData. animation = true // trigger judgment when sliding ends. // trigger judgment when sliding width exceeds 100 pixels. if (Math. abs (this. temporaryData. poswidth)> = 100) {// The final displacement is set to the offset of X axis 200 pixels. let ratio = Math. abs (this. temporaryData. posheight/this. temporaryData. poswidth) this. temporaryData. poswidth = this. temporaryData. poswidth> = 0? This. temporaryData. poswidth + 200: this. temporaryData. poswidth-200 this. temporaryData. posheight = this. temporaryData. posheight> = 0? Math. abs (this. temporaryData. poswidth * ratio):-Math. abs (this. temporaryData. poswidth * ratio) this. temporaryData. opacity = 0 this. temporaryData. swipe = true // records the final sliding distance this. temporaryData. lastPosWidth = this. temporaryData. poswidth this. temporaryData. lastPosHeight = this. temporaryData. posheight // currentPage + 1 causes the sorting change this. basicdata. currentPage + = 1 // currentPage switch, the overall dom changes, and the first layer slides to zero this. $ nextTick () => {this. temporaryData. poswidth = 0 this. temporaryData. posheight = 0 this. temporaryData. opacity = 1}) // slide into} else {this. temporaryData. poswidth = 0 this. temporaryData. posheight = 0 this. temporaryData. swipe = false }}, onTransitionEnd (index) {// After the dom changes, the ongoing animated slide sequence has changed to the previous if (this. temporaryData. swipe & index = this. basicdata. currentPage-1) {this. temporaryData. animation = true this. temporaryData. lastPosWidth = 0 this. temporaryData. lastPosHeight = 0 this. temporaryData. swipe = false }}, // non-homepage style switch transform (index) {if (index> this. basicdata. currentPage) {let style = {} let visible = 3 let perIndex = index-this. basicdata. currentPage // visible number before the slider style if (index <= this. basicdata. currentPage + visible-1) {style ['opacity '] = '1' style ['transform'] = 'translate3d, '+-1 * perIndex * 60 + 'px' + ')' style ['zindex'] = visible-index + this. basicdata. currentPage style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} else {style ['zindex'] = '-1' style [' transform '] = 'translate3d (0, 0, '+-1 * visible * 60 + 'px' + ')'} return style // After the slide module is released} else if (index = this. basicdata. currentPage-1) {let style ={} // continue to execute the animation style ['transform'] = 'translate3d ('+ this. temporaryData. lastPosWidth + 'px '+', '+ this. temporaryData. lastPosHeight + 'px '+', 0px) 'style ['opacity '] = '0' style ['zindex'] ='-1' style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms' return style }}, // switch the homepage style to transformIndex (index) {// process the 3D effect if (index = this. basicdata. currentPage) {let style = {} style ['transform'] = 'translate3d ('+ this. temporaryData. poswidth + 'px '+', '+ this. temporaryData. posheight + 'px '+', 0px) 'style ['opacity '] = this. temporaryData. opacity style ['zindex'] = 10 if (this. temporaryData. animation) {style ['transitiontimingfunction'] = 'internal' style ['transitionduration'] = 300 + 'ms'} return style }}</script>

OK ~ After completing the above four steps, the basic functions of stack components have been implemented. Let's take a look at the results.

 

The stacked sliding effect has come out, but in terms of experience, it also increases the touch angle offset and determines the proportion of the sliding area.

The principle of angle offset is to record the touch position of the user each time the user performs touch, and calculate the maximum offset angle. When the sliding occurs, the angle and maximum offset angle are linearly increased.

In stack, you must:

  • Calculate the desired angle and direction in touchmove.
  • In touchend and onTransitionEnd, the angle is 0.

Determine the sliding area ratio. The offset is used to calculate the offset area to obtain the area proportion and complete the judgment.

The complete code and demo can be viewed on github. It will not be posted here.

Thank you for reading this article. I like to give it a star: Ghost on github. Finally, I hope you can find your ex-girlfriend: green_heart:

Summary

The above is an example code for using vue to create a probe and slide component. I hope it will be helpful to you. If you have any questions, please leave a message for me, the editor will reply to you in a timely manner. Thank you very much for your support for the help House website!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.