Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

目录文件结构

src/pagessrc/components目录下,您可以编写应用页面和组件了。每个页面/组件都占据着唯一的子目录,在子目录下可能有如下若干文件:

文件名作用
index.ts定义页面/组件的逻辑(必需)
index.config.ts页面/组件的结构化配置。页面使用CreatePageConfig,组件使用CreateComponentConfig
index.json历史兼容的小程序页面/组件JSON配置。新代码优先使用index.config.ts
locales/zh-CN.json页面/组件的i18n内容
web.pc.tsx宽屏的html渲染
web.tsxweb通用渲染,在没有更具体入口时回退
web.mobile.tsx移动宽度下优先使用的html渲染
web.pc.module.less宽屏样式
web.module.less窄屏样式
index.xml小程序渲染
index.less小程序样式
render.native.tsxApp渲染
render.native.scssApp渲染样式
render.ios.tsxios渲染
render.android.tsxandroid渲染

看上去有些复杂,但是实际上绝大多数项目都只会实现其中的部分文件。Oak框架在前端采取了一个较为保守的方案,以应对跨前端的一致性问题。其中心思想是:对页面的逻辑统一抽象(index.ts),而对页面的具体渲染则分别处理。

将前端各平台的渲染语法强行统一到一个框架之下(如taro, uniapp)的前景固然美好,但这会带来兼容性和扩展性的严重问题,同时也会造成与开源社区的割裂。这显然与Oak框架的设计目标背道而驰。因此Oak框架借鉴了微信小程序和React的设计思想,将页面的各种与渲染无关的逻辑部分抽象到index.ts当中,而将各个平台的渲染代码分割到各个文件之中,在对应平台下运行的时候进行加载,从而达到一致性和兼容性的较好平衡。

index.ts

在index.ts中,定义了本页面/组件的逻辑代码,此文件中应当避免引用任何平台相关的特性内容,而只关注于页面的逻辑能力。关于index.ts如何编写,请参见编写组件;而组件逻辑上的方法和数据项,可以参见定义组件对象

如果确实需要引用平台相关的特性内容,可以通过process.env.OAK_PLATFORM环境变量加以区别。例如,在支付时如果需要唤起平台的支付接口,可以像下面这样编写(代码引用自oak-pay-business/src/components/pay/detail/index.ts):

 if (process.env.OAK_PLATFORM === 'wechatMp') {
    const { prepayMeta } = meta as { prepayMeta: WechatMiniprogram.RequestPaymentOption };
    if (prepayMeta) {
        const result = await wx.requestPayment(prepayMeta);
        process.env.NODE_ENV === 'development' && console.log(result);
        return result;
    }
    else {
        features.message.setMessage({
            type: 'error',
            content: features.locales.t('startPayError.illegaPayData'),
        });
    }
}
else {
    features.message.setMessage({
        type: 'error',
        content: features.locales.t('startPayError.falseEnv', { env: 'wechatMp' }),
    });
}

在这里,当页面调用了支付事件时,如果判断当前环境是小程序,则调用wx.requestPayment方法唤起支付。

index.config.ts

index.config.ts用于声明页面或组件的结构化配置,它会被Oak CLI读取并参与web路由、小程序虚拟JSON、菜单和访问控制等生成流程。页面目录中通常这样写:

import { CreatePageConfig } from '@oak-frontend-base/config';

export default CreatePageConfig({
    route: {
        titleI18nKey: 'pageTitle',
        access: { type: 'login' },
    },
    menu: {
        name: 'Order',
        icon: 'list',
    },
    mp: {
        navigationBarTitleText: '订单',
        enablePullDownRefresh: true,
        usingComponents: {
            price: '@project/components/price',
        },
    },
});

组件目录中通常这样写:

import { CreateComponentConfig } from '@oak-frontend-base/config';

export default CreateComponentConfig({
    mp: {
        component: true,
        usingComponents: {
            avatar: '@project/components/avatar',
        },
    },
});

其中mp字段对应原来小程序index.json中的配置项,例如usingComponentscomponentGenericscomponentPlaceholderstyleIsolationnavigationBarTitleText等。保留index.json仍然可以兼容旧项目,但新页面和新组件建议优先写index.config.ts

web端

如果您的应用基于 web,可以按需要提供 web.tsxweb.pc.tsxweb.mobile.tsx。当前选择顺序是:

  • 移动宽度:web.mobile.tsx -> web.tsx -> web.pc.tsx
  • 宽屏:web.pc.tsx -> web.tsx -> web.mobile.tsx

只提供其中一个入口时,宽屏和移动端都会回退使用它。当前 Vite render-entry invalidation 会监听这些兄弟入口的新增和删除,开发中补充另一个入口后通常不再需要手工执行 clean:cache。在 TSX 中仍可使用普通 React 组件和 render-local hooks,但 Oak 数据树状态、projection、filter 和跨端业务方法应继续放在 index.ts

微信小程序端

微信小程序端的模板写在index.xml中,其语法和wxml完全一致。页面/组件JSON配置优先写在index.config.tsmp字段中,例如usingComponentsnavigationBarTitleTextcomponentGenerics等;Oak CLI会在构建时生成对应的小程序JSON。旧项目中的index.json仍然兼容,但不建议在新代码里继续新增。

App端

Oak框架的App端基于react-native,您只需要编写render.native.tsx,则可生成在IOs和Android下通用的页面。当然,与react-native的编译规则类似,您也可以编写render.ios.tsx或者render.android.tsx,分别在两个操作系统之下进行渲染。同样的,您可以在tsx文件中引用任何您想使用的第三方组件。