composables.mjs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*!
  2. * vue-router v3.6.5
  3. * (c) 2022 Evan You
  4. * @license MIT
  5. */
  6. import { getCurrentInstance, effectScope, shallowReactive, onUnmounted, computed, unref } from 'vue';
  7. // dev only warn if no current instance
  8. function throwNoCurrentInstance (method) {
  9. if (!getCurrentInstance()) {
  10. throw new Error(
  11. ("[vue-router]: Missing current instance. " + method + "() must be called inside <script setup> or setup().")
  12. )
  13. }
  14. }
  15. function useRouter () {
  16. if (process.env.NODE_ENV !== 'production') {
  17. throwNoCurrentInstance('useRouter');
  18. }
  19. return getCurrentInstance().proxy.$root.$router
  20. }
  21. function useRoute () {
  22. if (process.env.NODE_ENV !== 'production') {
  23. throwNoCurrentInstance('useRoute');
  24. }
  25. var root = getCurrentInstance().proxy.$root;
  26. if (!root._$route) {
  27. var route = effectScope(true).run(function () { return shallowReactive(Object.assign({}, root.$router.currentRoute)); }
  28. );
  29. root._$route = route;
  30. root.$router.afterEach(function (to) {
  31. Object.assign(route, to);
  32. });
  33. }
  34. return root._$route
  35. }
  36. function onBeforeRouteUpdate (guard) {
  37. if (process.env.NODE_ENV !== 'production') {
  38. throwNoCurrentInstance('onBeforeRouteUpdate');
  39. }
  40. return useFilteredGuard(guard, isUpdateNavigation)
  41. }
  42. function isUpdateNavigation (to, from, depth) {
  43. var toMatched = to.matched;
  44. var fromMatched = from.matched;
  45. return (
  46. toMatched.length >= depth &&
  47. toMatched
  48. .slice(0, depth + 1)
  49. .every(function (record, i) { return record === fromMatched[i]; })
  50. )
  51. }
  52. function isLeaveNavigation (to, from, depth) {
  53. var toMatched = to.matched;
  54. var fromMatched = from.matched;
  55. return toMatched.length < depth || toMatched[depth] !== fromMatched[depth]
  56. }
  57. function onBeforeRouteLeave (guard) {
  58. if (process.env.NODE_ENV !== 'production') {
  59. throwNoCurrentInstance('onBeforeRouteLeave');
  60. }
  61. return useFilteredGuard(guard, isLeaveNavigation)
  62. }
  63. var noop = function () {};
  64. function useFilteredGuard (guard, fn) {
  65. var instance = getCurrentInstance();
  66. var router = useRouter();
  67. var target = instance.proxy;
  68. // find the nearest RouterView to know the depth
  69. while (
  70. target &&
  71. target.$vnode &&
  72. target.$vnode.data &&
  73. target.$vnode.data.routerViewDepth == null
  74. ) {
  75. target = target.$parent;
  76. }
  77. var depth =
  78. target && target.$vnode && target.$vnode.data
  79. ? target.$vnode.data.routerViewDepth
  80. : null;
  81. if (depth != null) {
  82. var removeGuard = router.beforeEach(function (to, from, next) {
  83. return fn(to, from, depth) ? guard(to, from, next) : next()
  84. });
  85. onUnmounted(removeGuard);
  86. return removeGuard
  87. }
  88. return noop
  89. }
  90. /* */
  91. function guardEvent (e) {
  92. // don't redirect with control keys
  93. if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) { return }
  94. // don't redirect when preventDefault called
  95. if (e.defaultPrevented) { return }
  96. // don't redirect on right click
  97. if (e.button !== undefined && e.button !== 0) { return }
  98. // don't redirect if `target="_blank"`
  99. if (e.currentTarget && e.currentTarget.getAttribute) {
  100. var target = e.currentTarget.getAttribute('target');
  101. if (/\b_blank\b/i.test(target)) { return }
  102. }
  103. // this may be a Weex event which doesn't have this method
  104. if (e.preventDefault) {
  105. e.preventDefault();
  106. }
  107. return true
  108. }
  109. function includesParams (outer, inner) {
  110. var loop = function ( key ) {
  111. var innerValue = inner[key];
  112. var outerValue = outer[key];
  113. if (typeof innerValue === 'string') {
  114. if (innerValue !== outerValue) { return { v: false } }
  115. } else {
  116. if (
  117. !Array.isArray(outerValue) ||
  118. outerValue.length !== innerValue.length ||
  119. innerValue.some(function (value, i) { return value !== outerValue[i]; })
  120. ) {
  121. return { v: false }
  122. }
  123. }
  124. };
  125. for (var key in inner) {
  126. var returned = loop( key );
  127. if ( returned ) return returned.v;
  128. }
  129. return true
  130. }
  131. // helpers from vue router 4
  132. function isSameRouteLocationParamsValue (a, b) {
  133. return Array.isArray(a)
  134. ? isEquivalentArray(a, b)
  135. : Array.isArray(b)
  136. ? isEquivalentArray(b, a)
  137. : a === b
  138. }
  139. function isEquivalentArray (a, b) {
  140. return Array.isArray(b)
  141. ? a.length === b.length && a.every(function (value, i) { return value === b[i]; })
  142. : a.length === 1 && a[0] === b
  143. }
  144. function isSameRouteLocationParams (a, b) {
  145. if (Object.keys(a).length !== Object.keys(b).length) { return false }
  146. for (var key in a) {
  147. if (!isSameRouteLocationParamsValue(a[key], b[key])) { return false }
  148. }
  149. return true
  150. }
  151. function useLink (props) {
  152. if (process.env.NODE_ENV !== 'production') {
  153. throwNoCurrentInstance('useLink');
  154. }
  155. var router = useRouter();
  156. var currentRoute = useRoute();
  157. var resolvedRoute = computed(function () { return router.resolve(unref(props.to), currentRoute); });
  158. var activeRecordIndex = computed(function () {
  159. var route = resolvedRoute.value.route;
  160. var matched = route.matched;
  161. var length = matched.length;
  162. var routeMatched = matched[length - 1];
  163. var currentMatched = currentRoute.matched;
  164. if (!routeMatched || !currentMatched.length) { return -1 }
  165. var index = currentMatched.indexOf(routeMatched);
  166. if (index > -1) { return index }
  167. // possible parent record
  168. var parentRecord = currentMatched[currentMatched.length - 2];
  169. return (
  170. // we are dealing with nested routes
  171. length > 1 &&
  172. // if the parent and matched route have the same path, this link is
  173. // referring to the empty child. Or we currently are on a different
  174. // child of the same parent
  175. parentRecord && parentRecord === routeMatched.parent
  176. )
  177. });
  178. var isActive = computed(
  179. function () { return activeRecordIndex.value > -1 &&
  180. includesParams(currentRoute.params, resolvedRoute.value.route.params); }
  181. );
  182. var isExactActive = computed(
  183. function () { return activeRecordIndex.value > -1 &&
  184. activeRecordIndex.value === currentRoute.matched.length - 1 &&
  185. isSameRouteLocationParams(currentRoute.params, resolvedRoute.value.route.params); }
  186. );
  187. var navigate = function (e) {
  188. var href = resolvedRoute.value.route;
  189. if (guardEvent(e)) {
  190. return props.replace
  191. ? router.replace(href)
  192. : router.push(href)
  193. }
  194. return Promise.resolve()
  195. };
  196. return {
  197. href: computed(function () { return resolvedRoute.value.href; }),
  198. route: computed(function () { return resolvedRoute.value.route; }),
  199. isExactActive: isExactActive,
  200. isActive: isActive,
  201. navigate: navigate
  202. }
  203. }
  204. export { isSameRouteLocationParams, onBeforeRouteLeave, onBeforeRouteUpdate, useLink, useRoute, useRouter };