@mpxjs/webpack-plugin 2.10.3-beta.8 → 2.10.3-beta.9

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.
@@ -42,6 +42,7 @@ const wxs = require('./wxs')
42
42
  const component = require('./component')
43
43
  const fixComponentName = require('./fix-component-name')
44
44
  const rootPortal = require('./root-portal')
45
+ const titlebar = require('./titlebar')
45
46
 
46
47
  module.exports = function getComponentConfigs ({ warn, error }) {
47
48
  /**
@@ -125,6 +126,7 @@ module.exports = function getComponentConfigs ({ warn, error }) {
125
126
  hyphenTagName({ print }),
126
127
  label({ print }),
127
128
  component(),
128
- rootPortal({ print })
129
+ rootPortal({ print }),
130
+ titlebar({ print })
129
131
  ]
130
132
  }
@@ -0,0 +1,243 @@
1
+ <script>
2
+ import mpx from '@mpxjs/core'
3
+ export default {
4
+ name: 'mpx-titlebar',
5
+ props: {
6
+ // 来自 app.json 中 window 的 titlebar 相关配置
7
+ windowConfig: {
8
+ type: Object,
9
+ default: () => global.__mpxPageConfig
10
+ },
11
+ // 来自 页面 json 中的 titlebar 相关配置,会覆盖 windowConfig
12
+ pageConfig: {
13
+ type: Object,
14
+ default: () => ({})
15
+ }
16
+ },
17
+ computed: {
18
+ // 合并全局 window 配置与页面配置(页面配置覆盖全局配置)
19
+ cfg () {
20
+ return Object.assign({}, this.windowConfig || {}, this.pageConfig || {})
21
+ },
22
+ // 标题文本(兼容常见字段名)
23
+ titleText () {
24
+ return this.cfg.navigationBarTitleText || this.cfg.title || ''
25
+ },
26
+ // 背景色(兼容常见字段)
27
+ backgroundColor () {
28
+ return this.cfg.navigationBarBackgroundColor || '#ffffff'
29
+ },
30
+ // 文本颜色,微信小程序中 navigationBarTextStyle 为 white 或 black
31
+ textColor () {
32
+ const style = this.cfg.navigationBarTextStyle || 'black'
33
+ return style === 'white' ? '#ffffff' : '#000000'
34
+ },
35
+ // navigationStyle: 'default' | 'custom',custom 表示需要自定义绘制
36
+ navigationStyle () {
37
+ return this.cfg.navigationStyle || 'default'
38
+ },
39
+ // 是否隐藏(navigationStyle 为 'custom' 时也应隐藏)
40
+ hidden () {
41
+ return mpx.config?.webConfig?.enableTitleBar !== true || this.navigationStyle === 'custom'
42
+ },
43
+ // 是否展示返回按钮:根据浏览器历史判断(不依赖额外 page 配置)
44
+ showBack () {
45
+ console.log('showBack', this.$router.stack.length)
46
+ try {
47
+ return this.$router.stack.length > 1
48
+ } catch (e) {
49
+ return false
50
+ }
51
+ },
52
+ // safe area 顶部 padding,使用 env(safe-area-inset-top)
53
+ safeStyle () {
54
+ // 多数浏览器支持 env(), 为兼容也使用 constant() 备选(旧 iOS Safari)
55
+ return {
56
+ paddingTop: 'env(safe-area-inset-top, 0px)'
57
+ }
58
+ },
59
+ // 内部标题栏高度(遵循小程序常见平台差异)
60
+ innerHeight () {
61
+ const isIOS = /iP(hone|od|ad)/.test(navigator.userAgent)
62
+ return (isIOS ? 44 : 48) + 'px'
63
+ },
64
+ rootStyle () {
65
+ return {
66
+ background: this.backgroundColor,
67
+ color: this.textColor
68
+ }
69
+ },
70
+ innerStyle () {
71
+ return {
72
+ height: this.innerHeight
73
+ }
74
+ }
75
+ ,
76
+ // content wrapper style: padding-top to avoid being covered by fixed titlebar
77
+ contentStyle () {
78
+ // use calc to combine innerHeight and safe-area inset
79
+ return {
80
+ paddingTop: this.hidden ? '0px' : `calc(${this.innerHeight} + env(safe-area-inset-top, 0px))`,
81
+ // create its own layer to avoid overlapping issues
82
+ transform: 'translateZ(0)',
83
+ willChange: 'transform'
84
+ }
85
+ }
86
+ },
87
+ methods: {
88
+ // 左侧点击:派发事件并在可回退时回退
89
+ onLeftClick (e) {
90
+ this.$emit('click-left', e)
91
+ if (this.showBack) {
92
+ try { window.history.back() } catch (err) {}
93
+ }
94
+ }
95
+ },
96
+ render (h) {
97
+ const leftChildren = []
98
+
99
+ // default back button (SVG) — no left slot support
100
+ if (this.showBack) {
101
+ leftChildren.push(
102
+ h('button', {
103
+ class: 'mpx-titlebar__back',
104
+ attrs: { 'aria-label': 'back', type: 'button' }
105
+ }, [
106
+ h('svg', {
107
+ attrs: {
108
+ viewBox: '0 0 24 24',
109
+ width: '20',
110
+ height: '20',
111
+ fill: 'none',
112
+ xmlns: 'http://www.w3.org/2000/svg',
113
+ focusable: 'false',
114
+ 'aria-hidden': 'true'
115
+ }
116
+ }, [
117
+ h('path', {
118
+ attrs: {
119
+ d: 'M15 18l-6-6 6-6',
120
+ stroke: 'currentColor',
121
+ 'stroke-width': '2',
122
+ 'stroke-linecap': 'round',
123
+ 'stroke-linejoin': 'round'
124
+ }
125
+ })
126
+ ])
127
+ ])
128
+ )
129
+ }
130
+
131
+ // center shows title; only default slot (page content) is supported
132
+ const centerChildren = [
133
+ h('div', { class: 'mpx-titlebar__title', style: { color: this.textColor } }, [this.titleText])
134
+ ]
135
+
136
+ // top-level wrapper: contains fixed titlebar and page content wrapper
137
+ return h('page', { class: 'mpx-titlebar-wrapper' }, [
138
+ // fixed titlebar
139
+ h('div', {
140
+ class: ['mpx-titlebar', { 'mpx-titlebar--hidden': this.hidden }],
141
+ style: this.rootStyle
142
+ }, [
143
+ h('div', { class: 'mpx-titlebar__safe', style: this.safeStyle }, [
144
+ h('div', { class: 'mpx-titlebar__inner', style: this.innerStyle }, [
145
+ h('div', { class: 'mpx-titlebar__left', on: { click: this.onLeftClick } }, leftChildren),
146
+ h('div', { class: 'mpx-titlebar__center' }, centerChildren),
147
+ h('div', { class: 'mpx-titlebar__right' }, [])
148
+ ])
149
+ ])
150
+ ]),
151
+
152
+ // page content wrapper: default slot is page content
153
+ h('div', { class: 'mpx-titlebar__content', style: this.contentStyle }, this.$slots.default || [])
154
+ ])
155
+ }
156
+ }
157
+ </script>
158
+
159
+ <style scoped>
160
+ .mpx-titlebar {
161
+ width: 100%;
162
+ box-sizing: border-box;
163
+ -webkit-font-smoothing: antialiased;
164
+ }
165
+ .mpx-titlebar--hidden {
166
+ display: none;
167
+ }
168
+ .mpx-titlebar__safe {
169
+ /* safe area handled by padding-top; include both env and constant for broader iOS support */
170
+ padding-top: env(safe-area-inset-top, 0px);
171
+ padding-top: constant(safe-area-inset-top, 0px);
172
+ }
173
+ .mpx-titlebar__inner {
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: space-between;
177
+ padding: 0 12px;
178
+ box-sizing: border-box;
179
+ }
180
+ .mpx-titlebar__left,
181
+ .mpx-titlebar__right {
182
+ flex: 0 0 auto;
183
+ min-width: 44px;
184
+ display: flex;
185
+ align-items: center;
186
+ }
187
+ .mpx-titlebar__center {
188
+ flex: 1 1 auto;
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: center;
192
+ overflow: hidden;
193
+ padding: 0 8px;
194
+ }
195
+ .mpx-titlebar__title {
196
+ font-size: 17px;
197
+ white-space: nowrap;
198
+ text-overflow: ellipsis;
199
+ overflow: hidden;
200
+ font-weight: 500;
201
+ }
202
+ .mpx-titlebar__back {
203
+ background: none;
204
+ border: none;
205
+ font-size: 20px;
206
+ color: inherit;
207
+ padding: 6px;
208
+ cursor: pointer;
209
+ }
210
+
211
+ /* wrapper and content layout */
212
+ .mpx-titlebar-wrapper {
213
+ position: relative;
214
+ width: 100%;
215
+ height: 100%;
216
+ }
217
+
218
+ .mpx-titlebar {
219
+ position: fixed;
220
+ top: 0;
221
+ left: 0;
222
+ right: 0;
223
+ z-index: 1000; /* ensure above page content */
224
+ }
225
+
226
+ .mpx-titlebar__content {
227
+ position: relative;
228
+ width: 100%;
229
+ min-height: 100%;
230
+ box-sizing: border-box;
231
+ background: transparent;
232
+ }
233
+
234
+ /* SVG icon sizing and inherit color */
235
+ .mpx-titlebar__back svg {
236
+ display: block;
237
+ width: 20px;
238
+ height: 20px;
239
+ }
240
+ .mpx-titlebar__back path {
241
+ stroke: currentColor;
242
+ }
243
+ </style>
@@ -2476,7 +2476,14 @@ function getVirtualHostRoot (options, meta) {
2476
2476
  }
2477
2477
  }
2478
2478
  if (isWeb(mode) && ctorType === 'page') {
2479
- return createASTElement('page')
2479
+ const rootView = createASTElement('mpx-titlebar', [
2480
+ {
2481
+ name: 'pageConfig',
2482
+ value: '{{ this.$options.__mpxPageConfig }}'
2483
+ }
2484
+ ])
2485
+ processElement(rootView, rootView, options, meta)
2486
+ return rootView
2480
2487
  }
2481
2488
  }
2482
2489
  return getTempNode()
@@ -60,7 +60,9 @@ Vue.use(VueRouter)\n`
60
60
  globalTabBar
61
61
  })
62
62
 
63
- output += `var App = require(${stringifyRequest(loaderContext, addQuery(loaderContext.resource, { isApp: true }))}).default\n`
63
+ output += `var App = require(${stringifyRequest(loaderContext, addQuery(loaderContext.resource, { isApp: true }))}).default;\n`
64
+
65
+ output += `Vue.component('mpx-titlebar', require(${stringifyRequest(loaderContext, normalize.lib('runtime/components/web/mpx-titlebar.vue'))}).default);\n`
64
66
 
65
67
  output += `
66
68
  export default processAppOption({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.10.3-beta.8",
3
+ "version": "2.10.3-beta.9",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"