tona-plugins 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +48 -0
  2. package/index.d.ts +32 -0
  3. package/package.json +51 -0
  4. package/src/constants/cdn.js +12 -0
  5. package/src/index.js +30 -0
  6. package/src/plugins/background/index.js +50 -0
  7. package/src/plugins/background/index.scss +0 -0
  8. package/src/plugins/barrage/index.js +104 -0
  9. package/src/plugins/barrage/index.scss +16 -0
  10. package/src/plugins/catalog/index.js +212 -0
  11. package/src/plugins/catalog/index.scss +0 -0
  12. package/src/plugins/charts/index.js +60 -0
  13. package/src/plugins/charts/index.scss +16 -0
  14. package/src/plugins/clickEffects/index.js +137 -0
  15. package/src/plugins/clickEffects/index.scss +0 -0
  16. package/src/plugins/codeCopy/index.js +94 -0
  17. package/src/plugins/codeCopy/index.scss +65 -0
  18. package/src/plugins/codeHighlight/index.js +35 -0
  19. package/src/plugins/codeHighlight/index.scss +216 -0
  20. package/src/plugins/codeHighlight/themes.js +60 -0
  21. package/src/plugins/codeLang/index.js +51 -0
  22. package/src/plugins/codeLang/index.scss +28 -0
  23. package/src/plugins/codeLinenumbers/index.js +33 -0
  24. package/src/plugins/codeLinenumbers/index.scss +61 -0
  25. package/src/plugins/codeTrafficLight/index.js +18 -0
  26. package/src/plugins/codeTrafficLight/index.scss +0 -0
  27. package/src/plugins/colorMode/index.js +81 -0
  28. package/src/plugins/colorMode/index.scss +0 -0
  29. package/src/plugins/commentsAvatars/index.js +85 -0
  30. package/src/plugins/commentsAvatars/index.scss +3 -0
  31. package/src/plugins/darkMode/index.js +115 -0
  32. package/src/plugins/darkMode/index.scss +67 -0
  33. package/src/plugins/donation/index.js +45 -0
  34. package/src/plugins/donation/index.scss +63 -0
  35. package/src/plugins/emoji/index.js +167 -0
  36. package/src/plugins/emoji/index.scss +155 -0
  37. package/src/plugins/footer/index.js +35 -0
  38. package/src/plugins/footer/index.scss +54 -0
  39. package/src/plugins/imagePreview/index.js +98 -0
  40. package/src/plugins/imagePreview/index.scss +51 -0
  41. package/src/plugins/license/index.js +62 -0
  42. package/src/plugins/license/index.scss +51 -0
  43. package/src/plugins/live2d/index.js +67 -0
  44. package/src/plugins/live2d/index.scss +0 -0
  45. package/src/plugins/live2d/live2d-models.js +21 -0
  46. package/src/plugins/lock/index.js +77 -0
  47. package/src/plugins/lock/index.scss +56 -0
  48. package/src/plugins/musicPlayer/index.js +81 -0
  49. package/src/plugins/musicPlayer/index.scss +68 -0
  50. package/src/plugins/notation/index.js +73 -0
  51. package/src/plugins/notation/index.scss +12 -0
  52. package/src/plugins/notice/index.js +17 -0
  53. package/src/plugins/notice/index.scss +46 -0
  54. package/src/plugins/postBottomImage/index.js +27 -0
  55. package/src/plugins/postBottomImage/index.scss +26 -0
  56. package/src/plugins/postMessage/index.js +89 -0
  57. package/src/plugins/postMessage/index.scss +81 -0
  58. package/src/plugins/postTopImage/index.js +28 -0
  59. package/src/plugins/postTopImage/index.scss +29 -0
  60. package/src/plugins/qrcode/index.js +42 -0
  61. package/src/plugins/qrcode/index.scss +10 -0
  62. package/src/plugins/signature/index.js +47 -0
  63. package/src/plugins/signature/index.scss +18 -0
  64. package/src/plugins/toast/index.js +49 -0
  65. package/src/plugins/tools/index.js +251 -0
  66. package/src/plugins/tools/index.scss +114 -0
  67. package/src/plugins/webTag/index.js +40 -0
  68. package/src/plugins/webTag/index.scss +0 -0
  69. package/src/utils/cnblog.js +282 -0
  70. package/src/utils/helpers.js +418 -0
  71. package/src/utils/shared.js +2 -0
@@ -0,0 +1,282 @@
1
+ const { currentBlogApp } = window
2
+
3
+ /**
4
+ * 判断访问者是否为博主
5
+ * @returns {boolean} boolean - 是否为博主
6
+ */
7
+ export const isOwner = () => window.isBlogOwner
8
+
9
+ /**
10
+ * 判断用户登录是否登录
11
+ * @returns {boolean} 是否登录
12
+ */
13
+ export const getLoginState = () => window.isLogined
14
+
15
+ /**
16
+ * 判断是否开启公告
17
+ * @returns {boolean} 是否开启公告
18
+ */
19
+ export const openNews = () => Boolean($('#profile_block').length)
20
+
21
+ /**
22
+ * 获取博客园昵称
23
+ * @returns {string} 博客园昵称
24
+ */
25
+ export function getBlogname() {
26
+ if (openNews()) {
27
+ return $('#profile_block>a:nth-of-type(1)').html().trim()
28
+ }
29
+ const headerTitle = $('#Header1_HeaderTitle').text().trim()
30
+ if (headerTitle.length) {
31
+ return headerTitle
32
+ }
33
+ return currentBlogApp
34
+ }
35
+
36
+ /**
37
+ * 获取粉丝数
38
+ * @returns {number} 粉丝数
39
+ */
40
+ export function getFollowers() {
41
+ const count = openNews()
42
+ ? $('#profile_block a:nth-of-type(3)').text().trim()
43
+ : '未知'
44
+ return count
45
+ }
46
+
47
+ /**
48
+ * 获取关注的人数
49
+ * @returns {number} 关注的人数
50
+ */
51
+ export function getFollowing() {
52
+ const count = openNews()
53
+ ? $('#profile_block a:nth-of-type(4)').text().trim()
54
+ : '未知'
55
+ return count
56
+ }
57
+
58
+ /**
59
+ * 判断是否已经关注
60
+ * @returns {boolean} 是否已经关注
61
+ */
62
+ export function getFollowState() {
63
+ return $('#p_b_follow>a').text().trim() === '-取消关注'
64
+ }
65
+
66
+ /**
67
+ * 获取园龄
68
+ * @returns {string} 园龄
69
+ */
70
+ export function getBlogAge() {
71
+ return openNews()
72
+ ? $('#profile_block a:nth-of-type(2)').text().trim()
73
+ : '未知'
74
+ }
75
+
76
+ /**
77
+ * 获取当前博文链接
78
+ * @returns {string} 当前博文链接
79
+ */
80
+ export function getCurrentPostUrl() {
81
+ return !location.href.includes('#')
82
+ ? location.href
83
+ : location.href.substring(0, location.href.lastIndexOf('#'))
84
+ }
85
+
86
+ /**
87
+ * 获取博客园 user guid
88
+ */
89
+ export function getBlogUserGuid() {
90
+ const strValue = $('body>script:last').text()
91
+
92
+ const regex = /'([^"]*)'/
93
+ return regex.exec(strValue)[1]
94
+ }
95
+
96
+ /**
97
+ * 关注
98
+ */
99
+ export function follow() {
100
+ const guid = window.cb_blogUserGuid
101
+ if (guid) {
102
+ window.follow(guid)
103
+ } else {
104
+ $('#p_b_follow>a').trigger('click')
105
+ }
106
+ }
107
+
108
+ /**
109
+ * 取消关注
110
+ */
111
+ export function unfollow() {
112
+ window.unfollow(window.cb_blogUserGuid)
113
+ }
114
+
115
+ /**
116
+ * 判断文章是否打开了评论
117
+ * @returns {boolean} 文章是否打开了评论
118
+ */
119
+ export const IsCommentTurnedOn = () => Boolean($('#tbCommentBody').length)
120
+
121
+ /**
122
+ * 判断是否为博文详情页
123
+ * @returns {boolean} 是否为博文详情页
124
+ */
125
+ export function isPostDetailsPage() {
126
+ return Boolean($('#post_detail').length)
127
+ }
128
+
129
+ /**
130
+ * 是否为首页
131
+ * @returns {boolean} 是否为首页
132
+ */
133
+ export function isHomePage() {
134
+ return Boolean($('.day').length)
135
+ }
136
+
137
+ /**
138
+ * 是否为标签列表页
139
+ * @returns {boolean} 是否为标签列表页
140
+ */
141
+ export function isTagListPage() {
142
+ return Boolean($('#taglist_main').length)
143
+ }
144
+
145
+ /**
146
+ * 是否为博文详情页
147
+ * @returns {boolean} 是否为博文详情页
148
+ */
149
+ export function isEntrylistPage() {
150
+ return Boolean($('.entrylistPosttitle').length)
151
+ }
152
+
153
+ /**
154
+ * 判断是否为相册页
155
+ * @returns {boolean} 是否为相册页
156
+ */
157
+ export function isAlbumPage() {
158
+ return Boolean($('.gallery').length)
159
+ }
160
+
161
+ /**
162
+ * 判断是否为博文分类页
163
+ * @returns {boolean} 是否为博文分类页
164
+ */
165
+ export function isCategoryPage() {
166
+ return Boolean($('.entrylistItem').length)
167
+ }
168
+
169
+ /**
170
+ * 获取当前页面名称
171
+ * @returns {string} 'post' | 'index' | 'tag' | 'list' | 'tag' | 'taglist'
172
+ */
173
+ export function getCurrentPage() {
174
+ const postDetailExists = $('#post_detail').length
175
+ const dayExists = $('.day').length
176
+ const taglistMainExists = $('#taglist_main').length
177
+ const entrylistPosttitleExists = $('.entrylistPosttitle').length
178
+ const mypostsExists = $('#myposts').length
179
+
180
+ if (postDetailExists) {
181
+ return 'post'
182
+ } else if (dayExists) {
183
+ return 'index'
184
+ } else if (taglistMainExists || mypostsExists) {
185
+ return 'tag'
186
+ } else if (entrylistPosttitleExists) {
187
+ return 'list'
188
+ }
189
+ return undefined
190
+ }
191
+
192
+ /**
193
+ * 判断编辑器类型是否为 md
194
+ * @returns {boolean} 编辑器类型是否为 md
195
+ */
196
+ export function isMd() {
197
+ return $('#cnblogs_post_body').hasClass('cnblogs-markdown')
198
+ }
199
+
200
+ // TODO
201
+ /**
202
+ * 判断编辑器类型是否为 tinymce 5
203
+ */
204
+ export function isTinymce5() {}
205
+
206
+ /**
207
+ * 判断文章内容是否存在标题
208
+ * @returns {boolean} 文章内容是否存在标题
209
+ */
210
+ export function hasPostTitle() {
211
+ return Boolean(
212
+ $(
213
+ '#cnblogs_post_body>h1,#cnblogs_post_body>h2,#cnblogs_post_body>h3,#cnblogs_post_body>h4',
214
+ ).length,
215
+ )
216
+ }
217
+
218
+ /**
219
+ * 推荐博文
220
+ * 博客园过滤机制禁止调用 `windown.votePost`
221
+ * https://group.cnblogs.com/topic/115024.html
222
+ */
223
+ export function likePost() {
224
+ // const id = window.location.href.match(/p\/(\S*).html/)[1]
225
+ // window.votePost(parseInt(id), 'Digg')
226
+ $('.diggit').trigger('click')
227
+ }
228
+
229
+ /**
230
+ * 获取用户信息
231
+ * 仅当用户代码放到页脚 HTML 中才有效
232
+ * @returns {Promise} 表示用户信息的 Promise 对象
233
+ */
234
+ export function getUserInfo() {
235
+ return new Promise((resolve) => {
236
+ $(document).ajaxComplete((_, xhr, settings) => {
237
+ if (settings.url === 'https://account.cnblogs.com/user/userinfo') {
238
+ resolve($.parseJSON(xhr.responseText))
239
+ }
240
+ })
241
+ })
242
+ }
243
+
244
+ /**
245
+ * 获取消息数
246
+ * @returns {(string|undefined)} 消息数
247
+ */
248
+ export function getMessageCount() {
249
+ return $('#msg_count').text()
250
+ }
251
+
252
+ /**
253
+ * 获取随笔数量
254
+ * @returns {string} 随笔数量
255
+ */
256
+ export function getPostCount() {
257
+ return $('#stats_post_count').text().trim().replace(/\D/g, '')
258
+ }
259
+
260
+ /**
261
+ * 获取文章数量
262
+ * @returns {string} 文章数量
263
+ */
264
+ export function getArticleCount() {
265
+ return $('#stats_article_count').text().trim().replace(/\D/g, '')
266
+ }
267
+
268
+ /**
269
+ * 获取评论数量
270
+ * @returns {string} 评论数量
271
+ */
272
+ export function getCommentCount() {
273
+ return $('#stats-comment_count').text().trim().replace(/\D/g, '')
274
+ }
275
+
276
+ /**
277
+ * 获取博客访问总量
278
+ * @returns {string} 博客访问总量
279
+ */
280
+ export function getViewCount() {
281
+ return $('#stats-total-view-count>span').text().trim()
282
+ }
@@ -0,0 +1,418 @@
1
+ /**
2
+ * 将字符串复制到剪贴板
3
+ */
4
+ export function copyToClipboard(str) {
5
+ return navigator.clipboard.writeText(str)
6
+ }
7
+
8
+ /**
9
+ * 监听 DOM 变化
10
+ */
11
+ export function createMutationObserve(selector, callback) {
12
+ const observer = new MutationObserver(() => {
13
+ callback().then(() => {
14
+ observer.disconnect()
15
+ })
16
+ })
17
+ observer.observe(selector, {
18
+ attributes: true,
19
+ childList: true,
20
+ subtree: true,
21
+ })
22
+ }
23
+
24
+ /**
25
+ * HTML 反转义
26
+ */
27
+ export function HTMLDecode(str) {
28
+ return $('<textarea/>').html(str).text()
29
+ }
30
+
31
+ /**
32
+ * 插入 css
33
+ */
34
+ export function insertStyle(style) {
35
+ const styleElement = document.createElement('style')
36
+ styleElement.innerHTML = style
37
+ document.head.appendChild(styleElement)
38
+ }
39
+
40
+ /**
41
+ * 监听鼠标滚轮
42
+ * @param {Function} upCallback 向上滚动回调
43
+ * @param {Function} downCallback 向下滚动回调
44
+ */
45
+ export function mousewheel(upCallback, downCallback) {
46
+ if (!downCallback) {
47
+ downCallback = upCallback
48
+ }
49
+ const removeListener = () => {
50
+ $(document).unbind('mousewheel DOMMouseScroll')
51
+ }
52
+ const up = () => {
53
+ upCallback()
54
+ removeListener()
55
+ }
56
+ const down = () => {
57
+ upCallback()
58
+ removeListener()
59
+ }
60
+ $(document).on('mousewheel DOMMouseScroll', (e) => {
61
+ // e.preventDefault()
62
+ const wheel = e.originalEvent.wheelDelta || -e.originalEvent.detail
63
+ const delta = Math.max(-1, Math.min(1, wheel))
64
+ delta < 0 ? up() : down()
65
+ })
66
+ }
67
+
68
+ /**
69
+ * 获取季节
70
+ */
71
+ export function getQuarter() {
72
+ const month = new Date().getMonth()
73
+ if (month < 3) {
74
+ return 'Spring'
75
+ } else if (month < 6) {
76
+ return 'Summer'
77
+ } else if (month < 9) {
78
+ return 'Autumn'
79
+ } else if (month < 12) {
80
+ return 'Winter'
81
+ }
82
+ }
83
+
84
+ /**
85
+ * 获取英文月份
86
+ * @returns {string} 英文月份单词
87
+ */
88
+ export function getMonth() {
89
+ const monthsInEng = [
90
+ 'Jan',
91
+ 'Feb',
92
+ 'March',
93
+ 'Apr',
94
+ 'May',
95
+ 'Jun',
96
+ 'Jul',
97
+ 'Aug',
98
+ 'Sept',
99
+ 'Oct',
100
+ 'Nov',
101
+ 'Dec',
102
+ ]
103
+ const month = new Date().getMonth()
104
+ return monthsInEng[month]
105
+ }
106
+
107
+ /**
108
+ * 判断元素是否在视口范围内
109
+ * @param {object} el - DOM selector
110
+ * @returns {boolean} 元素是否在视口范围内
111
+ */
112
+ export function isElementInViewport(el) {
113
+ const rect = el.getBoundingClientRect()
114
+ return (
115
+ rect.top >= 0 &&
116
+ rect.left >= 0 &&
117
+ rect.bottom <=
118
+ (window.innerHeight || document.documentElement.clientHeight) &&
119
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
120
+ )
121
+ }
122
+
123
+ /**
124
+ * 创建 link 标签
125
+ * @param {string} href - css 链接
126
+ */
127
+ export function loadLink(href) {
128
+ $('head').append('<link>')
129
+ const link = $('head').children(':last')
130
+ link.attr({
131
+ rel: 'stylesheet',
132
+ type: 'text/css',
133
+ href,
134
+ })
135
+ }
136
+
137
+ /**
138
+ * 判断当前是否为夜间
139
+ * @returns {boolean} 是否为夜间
140
+ */
141
+ export function isNight() {
142
+ const nowHour = new Date().getHours()
143
+ const isNight = nowHour > 19 || nowHour <= 5
144
+ return isNight
145
+ }
146
+
147
+ /**
148
+ * 支持颜色的控制台打印函数
149
+ * @param {string} str - 要打印的字符串
150
+ * @param {string} color - 打印颜色
151
+ */
152
+ export function prettyLog(str, color = '#ffb3cc') {
153
+ // eslint-disable-next-line no-console
154
+ console.log(`%c ${str}`, `color: ${color}; font-weight: bold;`)
155
+ }
156
+
157
+ /**
158
+ * 获取今天的日期,格式: yyyy-MM-dd
159
+ * @returns {string} 今天的日期
160
+ */
161
+ export function getDate() {
162
+ const time = new Date()
163
+ const year = time.getFullYear()
164
+ const month = `0${time.getMonth() + 1}`.slice(-2)
165
+ const day = `0${time.getDate()}`.slice(-2)
166
+ // const hour = ('0' + time.getHours()).slice(-2)
167
+ // const minute = ('0' + time.getMinutes()).slice(-2)
168
+ // const second = ('0' + time.getSeconds()).slice(-2)
169
+ const today = `${year}-${month}-${day}`
170
+ return today
171
+ }
172
+
173
+ /**
174
+ * 获取数组中随机元素
175
+ * @param {Array} arr - 任意数组
176
+ * @param {number} count - 要获取的随机元素的数量
177
+ * @returns {any} 可能是数组中的任意指定数量的元素
178
+ */
179
+ export function randomArrayElements(arr, count = 1) {
180
+ const shuffled = arr.slice(0)
181
+ let i = arr.length
182
+ const min = i - count
183
+ let temp
184
+ let index
185
+ while (i-- > min) {
186
+ index = Math.floor((i + 1) * Math.random())
187
+ temp = shuffled[index]
188
+ shuffled[index] = shuffled[i]
189
+ shuffled[i] = temp
190
+ }
191
+ return shuffled.slice(min)
192
+ }
193
+
194
+ /**
195
+ * sleep
196
+ */
197
+ export async function sleep(time) {
198
+ return new Promise((res) => setTimeout(res, time))
199
+ }
200
+
201
+ /**
202
+ * 获取一个随机图片 url
203
+ * @returns {string} 随机图片 url
204
+ */
205
+ export function randomImgUrl() {
206
+ const animeImages = 'https://api.mz-moe.cn/img'
207
+ const random = Math.floor(Math.random() * 950)
208
+ const url = `${animeImages}/img${random}.jpg`
209
+ return url
210
+ }
211
+
212
+ /**
213
+ * 滚动穿透处理
214
+ * @param {boolean} show - 蒙层是否已经显示
215
+ */
216
+ export function unpass(show) {
217
+ if (show) {
218
+ const body = document.body
219
+ body.style.position = ''
220
+ const top = body.style.top
221
+
222
+ document.body.scrollTop = document.documentElement.scrollTop =
223
+ -Number.parseInt(top, 10)
224
+ body.style.top = ''
225
+ } else {
226
+ const scrollTop =
227
+ document.body.scrollTop || document.documentElement.scrollTop
228
+ document.body.style.cssText += `position:fixed;width:100%;top:-${scrollTop}px;`
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 轮询
234
+ */
235
+ export function poll(conditionFn, callback) {
236
+ if (conditionFn()) {
237
+ const res = callback()
238
+ if (typeof res === 'boolean' || typeof res === 'string') {
239
+ return res
240
+ }
241
+ return true
242
+ }
243
+ let count = 1
244
+ const intervalId = setInterval(() => {
245
+ if (conditionFn()) {
246
+ const res = callback()
247
+ if (typeof res === 'boolean' || typeof res === 'string') {
248
+ return res
249
+ }
250
+ clearInterval(intervalId)
251
+ return true
252
+ }
253
+ if (count === 50) {
254
+ clearInterval(intervalId)
255
+ return false
256
+ }
257
+ count++
258
+ }, 500)
259
+ }
260
+
261
+ /**
262
+ * 加载 script
263
+ * @param {string} url - script 链接
264
+ * @param {Function} callback - 加载成功后要执行的回调函数
265
+ */
266
+ export function loadScript(url, callback = () => {}) {
267
+ $.ajax({
268
+ type: 'GET',
269
+ dataType: 'script',
270
+ cache: true,
271
+ url,
272
+ success() {
273
+ callback()
274
+ },
275
+ })
276
+ }
277
+
278
+ export function debounce(func, wait, immediate) {
279
+ let timeout
280
+ return function (...args) {
281
+ const later = () => {
282
+ timeout = null
283
+ if (!immediate) {
284
+ func.apply(this, args)
285
+ }
286
+ }
287
+ const callNow = immediate && !timeout
288
+ clearTimeout(timeout)
289
+ timeout = setTimeout(later, wait)
290
+ if (callNow) {
291
+ func.apply(this, args)
292
+ }
293
+ }
294
+ }
295
+
296
+ export function throttle(func, wait, mustRun) {
297
+ let timeout
298
+ let startTime = new Date()
299
+
300
+ return function (...args) {
301
+ const curTime = new Date()
302
+
303
+ clearTimeout(timeout)
304
+
305
+ if (curTime - startTime >= mustRun) {
306
+ func.apply(this, args)
307
+ startTime = curTime
308
+ } else {
309
+ timeout = setTimeout(() => func.apply(this, args), wait)
310
+ }
311
+ }
312
+ }
313
+
314
+ /**
315
+ * 获取对象的随机属性
316
+ * @param {object} obj - JS 对象
317
+ * @returns 对象的随机属性
318
+ */
319
+ export function randomProperty(obj) {
320
+ let result
321
+ let count = 0
322
+ for (const prop in obj) {
323
+ if (Math.random() < 1 / ++count) {
324
+ result = prop
325
+ }
326
+ }
327
+ return result
328
+ }
329
+
330
+ /**
331
+ * 获取随机颜色
332
+ * @param {string} type - 返回的颜色值类型 "rgba" | "16"
333
+ * @returns 随机颜色值
334
+ */
335
+ export function randomColor(type) {
336
+ let res = ''
337
+ if (type === 'rgba') {
338
+ const r = Math.floor(Math.random() * 256)
339
+ const g = Math.floor(Math.random() * 256)
340
+ const b = Math.floor(Math.random() * 256)
341
+ const a = 0.6
342
+ res = `rgba(${r},${g},${b},${a})`
343
+ } else if (type === '16') {
344
+ res = `#${Math.floor(Math.random() * 0xffffff).toString(16)}`
345
+ } else {
346
+ const colors = type || [
347
+ '#FE0302',
348
+ '#FF7204',
349
+ '#FFAA02',
350
+ '#FFD302',
351
+ '#FFFF00',
352
+ '#A0EE00',
353
+ '#00CD00',
354
+ '#019899',
355
+ '#4266BE',
356
+ '#89D5FF',
357
+ '#CC0273',
358
+ '#CC0273',
359
+ ]
360
+ const random = Math.floor(Math.random() * colors.length)
361
+ res = colors[random]
362
+ }
363
+ return res
364
+ }
365
+
366
+ /**
367
+ * 获取元素相对与浏览器视口的位置
368
+ * @param {object} el - DOM 对象
369
+ * @returns {object} "top", "bottom", "left", "right", "height", "width"
370
+ */
371
+ export function getClientRect(el) {
372
+ const { top, bottom, left, right, height, width } = el.getBoundingClientRect()
373
+ return {
374
+ top,
375
+ bottom,
376
+ left,
377
+ right,
378
+ height: height || bottom - top,
379
+ width: width || right - left,
380
+ }
381
+ }
382
+
383
+ /**
384
+ * 生成随机数
385
+ * @param {number} max - 最大值
386
+ * @param {number} min - 最小值
387
+ * @returns 介于最大值与最小值闭区间的随机数
388
+ */
389
+ export function randomNum(max, min) {
390
+ Number.parseInt(Math.random() * (max - min + 1) + min, 10)
391
+ return Math.floor(Math.random() * (max - min + 1) + min)
392
+ }
393
+
394
+ /**
395
+ * 返回用户设备类型
396
+ * @returns {string} 'pc' | 'phone'
397
+ */
398
+ export function userAgent() {
399
+ const width = $(window).width()
400
+ return width > 768 ? 'pc' : 'phone'
401
+ }
402
+
403
+ /**
404
+ * 判断当前设备是否为手机
405
+ * @returns {boolean} 当前设备是否为手机
406
+ */
407
+ export function isPhone() {
408
+ const width = $(window).width()
409
+ return width <= 768
410
+ }
411
+
412
+ /**
413
+ * 判断字符串是否为 http 网址
414
+ * @returns {boolean} 是否为 http 网址
415
+ */
416
+ export function isUrl(string) {
417
+ return /http/.test(string)
418
+ }
@@ -0,0 +1,2 @@
1
+ export const isFunction = (val) => typeof val === 'function'
2
+ export const extend = Object.assign