1 /* 2 主站,子频道,定向站点共用 3 */ 4 (function() { 5 6 scrollToAnchor(); 7 8 toggleSearchForm(); 9 10 scrollTop(); 11 12 initScrollBar(); 13 14 // 文档图片放大查看 15 imgZoom(); 16 17 renderCodeBox(); 18 19 dropdownClick(); 20 21 fixAside(); 22 23 // 侧边栏固定 24 function fixAside() { 25 if (SITE_SLUG === 'open') { 26 var headerHeight = $('.header').outerHeight() + $('.search-wrapper').outerHeight() + 32; 27 var offsetTop = $('.dropdown-menu-selector').height() || 0; 28 affixSidebar(headerHeight, offsetTop); 29 affix($('.breadcrumb'), headerHeight, 0); 30 } else { 31 var headerHeight = $('.header').outerHeight(); 32 var offsetTop = 86; 33 affixSidebar(headerHeight, offsetTop); 34 } 35 } 36 37 // 页面加载时的锚点定位 38 function initScrollBar() { 39 $(window).on('load', function() { 40 var hash = decodeURIComponent(window.location.hash); 41 if (!hash) return; 42 43 // 兼容 toc 旧版本中的链接错误 44 if (hash.substr(0, 2) === '##') { 45 hash = hash.substr(1); 46 } 47 48 if (hash !== '#' && $(hash).length) { 49 var top = $(hash).offset().top - $('.breadcrumb').outerHeight(); 50 51 // 子站点需要计算头部高度 52 if (SITE_SLUG !== 'open') { 53 top -= $('.page-title').outerHeight(); 54 } 55 setTimeout(function() { 56 $(window).scrollTop(top); 57 }, 0); 58 } 59 }); 60 } 61 62 function affix($el, headerHeight, offsetTop) { 63 $(window).on('load scroll resize', function () { 64 if (!$el.length) return; 65 66 var scrollTop = window.scrollY || window.pageYOffset; 67 if (scrollTop > headerHeight) { 68 $el.css({ 69 position: 'fixed', 70 top: offsetTop, 71 left: $el.offset().left, 72 right: $('body').width() - $el.offset().left - $el.width(), 73 }) 74 } else { 75 $el.removeAttr('style') 76 } 77 }); 78 } 79 80 function affixSidebar(headerHeight, offsetTop) { 81 var footerHeight = $('.body-footer').outerHeight(); 82 var $sidebar = $('.sidebar-wrapper'); 83 var $breadcrumb = $('.breadcrumb'); 84 85 $(window).on('load scroll resize', function () { 86 var scrollTop = window.scrollY || window.pageYOffset; 87 88 // sidebar fixed 时跟底部保持的距离 89 var offsetBottom = document.body.scrollHeight - scrollTop - window.innerHeight - 32; 90 91 var bottom = 0; 92 if (offsetBottom < footerHeight) { 93 bottom = footerHeight - offsetBottom; 94 } 95 96 $sidebar.find('.sidebar').css({ 97 'height': window.innerHeight - bottom - offsetTop, 98 }); 99 100 // sidebar fixed 101 if (scrollTop > headerHeight) { 102 $sidebar.addClass('fixed'); 103 } else { 104 $sidebar.removeClass('fixed'); 105 } 106 }); 107 } 108 109 110 function dropdownClick() { 111 // dropdown trigger: click 112 $('body').on('click', '.dropdown .dropdown-trigger', function() { 113 var $dropdown = $(this).parent('.dropdown'); 114 $dropdown.toggleClass('open'); 115 116 if ($dropdown.hasClass('open') && $dropdown.hasClass('dropdown-menu-selector')) { 117 var $menu = $('#main-menu'); 118 var $active = $menu.find('.menu-item .active'); 119 if ($active.length) { 120 var top = $menu.scrollTop() + $active.position().top - 56; 121 if (top > 0) { 122 $menu.scrollTop(top); 123 } 124 } 125 } 126 }); 127 $('html').on('click', function() { 128 $('.dropdown.open').removeClass('open'); 129 }); 130 $('html').on('click', '.dropdown', function(e) { 131 e.stopPropagation(); 132 }); 133 } 134 135 function renderCodeBox() { 136 // copy code 137 var $codeBox = $('<div class="code-box" />'); 138 var codeTemplate = '<span class="btn-copy-code">点击复制</span>'; 139 $('code.language-js, code.language-javascript, code.language-jsx').each(function(index, item) { 140 $(item).parent('pre').wrap($codeBox).before(codeTemplate); 141 }) 142 143 var clipboard = new Clipboard('.btn-copy-code', { 144 text: function(trigger) { 145 return trigger.nextElementSibling.textContent; 146 } 147 }); 148 149 var clipboardTimer = null; 150 clipboard.on('success', (e) => { 151 $(e.trigger).text('复制成功!'); 152 if (clipboardTimer) { 153 clearTimeout(clipboardTimer); 154 } 155 clipboardTimer = setTimeout(() => { 156 $(e.trigger).text('点击复制'); 157 }, 1500); 158 }); 159 } 160 161 function imgZoom() { 162 var zoomDefaults = { 163 styles: { 164 zoomImage: { 165 cursor : 'zoom-out', 166 position : 'absolute', 167 transition : 'transform 300ms', 168 transform : 'translate3d(0, 0, 0) scale(1)', 169 transformOrigin : 'center center', 170 willChange : 'transform, top, left' 171 }, 172 zoomContainer: { 173 position : 'fixed', 174 top : 0, 175 right : 0, 176 bottom : 0, 177 left : 0, 178 zIndex : 1024, 179 }, 180 overlay: { 181 position : 'absolute', 182 top : 0, 183 right : 0, 184 bottom : 0, 185 left : 0, 186 backgroundColor : '#FFF', 187 opacity : 0, 188 transition : 'opacity 300ms', 189 }, 190 btn: { 191 position : 'absolute', 192 bottom : 12, 193 right : 12, 194 padding : '4px 10px', 195 border : '1px solid #e9e9e9', 196 borderRadius : 2, 197 fontSize : 12, 198 color : '#999', 199 }, 200 btnHover: { 201 color : '#666', 202 }, 203 }, 204 }; 205 var zoomOriginImage = null; 206 var zoomTimer = null; 207 // zoom in 208 $('.markdown').on('click', 'img', function() { 209 zoomOriginImage = $(this).get(0); 210 211 var $wrap = $('<div />'); 212 $wrap.css(zoomDefaults.styles.zoomContainer); 213 214 var $overlay = $('<div class="overlay" />'); 215 $overlay.css(zoomDefaults.styles.overlay); 216 217 var $img = $(this).clone(); 218 $img.css(getImageStyle(zoomOriginImage, false)); 219 220 var $btn = $('<a target="_blank" />'); 221 $btn.attr('href', $img.attr('src')).text('查看原图'); 222 $btn.css(zoomDefaults.styles.btn); 223 224 $btn.hover(function() { 225 $(this).css(zoomDefaults.styles.btnHover); 226 }, function() { 227 $(this).css(zoomDefaults.styles.btn); 228 }); 229 230 $wrap.append($overlay).append($img).append($btn); 231 $('#zoom-img').append($wrap); 232 233 // transition 234 $overlay.css({ 235 opacity: 1, 236 }); 237 $img.css(getImageStyle($img.get(0), true)); 238 }); 239 240 // zoom out 241 $('#zoom-img').on('click', function() { 242 var $zoom = $(this); 243 $zoom.find('img').css(getImageStyle(zoomOriginImage, false)); 244 $zoom.find('.overlay').css({ 245 opacity: 0 246 }); 247 248 if (zoomTimer) { 249 clearTimeout(zoomTimer); 250 } 251 zoomTimer = setTimeout(function() { 252 $zoom.html(''); 253 zoomOriginImage = null; 254 }, 150); 255 }); 256 257 $(window).on('scroll', function() { 258 $('#zoom-img').html(''); 259 zoomOriginImage = null; 260 }); 261 262 $(window).on('resize', function() { 263 if ($('#zoom-img img').length) { 264 $('#zoom-img img').css(getImageStyle(zoomOriginImage, true)); 265 } 266 }); 267 268 function getImageStyle(image, isZoom) { 269 var imageOffset = image.getBoundingClientRect(); 270 var top = imageOffset.top; 271 var left = imageOffset.left; 272 var width = image.width; 273 var height = image.height; 274 275 var style = { 276 top: top, 277 left: left, 278 width, 279 height: height 280 }; 281 282 if (!isZoom) { 283 return Object.assign({}, zoomDefaults.styles.zoomImage, style); 284 } 285 286 // Get the the coords for center of the viewport 287 var viewportX = window.innerWidth / 2; 288 var viewportY = window.innerHeight / 2; 289 290 // Get the coords for center of the original image 291 var imageCenterX = imageOffset.left + image.width / 2; 292 var imageCenterY = imageOffset.top + image.height / 2; 293 294 // Get offset amounts for image coords to be centered on screen 295 var translateX = viewportX - imageCenterX; 296 var translateY = viewportY - imageCenterY; 297 298 // Figure out how much to scale the image so it doesn't overflow the screen 299 var scale = getScale(width, height); 300 301 var zoomStyle = { 302 transform: 'translate3d(' + translateX + 'px, ' + translateY + 'px, 0) scale(' + scale + ')', 303 } 304 305 return Object.assign({}, zoomDefaults.styles.zoomImage, style, zoomStyle); 306 } 307 308 function getScale(width, height) { 309 var totalMargin = 40; 310 var scaleX = window.innerWidth / (width + totalMargin); 311 var scaleY = window.innerHeight / (height + totalMargin); 312 return Math.min(scaleX, scaleY); 313 } 314 } 315 316 function scrollTop() { 317 // scroll top 318 $(window).on('load scroll', function() { 319 if ($(window).scrollTop() > 400) { 320 $('#scroll-top').addClass('visible'); 321 } else { 322 $('#scroll-top').removeClass('visible'); 323 } 324 }) 325 $('#scroll-top').on('click', function(e) { 326 e.preventDefault(); 327 $('html, body').animate({ 328 scrollTop: 0 329 }, 150); 330 }) 331 } 332 333 function scrollToAnchor(offsetTop) { 334 // anchor click scroll to element 335 var breadcrumbHeight = $('.breadcrumb').outerHeight(); 336 var offsetTop = 0; 337 if (SITE_SLUG === 'open') { 338 offsetTop = breadcrumbHeight; 339 } else { 340 offsetTop = $('.page-title').outerHeight() + breadcrumbHeight; 341 } 342 343 // 锚点处理 344 $('.markdown').on('click', 'a', function(e) { 345 var href = $(this).attr('href'); 346 if (/^#/.test(href)) { 347 e.preventDefault(); 348 if ($(href).length) { 349 var top = $(href).offset().top - offsetTop; 350 $('html, body').scrollTop(top); 351 } 352 } 353 }); 354 } 355 356 function toggleSearchForm() { 357 // header search 358 $('.header').on('click', '.btn-search', function(e) { 359 e.preventDefault(); 360 $('.header .user-menu').addClass('search-open'); 361 $('.header .search-form input').focus(); 362 }) 363 $('html').on('click', function(e) { 364 $('.header .user-menu.search-open').removeClass('search-open'); 365 }) 366 $('html').on('click', '.header .search-form', function(e) { 367 e.stopPropagation(); 368 }) 369 } 370 }());