diff --git a/docs-vitepress/api/app-config.md b/docs-vitepress/api/app-config.md index 2effb37fc1..871e7d3418 100644 --- a/docs-vitepress/api/app-config.md +++ b/docs-vitepress/api/app-config.md @@ -178,3 +178,32 @@ mpx.config.webConfig.routeConfig = { mpx.config.webConfig.disablePageTransition = true ``` 此处的 `disablePageTransition` 后续将被废弃,请使用编译阶段的[disablePageTransition](compile.md#webconfig)进行配置 + +### webConfig.enableTitleBar + +`boolean = false` + +是否在 Web 输出时启用内置标题栏(`mpx-titlebar`)组件。默认为 `false`,即不渲染标题栏。 + +设为 `true` 后,Mpx 会在每个页面的根节点外层自动注入 `` 组件,读取 `app.json` 的 `window` 配置及当前页面 json 配置,渲染与小程序视觉一致的 fixed 标题栏(含安全区适配与返回按钮)。 + +> **注意**:若页面 json 中将 `navigationStyle` 配置为 `'custom'`,则该页面的标题栏会自动隐藏,以支持自定义导航栏场景。 + +```js +import mpx from '@mpxjs/core' + +mpx.config.webConfig.enableTitleBar = true +``` + +### webConfig.safeAreaInsetTop + +`number = 24` + +在 **Android** 设备上,标题栏顶部安全区(状态栏)的高度(单位:px)。仅在 `enableTitleBar` 为 `true` 且非 iOS 设备时生效;iOS 设备会自动使用 `env(safe-area-inset-top)` 获取安全区高度,无需手动配置。 + +```js +import mpx from '@mpxjs/core' + +// 将 Android 状态栏高度设为 28px(默认 24px) +mpx.config.webConfig.safeAreaInsetTop = 28 +``` diff --git a/packages/webpack-plugin/lib/runtime/components/web/mpx-titlebar.vue b/packages/webpack-plugin/lib/runtime/components/web/mpx-titlebar.vue new file mode 100644 index 0000000000..de689ecc23 --- /dev/null +++ b/packages/webpack-plugin/lib/runtime/components/web/mpx-titlebar.vue @@ -0,0 +1,241 @@ + + + diff --git a/packages/webpack-plugin/lib/web/index.js b/packages/webpack-plugin/lib/web/index.js index c69227511c..e76905d71d 100644 --- a/packages/webpack-plugin/lib/web/index.js +++ b/packages/webpack-plugin/lib/web/index.js @@ -74,7 +74,8 @@ module.exports = function ({ usingComponentsInfo, originalUsingComponents, componentGenerics, - componentPlaceholder + componentPlaceholder, + jsonContent }, callback) }, (callback) => { diff --git a/packages/webpack-plugin/lib/web/processJSON.js b/packages/webpack-plugin/lib/web/processJSON.js index 0c5c5cd7d4..5747ddd1e9 100644 --- a/packages/webpack-plugin/lib/web/processJSON.js +++ b/packages/webpack-plugin/lib/web/processJSON.js @@ -116,7 +116,10 @@ module.exports = function (jsonContent, { } } - if (ctorType !== 'app') { + if (ctorType === 'app') { + // 存储原始 app json(rulesRunner 执行前),供编译期其他模块读取基础配置 + mpx.appJson = jsonObj + } else { rulesRunnerOptions.mainKey = ctorType } diff --git a/packages/webpack-plugin/lib/web/processTemplate.js b/packages/webpack-plugin/lib/web/processTemplate.js index 4d66316cd9..0eddee9389 100644 --- a/packages/webpack-plugin/lib/web/processTemplate.js +++ b/packages/webpack-plugin/lib/web/processTemplate.js @@ -1,10 +1,15 @@ +const JSON5 = require('json5') const templateCompiler = require('../template-compiler/compiler') const genComponentTag = require('../utils/gen-component-tag') const addQuery = require('../utils/add-query') +const normalize = require('../utils/normalize') const parseRequest = require('../utils/parse-request') const { matchCondition } = require('../utils/match-condition') const { getWxTemplateComponentName, serializeWxTemplateDefinition, buildWebTemplateImportMergeExpr } = require('./template-shared') +const titleBarPath = normalize.lib('runtime/components/web/mpx-titlebar.vue') +const validNavigationStyles = ['default', 'custom'] + module.exports = function (template, { loaderContext, hasScoped, @@ -16,7 +21,8 @@ module.exports = function (template, { usingComponentsInfo, originalUsingComponents, componentGenerics, - componentPlaceholder + componentPlaceholder, + jsonContent }, callback) { const mpx = loaderContext.getMpx() const { @@ -161,6 +167,36 @@ module.exports = function (template, { } } + // Page 在 web 模式下插入 titlebar 组件 + if (ctorType === 'page') { + let needTitleBar = true + // 页面级 navigationStyle 优先,未配置时回退到 app 全局配置 + let navigationStyle = mpx.appJson && mpx.appJson.window && mpx.appJson.window.navigationStyle + if (!validNavigationStyles.includes(navigationStyle)) { + navigationStyle = undefined + } + if (jsonContent) { + try { + const jsonObj = JSON5.parse(jsonContent) + if (validNavigationStyles.includes(jsonObj.navigationStyle)) { + navigationStyle = jsonObj.navigationStyle + } + } catch (e) { + // json 解析失败,保持默认行为 + } + } + if (navigationStyle === 'custom') { + needTitleBar = false + } + if (needTitleBar) { + builtInComponentsMap['mpx-titlebar'] = { + resource: addQuery(titleBarPath, { isComponent: true }) + } + const serialized = templateCompiler.serialize(root) + return `${serialized}` + } + } + return templateCompiler.serialize(root) } })