diff --git a/packages/shims-uni-app.d.ts b/packages/shims-uni-app.d.ts index c4190d8aba95da24409b91bb82e126d134c1cb7d..d52d2a9838306263e3c06bf75ab9c234fd0274d8 100644 --- a/packages/shims-uni-app.d.ts +++ b/packages/shims-uni-app.d.ts @@ -199,6 +199,7 @@ declare namespace UniApp { backgroundColor?: string maxWidth?: string | number // app-plus + scrollIndicator?: 'none' animationType?: string animationDuration?: number subNVues?: PagesJsonPageStyleSubNVue[] diff --git a/packages/uni-app-vite/src/nvue/plugin/index.ts b/packages/uni-app-vite/src/nvue/plugin/index.ts index 99267511468d304503690968343baa72f15bf534..5973c6084844a01d3acf360257fe951ae71699d1 100644 --- a/packages/uni-app-vite/src/nvue/plugin/index.ts +++ b/packages/uni-app-vite/src/nvue/plugin/index.ts @@ -24,6 +24,7 @@ import { transformText } from './transforms/transformText' import { createConfigResolved } from '../../plugin/configResolved' import { defaultNVueRpx2Unit } from '@dcloudio/uni-shared' import { external, globals } from '../utils' +import { transformRootNode } from './transforms/transformRootNode' const uTags = { text: 'u-text', @@ -38,6 +39,7 @@ const uTags = { export function initNVueNodeTransforms() { // 优先级必须确保 renderWhole > appendAsTree return [ + transformRootNode, createTransformTag(uTags), transformText, transformVideo, diff --git a/packages/uni-app-vite/src/nvue/plugin/transforms/transformRootNode.ts b/packages/uni-app-vite/src/nvue/plugin/transforms/transformRootNode.ts new file mode 100644 index 0000000000000000000000000000000000000000..ecb6c3a31dc16e95680bf0497804e113c976b4fe --- /dev/null +++ b/packages/uni-app-vite/src/nvue/plugin/transforms/transformRootNode.ts @@ -0,0 +1,103 @@ +import { createBindDirectiveNode } from '@dcloudio/uni-cli-shared' +import { + AttributeNode, + createSimpleExpression, + DirectiveNode, + ElementNode, + ElementTypes, + locStub, + NodeTransform, + NodeTypes, + RootNode, + TemplateChildNode, +} from '@vue/compiler-core' +const SCROLLER_COMPONENTS = [ + 'list', + 'scroller', + 'scroll-view', + 'waterfall', + 'recycle-list', +] +export const transformRootNode: NodeTransform = (node, context) => { + if (node.type !== NodeTypes.ROOT || !context.bindingMetadata.__pageOptions) { + return + } + const { disableScroll, scrollIndicator } = context.bindingMetadata + .__pageOptions as { + disableScroll?: boolean + scrollIndicator?: 'none' + } + // 禁用滚动,或已包含滚动元素 + if (disableScroll || hasScrollerElement(node)) { + return wrapperByView(node) + } + return wrapperByScrollView(node, { scrollIndicator }) +} + +function hasScrollerElement(node: RootNode) { + return node.children.some((child) => { + if (child.type === NodeTypes.ELEMENT) { + return SCROLLER_COMPONENTS.includes(child.tag) + } + }) +} + +function wrapperByScrollView( + node: RootNode, + { scrollIndicator }: { scrollIndicator?: 'none' } +) { + node.children = [ + createElement( + 'scroll-view', + createScrollViewProps({ scrollIndicator }), + node.children + ), + ] +} + +const trueExpr = createSimpleExpression('true') +const falseExpr = createSimpleExpression('false') +function createScrollViewProps({ + scrollIndicator, +}: { + scrollIndicator?: 'none' +}) { + return [ + createBindDirectiveNode('scrollY', trueExpr), + createBindDirectiveNode( + 'showScrollbar', + scrollIndicator === 'none' ? falseExpr : trueExpr + ), + createBindDirectiveNode('enableBackToTop', trueExpr), + createBindDirectiveNode('bubble', trueExpr), + createBindDirectiveNode('style', `{flexDirection:'column'}`), + ] +} + +/** + * 目前暂不支持多节点,故发现多节点时,自动补充一个 view 根节点 + * @param node + */ +function wrapperByView(node: RootNode) { + if (node.children.length > 1) { + node.children = [createElement('view', [], node.children)] + } +} + +function createElement( + tag: string, + props: (AttributeNode | DirectiveNode)[], + children: TemplateChildNode[] +): ElementNode { + return { + type: NodeTypes.ELEMENT, + ns: 0, + tag, + isSelfClosing: false, + props, + children, + tagType: ElementTypes.ELEMENT, + codegenNode: undefined, + loc: locStub, + } +} diff --git a/packages/uni-app-vite/src/nvue/plugin/transforms/transformScrollView.ts b/packages/uni-app-vite/src/nvue/plugin/transforms/transformScrollView.ts deleted file mode 100644 index 1d6f77b00df6cf9d1ef3611849ea884369428cdd..0000000000000000000000000000000000000000 --- a/packages/uni-app-vite/src/nvue/plugin/transforms/transformScrollView.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NodeTransform, NodeTypes } from '@vue/compiler-core' - -export const transformScrollView: NodeTransform = (node, context) => { - if (node.type !== NodeTypes.ROOT) { - return - } - console.log(context) -} diff --git a/packages/uni-app-vite/src/nvue/plugins/pagesJson.ts b/packages/uni-app-vite/src/nvue/plugins/pagesJson.ts index 7632d4ac0cd6a2f39ca5de8e41b3429cefff52b3..82e11b4bdfb8bde0587b0f95edd257ecabb04737 100644 --- a/packages/uni-app-vite/src/nvue/plugins/pagesJson.ts +++ b/packages/uni-app-vite/src/nvue/plugins/pagesJson.ts @@ -1,6 +1,6 @@ import path from 'path' -import { Plugin } from 'vite' - +import type { Plugin } from 'vite' +import type { CompilerOptions } from '@vue/compiler-sfc' import { defineUniPagesJsonPlugin, normalizeAppConfigService, @@ -9,8 +9,17 @@ import { getLocaleFiles, normalizeAppNVuePagesJson, APP_CONFIG_SERVICE, + resolveBuiltIn, + normalizePath, } from '@dcloudio/uni-cli-shared' +interface NVuePages { + [filename: string]: { + disableScroll?: boolean + scrollIndicator?: 'none' + } +} + export function uniPagesJsonPlugin({ renderer, appService, @@ -18,6 +27,11 @@ export function uniPagesJsonPlugin({ renderer?: 'native' appService: boolean }): Plugin { + const nvuePages: NVuePages = {} + // 仅编译nvue页面时重写 + if (!appService) { + rewriteBindingMetadata(nvuePages) + } return defineUniPagesJsonPlugin((opts) => { return { name: 'uni:app-nvue-pages-json', @@ -35,9 +49,14 @@ export function uniPagesJsonPlugin({ const pagesJson = normalizePagesJson(code, process.env.UNI_PLATFORM) pagesJson.pages.forEach((page) => { if (page.style.isNVue) { - this.addWatchFile( + const filename = normalizePath( path.resolve(process.env.UNI_INPUT_DIR, page.path + '.nvue') ) + nvuePages[filename] = { + disableScroll: page.style.disableScroll, + scrollIndicator: page.style.scrollIndicator, + } + this.addWatchFile(filename) } }) if (renderer === 'native' && appService) { @@ -62,3 +81,20 @@ export function uniPagesJsonPlugin({ } }) } + +/** + * 在 BindingMetadata 中补充页面标记 + */ +function rewriteBindingMetadata(nvuePages: NVuePages) { + const compilerDom = require(resolveBuiltIn('@vue/compiler-dom')) + const { compile } = compilerDom + compilerDom.compile = (template: string, options: CompilerOptions = {}) => { + if (options.filename && options.bindingMetadata) { + if (nvuePages[options.filename]) { + ;(options.bindingMetadata as any).__pageOptions = + nvuePages[options.filename] + } + } + return compile(template, options) + } +}