useTransfer.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import {onLoad} from "@dcloudio/uni-app"
  2. import {computed, onUnmounted, readonly, ref, nextTick} from "vue"
  3. import {array, empty, object, string} from "@/uni_modules/uv-ui-tools/libs/function/test";
  4. import mxConst, {getTabRoutes} from "@/common/mxConst";
  5. import {guid, sleep} from "@/uni_modules/uv-ui-tools/libs/function";
  6. import baseConfig from "@/config";
  7. import mxConfig from "@/common/mxConfig";
  8. import {useH5BackHome} from "@/components/mx-nav-bar/useH5BackHome";
  9. import {createEventHook, injectLocal, provideLocal} from "@vueuse/core";
  10. import _ from 'lodash';
  11. export const useTransfer = function () {
  12. // data
  13. const cacheKey = ref('')
  14. const prevData = ref({})
  15. const usingCacheTransfer = computed(() => !!cacheKey.value)
  16. // 回传事件,只要在transferTo中定义一个callback字符串标识即可响应回调事件
  17. // 用uni.$on/$off/$emit来实现,如果要通用的话,可以考虑自行实现一个全局的eventBus
  18. const pageCallback = createEventHook() // 使用hook给transfer外部用户提供钩子
  19. const eventName = ref('') // 给发起跳转的页面记录事件注册, 用于自动注销
  20. const callbackEventData = ref(null) // 给当前页面存放数据,用于回传
  21. // hooks
  22. onLoad((opt) => {
  23. if (opt.cacheKey) cacheKey.value = opt.cacheKey, prevData.value = uni.getStorageSync(opt.cacheKey)
  24. else prevData.value = JSON.parse(decodeURIComponent(opt.data || '{}'))
  25. })
  26. onUnmounted(() => {
  27. if (usingCacheTransfer.value) uni.removeStorageSync(cacheKey.value)
  28. // 发起跳转的页面注销事件
  29. if (eventName.value) uni.$off(eventName.value)
  30. })
  31. // methods
  32. /*
  33. * main function for route, it keeps params type and supports big data transfer.
  34. * Note: if you defined `callback` in params, 2 pages will auto support onPageCallback event.
  35. * @param {String|Object} urlOrOptions - route url or options
  36. * @param {Object} props - indicates props to pickup from source data
  37. * @param {Array} source - source data array, default is [prevData.value]
  38. * @param {Boolean} usingCache - whether to use cache, default is false, for big data transfer
  39. * */
  40. const transferTo = function (urlOrOptions, props = {}, source = null, usingCache = false) {
  41. const options = object(urlOrOptions) ? urlOrOptions
  42. : {url: urlOrOptions, type: getTabRoutes().includes(urlOrOptions) ? 'tab' : 'to'}
  43. // confirm params
  44. let params = options.params || {}
  45. let extra = {}
  46. // prevData 自动包含是名学测评系统的逻辑,暂时不用去掉,以免引起一些数值覆盖的问题
  47. const extraSource = [/*prevData.value*/].concat(source)
  48. if (array(props)) extra = _.merge({}, ..._.map(extraSource, obj => _.pick(obj, props)))
  49. else if (object(props)) extra = _.merge(props, ..._.map(extraSource, obj => _.pick(obj, _.keys(props))))
  50. params = _.merge(params, extra)
  51. // handle params, using JSON.stringify or uni.setStorageSync
  52. let formatParams = params
  53. if (!empty(params)) {
  54. if (usingCache) {
  55. const storageKey = mxConst.keyCacheUniquePrefix + guid()
  56. uni.setStorageSync(storageKey, params)
  57. formatParams = {cacheKey: storageKey}
  58. } else {
  59. formatParams = {data: encodeURIComponent(JSON.stringify(params))}
  60. }
  61. }
  62. // page callback event // 注意这是在发起跳转的页面监听
  63. if (string(params.callback) && params.callback) {
  64. eventName.value = params.callback
  65. uni.$off(eventName.value) // 先清除其它注册,只注册一次
  66. uni.$on(eventName.value, handleCallback)
  67. }
  68. // 这里并没有干涉其它参数,所以$uv.route支持的功能这里应该都能用
  69. options.params = formatParams
  70. uni.$uv.route(options)
  71. console.log('transferTo:', options, params)
  72. }
  73. const handleCallback = async function (event) {
  74. await pageCallback.trigger(event)
  75. }
  76. const transferBack = function (options = {type: 'back'}) {
  77. // 主动调用transferBack的地方自动处理回调
  78. if (prevData.value.callback) {
  79. // 这里做了一个延迟处理,让回调发生在页面跳转之后,
  80. // 这样的话,页面因为数据变化引起的滚动条重置问题看起来平滑一些。
  81. // 如entry-single页面,换选学校之后滚动条由于缓存机制会停在选择学校之前的位置,
  82. // 即使设置了scrollTop也不起作用,这里延迟可以保证重置行为发生在滚动条缓存机制之后。
  83. const e = prevData.value.callback, arg = callbackEventData.value
  84. sleep().then(() => uni.$emit(e, arg))
  85. }
  86. const {hasPreviousPage} = useH5BackHome()
  87. if (hasPreviousPage.value) transferTo(options)
  88. else relaunch()
  89. }
  90. const transferToIndex = function () {
  91. transferTo(mxConst.routes.index)
  92. }
  93. const relaunch = function () {
  94. transferTo({...mxConst.routes.index, type: 'launch'})
  95. }
  96. const transferToWebView = function (url, title = '') {
  97. const nextPage = '/pages/h5/h5'
  98. transferTo(nextPage, {url, title})
  99. }
  100. const transferToProtocolUser = function () {
  101. const path = baseConfig.inlineSiteBaseUrl + mxConfig.inlineSiteFunctionPaths.protocolUser
  102. transferToWebView(path, '用户协议')
  103. }
  104. const transferToProtocolPrivacy = function () {
  105. const path = baseConfig.inlineSiteBaseUrl + mxConfig.inlineSiteFunctionPaths.protocolPrivacy
  106. transferToWebView(path, '隐私协议')
  107. }
  108. const transferToFAQ = function () {
  109. const path = baseConfig.inlineSiteBaseUrl + mxConfig.inlineSiteFunctionPaths.FAQ
  110. transferToWebView(path, '常见问题')
  111. }
  112. const playVideo = function (idOrSrc, aliIdType, title, callback = false) {
  113. transferTo(mxConst.routes.videoPlay, {aliId: idOrSrc, aliIdType, title, callback})
  114. }
  115. /*
  116. * tool function for clean all transfer cache data,
  117. * 这里提供了一个清除所有缓存数据的工具函数,
  118. * 可以用在一些管理性功能页中,如果页面非正常中断可能会累积一些缓存,
  119. * 这个函数可以用来清除所有缓存数据。
  120. * 注意:这个函数只是清除 transferTo 中 usingCache=true 产生缓存数据.
  121. * */
  122. const cleanAllTransferCacheData = function () {
  123. // 根据mxConst.keyCacheUniquePrefix清除所有缓存
  124. // 提供给某些管理性功能页使用,如果页面非正常中断可能会累积一些缓存
  125. const keys = uni.getStorageInfoSync().keys
  126. keys.forEach(key => {
  127. if (key.startsWith(mxConst.keyCacheUniquePrefix))
  128. uni.removeStorageSync(key)
  129. })
  130. }
  131. return {
  132. cacheKey: readonly(cacheKey), // 安全考虑,不允许外部修改
  133. prevData,
  134. usingCacheTransfer,
  135. eventName: readonly(eventName),
  136. onPageCallback: pageCallback.on,
  137. callbackEventData,
  138. transferTo,
  139. transferBack,
  140. transferToIndex,
  141. relaunch,
  142. transferToWebView,
  143. transferToProtocolUser,
  144. transferToProtocolPrivacy,
  145. transferToFAQ,
  146. playVideo,
  147. cleanAllTransferCacheData
  148. }
  149. }
  150. const key = Symbol('TRANSFER_SERVICE')
  151. export const useProvideTransfer = function () {
  152. const options = useTransfer()
  153. provideLocal(key, options)
  154. return options
  155. }
  156. export const useInjectTransfer = function () {
  157. return injectLocal(key)
  158. }