PageSourceSearch

https://wanghan0.github.io/js/src/motion.js?v=5.1.0

js wanghan0.github.io collected 2026-10-03 10:09:32 UTC 7,825 bytes, 291 lines download raw bytes

1/* global NexT: true */
2
3$(document).ready(function () {
4  NexT.motion = {};
5
6  var sidebarToggleLines = {
7    lines: [],
8    push: function (line) {
9      this.lines.push(line);
10    },
11    init: function () {
12      this.lines.forEach(function (line) {
13        line.init();
14      });
15    },
16    arrow: function () {
17      this.lines.forEach(function (line) {
18        line.arrow();
19      });
20    },
21    close: function () {
22      this.lines.forEach(function (line) {
23        line.close();
24      });
25    }
26  };
27
28  function SidebarToggleLine(settings) {
29    this.el = $(settings.el);
30    this.status = $.extend({}, {
31      init: {
32        width: '100%',
33        opacity: 1,
34        left: 0,
35        rotateZ: 0,
36        top: 0
37      }
38    }, settings.status);
39  }
40
41  SidebarToggleLine.prototype.init = function () {
42    this.transform('init');
43  };
44  SidebarToggleLine.prototype.arrow = function () {
45    this.transform('arrow');
46  };
47  SidebarToggleLine.prototype.close = function () {
48    this.transform('close');
49  };
50  SidebarToggleLine.prototype.transform = function (status) {
51    this.el.velocity('stop').velocity(this.status[status]);
52  };
53
54  var sidebarToggleLine1st = new SidebarToggleLine({
55    el: '.sidebar-toggle-line-first',
56    status: {
57      arrow: {width: '50%', rotateZ: '-45deg', top: '2px'},
58      close: {width: '100%', rotateZ: '-45deg', top: '5px'}
59    }
60  });
61  var sidebarToggleLine2nd = new SidebarToggleLine({
62    el: '.sidebar-toggle-line-middle',
63    status: {
64      arrow: {width: '90%'},
65      close: {opacity: 0}
66    }
67  });
68  var sidebarToggleLine3rd = new SidebarToggleLine({
69    el: '.sidebar-toggle-line-last',
70    status: {
71      arrow: {width: '50%', rotateZ: '45deg', top: '-2px'},
72      close: {width: '100%', rotateZ: '45deg', top: '-5px'}
73    }
74  });
75
76  sidebarToggleLines.push(sidebarToggleLine1st);
77  sidebarToggleLines.push(sidebarToggleLine2nd);
78  sidebarToggleLines.push(sidebarToggleLine3rd);
79
80  var SIDEBAR_WIDTH = '320px';
81  var SIDEBAR_DISPLAY_DURATION = 200;
82
83  var sidebarToggleMotion = {
84    toggleEl: $('.sidebar-toggle'),
85    sidebarEl: $('.sidebar'),
86    isSidebarVisible: false,
87    init: function () {
88      this.toggleEl.on('click', this.clickHandler.bind(this));
89      this.toggleEl.on('mouseenter', this.mouseEnterHandler.bind(this));
90      this.toggleEl.on('mouseleave', this.mouseLeaveHandler.bind(this));
91
92      $(document)
93        .on('sidebar.isShowing', function () {
94          NexT.utils.isDesktop() && $('body').velocity('stop').velocity(
95            {paddingRight: SIDEBAR_WIDTH},
96            SIDEBAR_DISPLAY_DURATION
97          );
98        })
99        .on('sidebar.isHiding', function () {
100        });
101    },
102    clickHandler: function () {
103      this.isSidebarVisible ? this.hideSidebar() : this.showSidebar();
104      this.isSidebarVisible = !this.isSidebarVisible;
105    },
106    mouseEnterHandler: function () {
107      if (this.isSidebarVisible) {
108        return;
109      }
110      sidebarToggleLines.arrow();
111    },
112    mouseLeaveHandler: function () {
113      if (this.isSidebarVisible) {
114        return;
115      }
116      sidebarToggleLines.init();
117    },
118    showSidebar: function () {
119      var self = this;
120
121      sidebarToggleLines.close();
122
123      this.sidebarEl.velocity('stop').velocity({
124          width: SIDEBAR_WIDTH
125        }, {
126          display: 'block',
127          duration: SIDEBAR_DISPLAY_DURATION,
128          begin: function () {
129            $('.sidebar .motion-element').velocity(
130              'transition.slideRightIn',
131              {
132                stagger: 50,
133                drag: true,
134                complete: function () {
135                  self.sidebarEl.trigger('sidebar.motion.complete');
136                }
137              }
138            );
139          },
140          complete: function () {
141            self.sidebarEl.addClass('sidebar-active');
142            self.sidebarEl.trigger('sidebar.didShow');
143          }
144        }
145      );
146
147      this.sidebarEl.trigger('sidebar.isShowing');
148    },
149    hideSidebar: function () {
150      NexT.utils.isDesktop() && $('body').velocity('stop').velocity({paddingRight: 0});
151      this.sidebarEl.find('.motion-element').velocity('stop').css('display', 'none');
152      this.sidebarEl.velocity('stop').velocity({width: 0}, {display: 'none'});
153
154      sidebarToggleLines.init();
155
156      this.sidebarEl.removeClass('sidebar-active');
157      this.sidebarEl.trigger('sidebar.isHiding');
158
159      //在 post 页面下按下隐藏 sidebar 时如果当前选中的是“站点概览”,将 toc 去除 motion 效果
160      //防止再次打开时会出现在“站点概览”下的 bug
161      if (!!$('.post-toc-wrap')) {
162        if ($('.site-overview').css('display') === 'block') {
163          $('.post-toc-wrap').removeClass('motion-element');
164        }
165      }
166    }
167  };
168  sidebarToggleMotion.init();
169
170  NexT.motion.integrator = {
171    queue: [],
172    cursor: -1,
173    add: function (fn) {
174      this.queue.push(fn);
175      return this;
176    },
177    next: function () {
178      this.cursor++;
179      var fn = this.queue[this.cursor];
180      $.isFunction(fn) && fn(NexT.motion.integrator);
181    },
182    bootstrap: function () {
183      this.next();
184    }
185  };
186
187  NexT.motion.middleWares =  {
188    logo: function (integrator) {
189      var sequence = [];
190      var $brand = $('.brand');
191      var $title = $('.site-title');
192      var $subtitle = $('.site-subtitle');
193      var $logoLineTop = $('.logo-line-before i');
194      var $logoLineBottom = $('.logo-line-after i');
195
196      $brand.size() > 0 && sequence.push({
197        e: $brand,
198        p: {opacity: 1},
199        o: {duration: 200}
200      });
201
202      NexT.utils.isMist() && hasElement([$logoLineTop, $logoLineBottom]) &&
203      sequence.push(
204        getMistLineSettings($logoLineTop, '100%'),
205        getMistLineSettings($logoLineBottom, '-100%')
206      );
207
208      hasElement($title) && sequence.push({
209        e: $title,
210        p: {opacity: 1, top: 0},
211        o: { duration: 200 }
212      });
213
214      hasElement($subtitle) && sequence.push({
215        e: $subtitle,
216        p: {opacity: 1, top: 0},
217        o: {duration: 200}
218      });
219
220      if (sequence.length > 0) {
221        sequence[sequence.length - 1].o.complete = function () {
222          integrator.next();
223        };
224        $.Velocity.RunSequence(sequence);
225      } else {
226        integrator.next();
227      }
228
229
230      function getMistLineSettings (element, translateX) {
231        return {
232          e: $(element),
233          p: {translateX: translateX},
234          o: {
235            duration: 500,
236            sequenceQueue: false
237          }
238        };
239      }
240
241      /**
242       * Check if $elements exist.
243       * @param {jQuery|Array} $elements
244       * @returns {boolean}
245       */
246      function hasElement ($elements) {
247        $elements = Array.isArray($elements) ? $elements : [$elements];
248        return $elements.every(function ($element) {
249          return $.isFunction($element.size) && $element.size() > 0;
250        });
251      }
252    },
253
254    menu: function (integrator) {
255      $('.menu-item').velocity('transition.slideDownIn', {
256        display: null,
257        duration: 200,
258        complete: function () {
259          integrator.next();
260        }
261      });
262    },
263
264    postList: function (integrator) {
265      var $post = $('.post');
266      var hasPost = $post.size() > 0;
267
268      hasPost ? postMotion() : integrator.next();
269
270      function postMotion () {
271        var postMotionOptions = window.postMotionOptions || {
272            stagger: 100,
273            drag: true
274          };
275        postMotionOptions.complete = function () {
276          integrator.next();
277        };
278
279        $post.velocity('transition.slideDownIn', postMotionOptions);
280      }
281    },
282
283    sidebar: function (integrator) {
284      if (CONFIG.sidebar.display === 'always') {
285        NexT.utils.displaySidebar();
286      }
287      integrator.next();
288    }
289  };
290
291});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.