Want to make a control like an iOS picker, the effect of the control on iOS is this: I also call this effect a wheel effect.
To achieve this effect, can be used in the technical point is very simple, nothing is transform translate3d and rotate, but to be very good implementation, but also to establish a precise mathematical model to solve how to "put" the problem. In particular, this effect is not static, the need to meet the mouse sliding, the wheel to turn up, which requires careful thinking. In the beginning, of course, it is important to figure out what the arguments are, what the variables are, what their relationships are, and some of the nature of the requirements. Finding a good nature can ease the workload and make the code more concise.
To do this, the first thought is to use a div to represent each small entry, and then imagine that these div is affixed to a circle, rolling the circle. First use HTML to display the structure:
1 <Divclass= "Border">2 <Divclass= "Item">0</Div>3 <Divclass= "Item">1</Div>4 <Divclass= "Item">2</Div>5 <Divclass= "Item">3</Div>6 <Divclass= "Item">4</Div>7 <Divclass= "Item">5</Div>8 <Divclass= "Item">6</Div>9 <Divclass= "Item">7</Div>Ten <Divclass= "Item">8</Div> One <Divclass= "Item">9</Div> A <Divclass= "Item">10</Div> - <Divclass= "Item">11</Div> - <Divclass= "Item">12</Div> the <Divclass= "Item">13</Div> - <Divclass= "Item">14</Div> - <Divclass= "Item">15</Div> - <Divclass= "Item">16</Div> + <Divclass= "Item">17</Div> - <Divclass= "Item">18</Div> + </Div>
Then write the CSS code:
1 <style>2 * {3 -webkit-user-select:None;4}5 6 . Item{7 Height:30px;8 Line-height:30px;9 font-size:15px;Ten Font-weight:Bolder; One Color:#222; A width:400px; - background: White; - text-align:Center; the position:Absolute; - Top:50%; - Margin-top:-15px; -} + - . Border{ + Overflow:Hidden; A cursor:Pointer; at position:relative; - Height:240px; - width:400px; - Border:2px solid Black; -} - in . Hide{ - Display:None; to} + </style>
Note that the above border takes a relative (relative) position, the entry (item) is absolutely positioned, and is vertically centered, so that it has the following effect:
Because you set the background color for item, you only see the last item. The next thing we need to do is to put the 19 item in the first place and the image is affixed to the circle. This requires digging into the nature of this demand, because the nature will be our breakthrough.
To take this effect, you need to analyze it first. We know that because each item is the same height, the difference in rotation between each of the two adjacent item is the same, and the difference in this angle can be calculated from Equation 2 * math.asin (HEIGHT/2/R). In addition, the rotation angle of the runner is the same as the rotation angle of item, so we need to know the angle of rotation, with this angle and the difference of angle, we can know the angle of rotation of any item, and then calculate the position of item on this angle.
With the above analysis, it's not that hard to put a nice picker control style in place. But before you do that, make a simple preparation.
First, you need a CSS style to set the JavaScript function, because in the process, it is frequently used to use JavaScript to set the CSS transform style, it is very necessary to extract this action to write as a function, it may be named as a CSS, The code for this section is as follows:
1 function css (el, style) {2 function (name, value) {3 el.style.setProperty (name, Value, ""); 4 })5 }
The code is very simple, but very practical. The third parameter of the SetProperty method can be important or an empty string, which is set to an empty string.
Next lay the layout. Because the item deployed on the sphere is symmetrical, the 19 item, starting with the 10th layout, and then looping 10 times, from the middle to the sides, the item is laid out in turn. This part of the code looks like this:
1 varR = 90;2 varHeight = 30;3 varDAngle = 2 * Math.asin (HEIGHT/2/R);4 varFirst = ITEMS.LENGTH/2 << 0;5 6 functionSetPosition (curangle) {7D.loop (first + 1,function(i) {8Doset (Items[first + i], curangle-i *dAngle);9Doset (Items[first-i], curangle + i *dAngle);Ten } ); One}
The code for Doset is as follows:
1 function doset (el, Angle) {2 Math.Abs (angle) > MATH.PI/2? El.classList.add ("Hide"): El.classList.remove ("Hide" ); 3 d.css (el, {4 "-webkit-transform": "Translate3d (0," + (R * Math.sin (-angle)) + "px,0" Rotat EX ("+ Angle/math.pi * +" + "deg)"5 }); 6 }
Add the initialized JavaScript code: setposition (0), and then open in the browser to see the effect, you can tell that the layout is successful, it is the effect we want.
The next work, to let it turn up, because the above considerations are very sufficient, there is no need to introduce new variables, as long as the mouse to record the distance, the corresponding curangle, and then passed to SetPosition can be. The relevant code looks like this:
1 varEnd =d.events ();2 3 d.dragy (Border, border, {4Moving:function () {5 varmoving =d.events ();6Moving.regist (function(e) {7SetPosition (-e.dy/50 );8 } );9 returnmoving;Ten }, One End:end, ASetmove:function(e) { - Console.log (e.dy); - } the} );
Open in the browser, and then you can see that it is ready to turn.
But this is still in the ointment, that is, the angle of rotation is not recorded, resulting in the second rotation, or a new start, so also need to change:
1 varAlreadys = 0;2 3 d.dragy (Border, border, {4Moving:function () {5 varmoving =d.events ();6Moving.regist (function(e) {7Console.log (Alreadys-e.dy);8SetPosition ((alreadys-e.dy)/50 );9 } );Ten returnmoving; One }, AEnd:function () { - varEnd =d.events (); -End.regist (function(e) { theAlreadys = Alreadys-E.dy; - } ); - returnend; - }, +Setmove:function(e) { - } +} );
A global variable Alreadys is added here to record the sliding distance so that you don't have to start over every time you swipe. The time to update Alreadys is at the end of each scroll, so a new end event is added.