cross-origin-storage

跨域本地存储

当前为 2024-05-28 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/473442/1384321/cross-origin-storage.js

  1. // @name cross-origin-storage
  2. // @name:zh 跨域本地存储
  3. // @namespace https://github.com/pansong291/
  4. // @version 1.0.1
  5. // @author paso
  6. // @license Apache-2.0
  7.  
  8. ;(function () {
  9. 'use strict'
  10.  
  11. const __msgType = 'cross-origin-storage'
  12.  
  13. /**
  14. * 生成随机ID
  15. */
  16. function uuid() {
  17. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  18. const r = (Math.random() * 16) | 0,
  19. v = c === 'x' ? r : (r & 0x3) | 0x8
  20. return v.toString(16)
  21. })
  22. }
  23.  
  24. function createStorageClient(middlewareUrl) {
  25. const iframe = document.createElement('iframe')
  26. iframe.src = middlewareUrl
  27. iframe.setAttribute('style', 'display: none !important;')
  28. window.document.body.appendChild(iframe)
  29. return startStorageClient(iframe.contentWindow)
  30. }
  31.  
  32. function startStorageClient(iframeWindow) {
  33. const _requests = {} // 所有请求消息数据映射
  34. // Server 是否已准备完成以及缓存的请求队列
  35. const _cache = {
  36. ready: false,
  37. queue: []
  38. }
  39. // 监听 Server 发来的消息
  40. window.addEventListener('message', (e) => {
  41. if (e?.data?.__msgType !== __msgType) return
  42. if (e.data.ready) {
  43. // Server 已准备完成, 发送队列中的全部请求
  44. _cache.ready = true
  45. while (_cache.queue.length) {
  46. iframeWindow.postMessage(_cache.queue.shift(), '*')
  47. }
  48. return
  49. }
  50. let { id, response } = e.data
  51.  
  52. // 找到消息对应的回调函数
  53. let currentCallback = _requests[id]
  54. if (!currentCallback) return
  55. // 调用并返回数据
  56. currentCallback(response, e.data)
  57. delete _requests[id]
  58. })
  59.  
  60. /**
  61. * 发起请求函数
  62. * @param method 请求方式
  63. * @param key
  64. * @param value
  65. */
  66. function _requestFn(method, key, value) {
  67. return new Promise((resolve) => {
  68. const req = {
  69. id: uuid(),
  70. method,
  71. key,
  72. value,
  73. __msgType
  74. }
  75.  
  76. // 请求唯一标识 id 和回调函数的映射
  77. _requests[req.id] = resolve
  78.  
  79. if (_cache.ready) {
  80. // Server 已准备完成时直接发请求
  81. iframeWindow.postMessage(req, '*')
  82. } else {
  83. // Server 未准备完成则把请求放入队列
  84. _cache.queue.push(req)
  85. }
  86. })
  87. }
  88.  
  89. return {
  90. /**
  91. * 获取存储数据
  92. * @param {Iterable | Object | string} key
  93. */
  94. getItem(key) {
  95. return _requestFn('get', key)
  96. },
  97. /**
  98. * 更新存储数据
  99. * @param {Object | string} key
  100. * @param {?Object | ?string} value
  101. */
  102. setItem(key, value = void 0) {
  103. return _requestFn('set', key, value)
  104. },
  105. /**
  106. * 删除数据
  107. * @param {Iterable | Object | string} key
  108. */
  109. delItem(key) {
  110. return _requestFn('delete', key)
  111. },
  112. /**
  113. * 清除数据
  114. */
  115. clear() {
  116. return _requestFn('clear')
  117. }
  118. }
  119. }
  120.  
  121. function startStorageServer() {
  122. if (window.parent === window) return
  123. const functionMap = {
  124. /**
  125. * 设置数据
  126. * @param {Object | string} key
  127. * @param {?Object | ?string} value
  128. */
  129. setStore(key, value = void 0) {
  130. if (!key) return
  131. if (typeof key === 'string') {
  132. return localStorage.setItem(key, typeof value === 'object' ? JSON.stringify(value) : value)
  133. }
  134. Object.keys(key).forEach((dataKey) => {
  135. let dataValue = typeof key[dataKey] === 'object' ? JSON.stringify(key[dataKey]) : key[dataKey]
  136. localStorage.setItem(dataKey, dataValue)
  137. })
  138. },
  139.  
  140. /**
  141. * 获取数据
  142. * @param {Iterable | Object | string} key
  143. */
  144. getStore(key) {
  145. if (!key) return
  146. if (typeof key === 'string') return localStorage.getItem(key)
  147. let dataRes = {}
  148. const keys = key[Symbol.iterator] ? key : Object.keys(key)
  149. for (const dataKey of keys) {
  150. dataRes[dataKey] = localStorage.getItem(dataKey) || null
  151. }
  152. return dataRes
  153. },
  154.  
  155. /**
  156. * 删除数据
  157. * @param {Iterable | Object | string} key
  158. */
  159. deleteStore(key) {
  160. if (!key) return
  161. if (typeof key === 'string') return localStorage.removeItem(key)
  162. const keys = key[Symbol.iterator] ? key : Object.keys(key)
  163. for (const dataKey of keys) {
  164. localStorage.removeItem(dataKey)
  165. }
  166. },
  167.  
  168. /**
  169. * 清空
  170. */
  171. clearStore() {
  172. localStorage.clear()
  173. }
  174. }
  175.  
  176. // 监听 Client 消息
  177. window.addEventListener('message', (e) => {
  178. if (e?.data?.__msgType !== __msgType) return
  179. const { method, key, value, id = 'default' } = e.data
  180.  
  181. // 获取方法
  182. const func = functionMap[`${method}Store`]
  183.  
  184. // 取出本地的数据
  185. const response = {
  186. data: func?.(key, value)
  187. }
  188. if (!func) response.errorMsg = 'Request method error!'
  189.  
  190. // 发送给 Client
  191. window.parent.postMessage(
  192. {
  193. id,
  194. request: e.data,
  195. response,
  196. __msgType
  197. },
  198. '*'
  199. )
  200. })
  201.  
  202. // 通知 Client, Server 已经准备完成
  203. window.parent.postMessage(
  204. {
  205. ready: true,
  206. __msgType
  207. },
  208. '*'
  209. )
  210. }
  211.  
  212. if (!window.paso || !(window.paso instanceof Object)) window.paso = {}
  213. window.paso.crossOriginStorage = {
  214. startStorageServer,
  215. startStorageClient,
  216. createStorageClient
  217. }
  218. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址