'f'
mh-two-thousand-and-two
2024-04-12 26f2711ef9461961fb953e2b497bd314ef95e345
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import getRealRoute from '../../get-real-route'
 
function encodeQueryString (url) {
  if (typeof url !== 'string') {
    return url
  }
  const index = url.indexOf('?')
 
  if (index === -1) {
    return url
  }
 
  const query = url.substr(index + 1).trim().replace(/^(\?|#|&)/, '')
 
  if (!query) {
    return url
  }
 
  url = url.substr(0, index)
 
  const params = []
 
  query.split('&').forEach(param => {
    const parts = param.replace(/\+/g, ' ').split('=')
    const key = parts.shift()
    const val = parts.length > 0
      ? parts.join('=')
      : ''
 
    params.push(key + '=' + encodeURIComponent(val))
  })
 
  return params.length ? url + '?' + params.join('&') : url
}
 
function createValidator (type) {
  return function validator (url, params) {
    // 格式化为绝对路径路由
    url = getRealRoute(url)
 
    const pagePath = url.split('?')[0]
    // 匹配路由是否存在
    const routeOptions = __uniRoutes.find(({
      path,
      alias
    }) => path === pagePath || alias === pagePath)
 
    if (!routeOptions) {
      return 'page `' + url + '` is not found'
    }
 
    // 检测不同类型跳转
    if (type === 'navigateTo' || type === 'redirectTo') {
      if (routeOptions.meta.isTabBar) {
        return `can not ${type} a tabbar page`
      }
    } else if (type === 'switchTab') {
      if (!routeOptions.meta.isTabBar) {
        return 'can not switch to no-tabBar page'
      }
    }
 
    // switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
    if (
      (type === 'switchTab' || type === 'preloadPage') &&
      routeOptions.meta.isTabBar &&
      params.openType !== 'appLaunch'
    ) {
      url = pagePath
    }
 
    // 首页自动格式化为`/`
    if (routeOptions.meta.isEntry) {
      url = url.replace(routeOptions.alias, '/')
    }
 
    // 参数格式化
    params.url = encodeQueryString(url)
    if (type === 'unPreloadPage') {
      return
    } else if (type === 'preloadPage') {
      if (__PLATFORM__ === 'app-plus') {
        if (!routeOptions.meta.isNVue) {
          return 'can not preload vue page'
        }
      }
      if (routeOptions.meta.isTabBar) {
        const pages = getCurrentPages(true)
        const tabBarPagePath = (routeOptions.alias || routeOptions.path).substr(1)
        if (pages.find(page => page.route === tabBarPagePath)) {
          return 'tabBar page `' + tabBarPagePath + '` already exists'
        }
      }
      return
    }
 
    // 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
    if (navigatorLock === url && params.openType !== 'appLaunch') {
      return `${navigatorLock} locked`
    }
    // 至少 onLaunch 之后,再启用lock逻辑(onLaunch之前可能开发者手动调用路由API,来提前跳转)
    // enableNavigatorLock 临时开关(不对外开放),避免该功能上线后,有部分情况异常,可以让开发者临时关闭 lock 功能
    if (__uniConfig.ready && __uniConfig.enableNavigatorLock !== false) {
      navigatorLock = url
    }
  }
}
 
let navigatorLock
 
function createProtocol (type, extras = {}) {
  return Object.assign({
    url: {
      type: String,
      required: true,
      validator: createValidator(type)
    },
    beforeAll () {
      navigatorLock = ''
    }
  }, extras)
}
 
function createAnimationProtocol (animationTypes) {
  return {
    animationType: {
      type: String,
      validator (type) {
        if (type && animationTypes.indexOf(type) === -1) {
          return '`' + type + '` is not supported for `animationType` (supported values are: `' + animationTypes.join(
            '`|`') + '`)'
        }
      }
    },
    animationDuration: {
      type: Number
    }
  }
}
 
export const redirectTo = createProtocol('redirectTo')
 
export const reLaunch = createProtocol('reLaunch')
 
export const navigateTo = createProtocol('navigateTo', createAnimationProtocol(
  [
    'slide-in-right',
    'slide-in-left',
    'slide-in-top',
    'slide-in-bottom',
    'fade-in',
    'zoom-out',
    'zoom-fade-out',
    'pop-in',
    'none'
  ]
))
 
export const switchTab = createProtocol('switchTab')
 
export const navigateBack = Object.assign({
  delta: {
    type: Number,
    validator (delta, params) {
      delta = parseInt(delta) || 1
      params.delta = Math.min(getCurrentPages().length - 1, delta)
    }
  }
}, createAnimationProtocol(
  [
    'slide-out-right',
    'slide-out-left',
    'slide-out-top',
    'slide-out-bottom',
    'fade-out',
    'zoom-in',
    'zoom-fade-in',
    'pop-out',
    'none'
  ]
))
 
export const preloadPage = {
  url: {
    type: String,
    required: true,
    validator: createValidator('preloadPage')
  }
}
 
export const unPreloadPage = {
  url: {
    type: String,
    required: true,
    validator: createValidator('unPreloadPage')
  }
}