工程化开发小程序

课程目标

  1. 学习Rax⼩程序的基本语法、API及组件的使⽤;
  2. 掌握Rax⼩程序的⾼阶⽤法;

知识要点

Rax基本使⽤

  • Rax 语法层⾯以 React 为标准,可以使⽤ Hooks、Context 等 80% 以上⽀持度的 React API
  • 官⽅配套的研发框架 Rax App,⽀持 TypeScript、Less/Sass 等基础⼯程能⼒,同时⽀持 MPA、 SPA、SSR
  • ⽀持通过完整的 Rax 语法开发跨⽀付宝/微信/字节等不同⼚商的⼩程序,同时可降级到 Web
  • 基于 Web 标准⽀持跨多容器的跨端应⽤,包含 Web 应⽤、Flutter 应⽤(Kraken)、Weex 应⽤
  • 丰富的跨端⽣态,⽐如跨端组件 Fusion Mobile,跨端 API Uni API
  • Rax 与 React 的区别是什么?
    • Rax ⾯向多端设计的,从最初始就引⼊了 Driver 机制来适配不同端,相⽐ React 更加轻量, gzip 之后只有 6KB;
  • Rax 对于 React 的 API ⽀持度是怎样的?
    • 不⽀持 Suspense、lazy API,其他诸如 Hooks、Component 等 API 都⽀持;

⽬录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├── .rax/                          // 运⾏时⽣成的临时⽬录,git不要提交
├── build/ // 构建产物⽬录,npm run build 后产物
├── public // 本地静态资源
│ └── favicon.png
├── src
│ ├── app.json // 路由及⻚⾯配置, routes、window等
│ ├── app.ts // [⼩程序|SPA]应⽤⼊⼝
│ ├── miniapp-native/ // [⼩程序]⼩程序原⽣代码
│ ├── components/ // ⾃定义业务组件
│ ├── pages/ // ⻚⾯
│ ├── models/ // 应⽤级数据状态
├── build.json // ⼯程配置
├── package.json
└── tsconfig.json

环境配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 获取不同环境的配置
// src/config.ts
export default {
// 默认配置
default: {
appId: '123',
baseURL: '/api'
},
local: {
appId: '456',
},
daily: {
appId: '789'
},
prod: {
appId: '101'
}
}
import { config } from 'rax-app';
console.log(config.appId);

编写组件

⽀持

  • Function Component
  • Class Component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// function component
import { createElement } from 'rax';

function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

// class component
import { createElement, Component } from 'rax';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

支持类型:

  • props
  • state
  • Fragment
  • Hooks:常⽤Hooks:useState、useEffect etc,具体看下⽂
  • JSX
  • JSX+
    • 条件判断:x-if、x-elseif、x-else
    • 循环列表:x-for
    • 单次渲染:x-memo:⾸次render后值不变不会render
    • 插槽:x-slot
    • 类名绑定:x-class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 条件判断
<View x-if={condition}>Hello</View>
<View x-elseif={anotherCondition}></View>
<View x-else>NothingElse</View>

// x-for
{/* Array or Plain Object*/}
<tag x-for={item in foo}>{item}</tag>

<tag x-for={(item, key) in foo}>{key}: {item}</tag>

// x-memo
<p x-memo>this paragragh {mesasge} content will not change.</p>

// x-slot
<Waterfall>
<view x-slot:header>header</view>
<view x-slot:item="props">{props.index}: {props.item}</view>
<view x-slot:footer>footer</view>
</Waterfall>

<slot name="header" /> // 槽位
// x-class
<div x-class={{ item: true, active: val }} />

样式⽅案

  • 全局样式
    统⼀定义在 src/global.[css|less|scss] ,框架会⾃动引⼊;
  • 组件样式
    ⽂件名定义:xxx.module.[css|less|scss],使⽤ CSS Modules ,避免全局污染
1
2
3
4
5
/** ./pages/Home/index.module.css */
.container {
background: #fff;
width: 750rpx;
}
1
2
3
4
5
6
7
8
/* 也可以通过 CSS Modules 的 :global 语法定义全局样式 */
:global {
body {
a {
color: blue;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
// ./pages/Home/index.tsx
import styles from './index.module.css';
function Home() {
return (
<View className={styles.container}>
<View>CSS Modules</View>
</View>
);
}
// 编译后
<View class="container--1DTudAN">title</View>
  • 内联样式
    在 build.json ⾥配置了 inlineStyle: true 则说明整个项⽬使⽤内联样式
1
2
3
4
5
const myStyle = {
fontSize: '24px',
color: '#FF0000'
};
const element = <View style={myStyle}>Hello Rax</View>;

⽀持在使⽤内联样式⽅案的项⽬中局部⽀持⾮内联形式
在 build.json 中将 inlineStyle 设置为 { forceEnableCSS: true }

1
2
3
4
5
6
7
import cssModule from './index.module.css';
import styles from './index.css';
function App() {
// CSS Modules 以 className 的形式使用
// inlineStyle 以 style 的形式使用
return <div className={cssModule.header} style={styles.header} />;
}

框架API

通过 rax-app 中引⼊
import { runApp } from 'rax-app';

  • runApp
  • APP_MODE
  • ErrorBoundary
  • store
  • getHistory:获取history实例
  • getSearchParams:获取参数
  • history:路由实例
1
2
3
4
5
6
7
8
9
10
11
12
13
import { history } from 'rax-app';
// 用于获取 history 栈里的实体个数
console.log(history.length);
// 用与获取 history 跳转的动作,包含 PUSH、REPLACE 和 POP 三种类型
console.log(history.action);
// 用于获取 location 对象,包含 pathname、search 和 hash
console.log(history.location);
// 用于路由跳转
history.push('/home');
// 用于路由替换
history.replace('/home');
// 用于跳转到上一个路由
history.goBack();

安全区域适配

  • 刘海屏适配为了使⻚⾯顶部内容,不被刘海遮挡,可以通过设置容器节点的 padding-top 值来实现,使核⼼内容整体下移。

    获取刘海⾼度,⾸先需要设置 viewport-fit ,调整可视窗⼝的布局⽅式。当且仅当 viewport-fit 设置为 cover 时,可以进⼀步设置⻚⾯的安全区域范围。
    <meta name="viewport" content="width=device-width, viewport-fit=cover">
    然后,结合 env() ⽅法,可以获取 safe-area-inset-top 值,并将其作为容器节点的 padding-top 值。

    1
    2
    3
    4
    .root {
    padding-top: constant(safe-area-inset-top); /* 兼容 iOS < 11.2 */
    padding-top: env(safe-area-inset-top); /* iOS > 11.2 */
    }
  • 底部⼩⿊条适配
    有 tabbar 的应⽤,iPhone 底部的⼩⿊条常常会挡住 tabbar,影响其可操作区域。和刘海屏适配的原理 ⼀致,以 tabbar 为例,⼩⿊条适配可以通过调整 tabbar 的 padding-bottom 值,增加空⽩区域来实现。

    1
    2
    3
    4
    5
    .tabbar {
    padding-bottom: 0; /* 无小黑条的情况下,无需额外设置 */
    padding-top: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
    padding-top: env(safe-area-inset-bottom); /* iOS > 11.2 */
    }

静态资源使⽤

将⽂件放⼊ public ⽂件夹,webpack不会处理它。⽽是它将被复制到构建⽂件夹中;
要引⽤ public ⽂件夹中的资源,需要使⽤名为 process.env.PUBLIC_URL 的特殊变量,这个值会根据⼯程配中的 publicPath 变化:

1
2
3
render() {
return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}

通常我们建议从 JS 导⼊ stylesheets,图⽚和字体存⼊public⽂件夹中:

  • 你需要在构建输出中具有特定名称的⽂件,例如 manifest.json;
  • 你有数千张图⽚,需要动态引⽤它们的路径;
  • 你希望在打包代码之外包含⼀个⽆需⾛构建逻辑的⼩脚本;
  • 某些库可能与 webpack 不兼容,只能将其放在 public 中引⼊;

代码切割

  • dynamic import
    使⽤ import(),webpack 会在编译阶段对引⼊的资源进⾏代码切割,即只有当运⾏时逻辑执⾏到 import() 调⽤点时才会加载对应的资源,该函数返回值是 Promise

    1
    2
    3
    4
    5
    6
    7
    8
    import { isWeb } from '@uni/env';
    if (isWeb) {
    import('./fetch').then(fetch => {
    fetch('m.taobao.com');
    }).catch(err => {
    console.error(' ');
    });
    }
  • rax-use-import
    函数式组件提供的Hooks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import { createElement } from 'rax';
    import useImport from 'rax-use-import';

    export default function App() {
    const [Bar, error] = useImport(() => import(/* webpackChunkName: "bar"*/ './Bar'));
    if (error) {
    return <p>error</p>
    } else if (Bar) {
    return <Bar />
    } else {
    return <p>loading</p>
    }
    }

Rax⼩程序基本介绍

Rax ⼩程序以运⾏时⽅案为基础,⽀持局部场景使⽤编译时⽅案开发组件,充分结合了⼆者的优势特点,让⽤户在保证开发效率的⼤前提下能够针对局部场景进⾏更⾼渲染性能的优化。

Rax⼩程序简介

⽅案对⽐
  • 编译时⽅案:
    • 通过 AST 转译 + 运⾏时垫⽚模拟 Rax core 的⽅式,将Rax DSL 1:1 输出为原⽣⼩程序代码;
    • 限制较多:
      • JSX 较为灵活,适配⼯作量巨⼤,维护成本较⾼,开发者需要遵循⼤量的语法约束,否则代码就不能正常编译运⾏,开发效率难以保证;
      • 需要配合runtime垫⽚来模拟 Rax 运⾏ –> Rax 有功能更新时,编译⽆法得到同步;
      • DOM 和 BOM API 的缺失,Web 上累积的各种前端⽣态⽆法复⽤;
    • 性能较好;
  • 运⾏时⽅案:
    • 通过底层模拟 DOM 和 BOM API,使开发者可以使⽤Rax DSL开发;
    • 性能较差,但基本对⻬web端⽣态;

Rax运⾏

npm init rax rax-example

项⽬中 build.json 中的tagrets

1
2
3
4
5
6
7
8
9
{
"targets": [
"miniapp",
"wechat-miniprogram",
"bytedance-microapp",
"baidu-smartprogram",
"kuaishou-miniprogram"
]
}

package.json

  • start:rax-app start
    • 保留⽇志;
    • 保留source map
  • build:rax-app build
    • 不保留注释;
    • 去除source map;
    • 去除开发⼯具;

rax-app webpack config github地址:
https://github.com/raxjs/rax-app/tree/master/packages/rax-webpack-config/src

入口文件

src/app.js(TS为app.tsx)为⽂件⼊⼝

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
import { runApp } from 'rax-app';
const appConfig = {
app: {
// 可选,自定义添加 Provider
appProvider: ({ children }) => {
return <ConfigProvider>{children}</ConfigProvider>;
},
// 可选,开启默认 ErrorBoundary 行为,默认值为 false
errorBoundary: true,
// 可选,自定义错误边界的 fallback UI
ErrorBoundaryFallback: <div>渲染错误</div>,
// 可选,自定义错误的处理事件
onErrorBoundaryHandler: (error, componentStack) => {

},
// 可选,小程序应用生命周期
onLaunch() {},
onShow() {},
onHide() {},
onError() {},
onShareAppMessage() {},
},
// 不建议在此创建 store 的 getInitialStates
store: {
initialStates: {},
getInitialStates: (initialData) => {}
}
}

runApp(appConfig);

应用配置

src/app.json 中,对windowtabbar配置,且⼩程序中的路由存在于routes

  • path:指定⻚⾯对应的路由地址
  • source: 指定⻚⾯组件地址,必须写成 pages/[PAGE_NAME]/index 格式,暂不⽀持嵌套式路由;
  • targets:指定⻚⾯需要构建的端,默认为 build.json 所配置的 targets 的值;
  • window:指定该⻚⾯的窗体表现,可以覆盖全局的窗⼝设置;
  • tabBar:如果应⽤是⼀个多 tab 应⽤(底部栏可以切换⻚⾯),可以指定 tab 栏及切换时显示的对应⻚⾯;

Tips:原⽣⼩程序中,app.json(debug、networkTimeout)的其他字段都可以在此配置

⼯程配置

在build.json中,其中可以指定⼩程序的配置项

  • buildType:⼩程序引擎,默认位运⾏时,编译时为 compile;
  • nativeConfig:即微信⼩程序的project.config.json;
  • subPackages:是否分包加载;
  • runtimeDependencies:在运⾏时引擎下,使⽤rax⼯程的多包npm时,使⽤编译时还是运⾏时实现;
  • nativePackage:配置原⽣⼩程序⾃定义组件及原⽣⻚⾯所⽤到的 npm 依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"targets": ["miniapp", "wechat-miniprogram"],
"miniapp": {}, // 支付宝小程序语法配置
// 微信小程序语法配置
"wechat-miniprogram": {
"nativeConfig": {
"appId": "YOUR_APP_ID",
"miniprogramRoot": "build/wechat-miniprogram",
},
"subPackages": {
"shareMemory": true // 共享运行时内存
},
"nativePackage": {
// 自动安装 Rax 项目中的元素小程序自定义组件及原生页面所用到的 npm 依赖
// 不配置 dependencies 字段且 autoInstall 未设置为 false 时会默认安装所有依赖,可作为性能优化
"autoInstall": true,
"dependencies": {
"mini-ali-ui": "^1.3.4"
}
}
}
}

Tips:

  • 当运⾏时项⽬中使⽤到由 Rax 组件⼯程产出的多端组件 npm 包时,不配置 runtimeDependencies, 默认采⽤其编译时的代码实现。此时需要将其配置到 nativePackage.dependencies,否则产物中将报找不到该组件的问题;
  • nativePackage.dependencies 中配置的原⽣⼩程序 npm 依赖依然需要在 Rax 项⽬根⽬录的 package.json 中配置并安装;

⻚⾯⽣命周期及事件处理

移除了部分原⽣⼩程序事件相关Hooks:

  1. useHistory、useReachBottom等只能作为单纯API⽽不是Hooks使⽤;
  2. 性能与可扩展性较弱,每当⼩程序新⽀持⼀个事件,都需要去开发⼀个对应功能的 API,并且在⻚⾯初始化之初就监听所有事件 –> 不合理的;

新增API:

Syntax Description
registerNativeEventListeners(Component,[...eventName]) 注册该⻚⾯需要监听的所有事件,第⼀个参数为⻚⾯级组件
addNativeEventListener(eventName, callback) 开始监听某个事件并执⾏回调函数
removeNativeEventListener(eventName, callback) 移除某个事件的回调函数⾏回调函数
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
import { createElement, useEffect } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import { isMiniApp } from 'universal-env';
import { registerNativeEventListeners, addNativeEventListener,
removeNativeEventListener } from 'rax-app';
function Index() {
function handlePageReachBottom() {}
useEffect(() => {
if (isMiniApp) {
addNativeEventListener('onReachBottom', handlePageReachBottom);
}
return () => {
if (isMiniApp) {
removeNativeEventListener('onReachBottom', handlePageReachBottom);
}
}
}, [])

return (
<View>
<Text>1</Text>
</View>
);
}

if (isMiniApp) {
registerNativeEventListeners(Index, ['onReachBottom']);
}
export default Index;

注意:

  1. onShow事件建议:
    1. Function component:使⽤ usePageShow(cb),cb在渲染后执⾏;
    2. Class component:使⽤ onShow(),会在 constructor 后调⽤;
    3. addNativeEventListener 监听需要在 useEffect 外调⽤,也要在 useEffect cb 清除监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { createElement, useEffect } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import { registerNativeEventListeners, addNativeEventListener,
removeNativeEventListener } from 'rax-app';
function Index() {
function handlePageShow() {}
addNativeEventListener('onShow', handlePageShow);
useEffect(() => {
return () => {
removeNativeEventListener('onShow', handlePageShow);
} });
return (
<View>
<Text>1</Text>
</View>
); }
registerNativeEventListeners(Index, ['onShow']);
export default Index;

组件

在微信等⼩程序端通过 bind 前缀绑定事件,在 JSX 中需要处理为 on 前缀,并遵循驼峰式命名规则,如上⾯ bindgetphonenumber 处理为 onGetPhoneNumber;
使⽤⼩程序原⽣组件

  1. npm安装
    1. 配置nativePackage 的 dependencies,不然会安装所有依赖;
    2. 开发者个⼈npm包
      1. 配置在 package.json 中的miniappConfig,main指向原⽣⼩程序⼊⼝
    3. 第三⽅npm包
      1. 不使⽤ miniappConfig,使⽤ import Title from 'mini-ali-ui/es/title/index' ⽅式引⼊
  2. 源码拷⻉到本地
    1. 拷⻉到 src/miniapp-native 下,使⽤ import Button from '../../miniapp-native/Button/index' (⽽⾮ import Button from '@src/miniapp-native'

API

⽀持直接在对应环境下使⽤对应api

1
2
3
4
5
6
7
8
9
import { isMiniApp, isWeChatMiniProgram } from '@uni/env';

function scan () {
if (isWeChatMiniProgram) {
wx.scanCode()
} else if (isMiniApp) {
my.scan()
}
}

状态管理

全局状态管理:

  • useReducer、useContext etc;–> 不建议
  • 提供store
1
2
3
4
5
6
src
├── models // 全局状态
| ├── counter.ts
│ └── user.ts
├── app.tsx
└── store.ts
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
// src/models/user.ts
export const delay = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));

export default {
// 定义 model 的初始 state
state: {
name: '',
id: ''
},
// 定义改变该模型状态的纯函数
reducers: {
update (prevState, payload) {
return {
...prevState,
...payload,
}; },
},
// 定义处理该模型副作用的函数
effects: (dispatch) => ({
async updateUserInfo () {
await delay(1000);
dispatch.user.update({
name: 'taobao',
id: '123',
});
},
}),
};
1
2
3
4
5
// src/store.ts
import { createStore } from 'rax-app';
import user from './models/user';
const store = createStore({ user });
export default store;
1
2
3
4
5
6
7
8
9
10
11
// 引用全局状态
import store from '@/store';
const HomePage = () => {
const [userState, userDispatchers] = store.useModel('user');
return (
<>
<span>{userState.id}</span>
<span>{userState.name}</span>
</>
);
}

使⽤编译时组件

  1. 源码⽅式开发
    1. npm init 运⾏时,npm 安装 jsx2mp-runtime;
    2. src下创建miniapp-compiled,此⽬录下使⽤编译时编译;
    3. 在src/miniapp-compiled 下新建 index.jsx ⽂件,将所有编译时组件引⼊后进⾏导出;
    4. 引⼊时使⽤相对路径,不要⽤解构;
    5. 限制:
      1. ⽆法使⽤全局状态管理⽅案,其只拥有从⽗组件获取 props 执⾏渲染,并通过事件与⽗组件通信的能⼒;
      2. 编译时组件在形态上等同于原⽣⾃定义组件,其依赖的 npm 包建议⽤户配置在 nativePackage 中,必须将 jsx2mp-runtime 加⼊ nativePackage.dependencies 中;
  2. npm⽅式开发
    1. Rax组件⽅式开发⼩程序默认采⽤编译时编译组件,可以直接在运⾏时项⽬中使⽤;
    2. 需要将该组件添加到 package.json 依赖中,还需要将其添加到 build.json 中 nativePackage.dependencies 字段内;
    3. 在微信⼩程序中使⽤:
      1. 需要在 Rax 组件的 package.json 中加⼊ “miniprogram”: “.” 兼容 npm 构建机制;
      2. 在运⾏时项⽬中将 jsx2mp-runtime 添加到 package.json 和 build.json ⾥的 nativePackage.dependencies ;
      3. 编译完成后,⽤户需要在微信 IDE 中进⾏构建 npm 的操作;
    4. 参考Rax⼩程序组件开发:
      https://rax.js.org/docs/guide/miniapp-com-dev

引⽤⼩程序原⽣⻚⾯

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
// 目录
├── build.json
├── package.json
└── src
├── app.js
├──app.json
├── components
│ └── Logo
│ ├── index.css
│ └── index.jsx
├── pages
│ ├── About // 小程序原生
│ │ ├── index.axml
│ │ ├── index.css
│ │ ├── index.js
│ │ └── index.json
│ └── Home
│ ├── index.css
│ └── index.jsx
└── miniapp-native // 小程序原生
└── List
├── index.axml
├── index.css
├── index.js
└── index.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 小程序 src/app.json
{
"routes": [
{
"path": "/",
"source": "pages/Home/index"
},
{
"path": "/about",
"source": "pages/About/index",
"targets": ["miniapp"] // 声明
}
],
"window": {
"title": "Rax App"
}
}

Tips:

  • 原⽣⻚⾯使⽤到的原⽣⾃定义组件(如上⾯项⽬中的 List 组件)必须放置于 src/miniapp-native ⽂件夹中,否则⽆法使⽤;
  • 原⽣⼩程序⻚⾯建议放在 src/miniapp-native ⽂件夹中,⽽不是上⾯ src/pages/About 的做法;

编写原生 app.js

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
// 自 miniapp-render v2.7.0 开始,用户在 runApp 中编写的 app 生命周期将全部与小程序原生的 APP 生命周期对其

// src/app.ts
import { runApp } from 'rax-app';
runApp({
// 可以在此处实现对应生命周期
app: {
onLaunch() {
this.__age = 20; // this 即为 app 实例,可直接挂载变量
console.log('on launch');
},
onShow() {
console.log('on show');
}
}
})

// src/miniapp-native 新建 app.js,必须 module.export 出 app.js
// src/miniapp-native/app.js
console.log('业务逻辑')
const originalPage = Page;
Page = function(options) {
console.log('Page 已被劫持')
originalPage(options);
}

const nativeAppConfig = {
__age: 20,
onLaunch() {
console.log('on launch');
},
onShow() {
console.log('on show');
}
};
module.exports = nativeAppConfig;

分包加载

  1. 在 build.json 中设置
    1
    2
    3
    4
    5
    6
    7
    8
    {
    "targets": [
    "miniapp"
    ],
    "miniapp": {
    "subPackages": true
    }
    }
  2. 分包⼊⼝设置
    设置分包后,src/app.js 失效,src/app.json routes设置为分包⼊⼝
    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
    {
    "routes": [
    {
    "source": "pages/Home/app",
    "miniappMain": true // 主包入口
    },
    {
    "source": "pages/About/app"
    }
    ],
    "window": {
    "title": "Rax app"
    },
    "tabBar": {
    "textColor": "#999",
    "selectedColor": "#666",
    "backgroundColor": "#f8f8f8",
    "items": [
    {
    "text": "首页",
    "pagePath": "pages/Home/models/Foo", // 路径修改为具体路径
    "icon": "https://gw.alicdn.com/tfs/TB1vGsVqiDsXe8jSZR0XXXK6FXa-200-200.png",
    "activeIcon":
    "https://gw.alicdn.com/tfs/TB1EBamvz39YK4jSZPcXXXrUFXa-200-200.png"
    },
    {
    "text": "关于",
    "pagePath": "pages/Home/models/Bar",
    "icon": "https://gw.alicdn.com/tfs/TB1PceUq5pE_u4jSZKbXXbCUVXa-200-200.png",
    "activeIcon":
    "https://gw.alicdn.com/tfs/TB1BZTsqmslXu8jSZFuXXXg7FXa-200-200.png"
    }
    ],
    }
    }
  3. 分包⼊⼝代码
    在分包下创建app.js作为⼊⼝,必须引⼊app.json并执⾏ruApp;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import { runApp } from 'rax-app';
    // 引入app.json
    import staticConfig from './app.json';
    runApp({
    app: {
    onShow() {
    console.log('app show...');
    }, onHide() {
    console.log('app hide...');
    },
    }
    }, staticConfig);
  4. 分包配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "routes": [{
    "path": "/about",
    "source": "pages/index",
    "miniappPreloadRule": {
    "network": "wifi",
    "packages": ["pages/About"]
    }
    }]
    }
  5. 分包间共享内存
    公共模块变为单例共享同⼀引⽤
    1
    2
    3
    4
    5
    6
    7
    8
    {
    "targets": ["miniapp"],
    "miniapp": {
    "subPackages": {
    "shareMemory": true
    }
    }
    }

原⽣⼩程序⼯程配置

在build.json 中的nativeConfig配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"targets": ["miniapp", "wechat-miniprogram"],
"wechat-miniprogram": {
"nativeConfig": {
"appId": "YOUR_APP_ID", // appId "miniprogramRoot": "build/wechat-miniprogram"
},
"subPackages": {
"shareMemory": true
},
"runtimeDependencies": ["@ali/comp1", "/^raxcomp/"],
"nativePackage": {
"autoInstall": true,
"dependencies": {
"mini-ali-ui": "^1.3.4"
}
} }
}

性能优化

  1. 局部场景引⼊编译时组件(双引擎结合)
    1. 在局部性能要求较⾼的场景下(例如⻓列表),将部分组件(例如⻓列表中的循环项)采⽤编译时⽅案开发;
  2. 代码逻辑优化
    1. 多使⽤ memo 等以减少不必要的⼦组件的重复渲染;
  3. ⾼频组件分级
    1. 针对 view/image/text 等⾼频使⽤的组件,Rax 会在运⾏时根据其是否绑定 props、events 为其⾃动分级,以映射到对应的模板上,减少⽆⽤的 props、events 绑定,提升交互性能。因此,在编写代码时请注意只为该类组件绑定必需的 props 和 events;
  4. 模板属性及事件配置
    1. 运⾏时⽅案中,我们会遍历所有内置组件,并将其输出⾄模板⽂件中,在⼩程序运⾏起来后根据实时的 setData 的数据递归迭代模板以⽣成完整的 DOM 结构。因此组件的 template 会预先绑定上所有的事件和属性,根据运⾏时的数据来进⾏属性传递和事件触发;
    2. 删除属性及事件:⽀持删除props和events
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      {
      "targets": [
      "wechat-miniprogram"
      ],
      "wechat-miniprogram": {
      "template": {
      "view": {
      "delete": {
      "props": ["hover-class", "role"],
      "events": ["TransitionEnd", "FirstAppear", "TouchMove"]
      } },
      "cover-view": {
      "delete": {
      "props": ["scroll-top"]
      }
      } }
      }
      }
    3. 添加组件属性:只⽀持属性
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      {
      "targets": [
      "miniapp"
      ],
      "miniapp": {
      "template": {
      "cover-view": {
      "add": {
      "props": [
      { "name": "test1", "default": "123" },
      { "name": "test2", "default": 123 },
      { "name": "test3", "default": false }
      ]
      }
      }
      }
      }
      }
    4. 删除⽆⽤template:针对不⽤的原⽣内置组件
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      {
      "targets": [
      "miniapp"
      ],
      "miniapp": {
      "template": {
      "delete": [
      "canvas",
      "progress"
      ]
      }
      }
      }

Rax⼩程序API

核⼼API

DOM
  1. render

    在container ⾥通过指定的 Driver, 渲染⼀个 Rax 元素,并返回该根组件的实例;如果提供了可选的回调函数,该回调将在组件被渲染或更新之后被执⾏;

    • element:任意需要渲染的 Rax 组件或字符串
    • container:任意指定 DOM 渲染容器
    • options:
      • driver : 指定 Driver,包含:DriverDom、DriverWeex、DriverUniversal
      • hydrate: 指定是否开启 hydrate 渲染模式,默认为 false
        • 最⼤程度的复⽤容器节点中已有的元素:SEO、SSR
    • callback:传⼊回调函数,将在组件被渲染或更新之后被执⾏
      1
      2
      3
      4
      5
      6
      7
      8
      9
      render(element, container, options, [callback])
      import { render } from 'rax';
      import DriverDom from 'driver-dom';

      const HelloMessage = function (props) {
      return <h1>{props.name}</h1>
      };

      render(<HelloMessage name="world" />, document.body, { driver: DriverDom })
  2. hydrate

    最⼤程度的复⽤容器节点中已有的元素

    • element:任意需要渲染的 Rax 组件或字符串
    • container:为任意指定 DOM 渲染容器
    • callback:传⼊回调函数,将在组件被渲染或更新之后被执⾏
      1
      2
      3
      4
      5
      6
      7
      8
      hydrate(element, container, [callback])
      import hydrate from 'rax-hydrate';

      // MyComponent.jsx
      function MyComponent(props) {
      return <h1>Hello world</h1>;
      }
      hydrate(<MyComponent />, document.body);
  3. createPortal

    提供了⼀种将⼦元素渲染到存在于 DOM 组件层次结构之外的 DOM 节点中。

    • child 是任何可渲染的 Rax ⼦元素,例如⼀个元素,字符串或 Fragment;
    • container 是⼀个 DOM 元素;
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      import createPortal from 'rax-create-portal';
      const Portal = ({ children }) => {
      const el = useRef(document.createElement('div'));
      useEffect(() => {
      document.body.appendChild(el.current);
      return () => {
      el.current.parentElement.removeChild(el.current);
      };
      }, [])

      // 无需再创建一个新的节点,它只是把 children 组件渲染到 el.current 中
      return createPortal(children, el.current);
      }

      function App() {
      return <div>
      <Portal>
      <text>Hello Rax</text>
      </Portal>
      </div>
      }
  4. unmountComponentAtNode

    卸载通过 render 函数渲染的组件

    • container:为需要卸载的 DOM 元素
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      unmountComponentAtNode(container)

      import {createElement, render, useRef, useEffect } from 'rax';
      import unmountComponentAtNode from 'rax-unmount-component-at-node';
      import View from 'rax-view';
      import Text from 'rax-text';

      function App() {
      const ref = useRef(null);
      useEffect(() => {
      const result = unmountComponentAtNode(ref.current);
      });
      return <View>
      <Text ref={ref}>Hello Rax!</Text>
      </View>;
      }
  5. findDOMNode

    通过ref获取真正的 DOM 元素,以便对 DOM 节点进⾏操作

    • component 参数可以是 Rax 元素或者 DOM,均可返回真实 DOM 节点。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      findDOMNode(component)
      import {createElement, render, useRef, useEffect } from 'rax';
      import findDOMNode from 'rax-find-dom-node';
      import View from 'rax-view';

      function App() {
      const ref = useRef(null);
      useEffect(() => {
      const dom = findDOMNode(ref.current);
      });
      return <View ref={ref} ></View>;
      }
  6. setNativeProps

    通过 setNativeProps 可以直接更改原⽣组件的属性来更新组件状态,避免多次render

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    setNativeProps(node, props?)
    import { createElement, Component, render, useRef } from 'rax';
    import View from 'rax-view';
    import Text from 'rax-text';
    import setNativeProps from 'rax-set-native-props';
    function App() {
    const textRef = useRef(null);
    function updateStyle() {
    setNativeProps(textRef.current, {
    style: {
    color: '#dddddd'
    } });
    }
    return <View>
    <Text ref={textRef} >setNativeProps</Text>
    <View onClick={updateStyle}>
    <Text > </Text>
    </View>
    </View>
    }
  7. getElementById

    ⾼效查找特定元素的⽅法

    • id:为指定id
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      getElementById(id)
      import { createElement, Component, render } from 'rax';
      import View from 'rax-view';
      import Text from 'rax-text';
      import getElementById from 'rax-get-element-by-id';
      function App() {
      function focus() {
      getElementById('input').focus();
      }
      return <View>
      <Input id="input" />
      <Text onClick={focus}>input focus</Text>
      </View>
      }
Element
  1. createElement

    ⽤于创建并返回指定类型的 Rax 元素

    • type:类型参数为标签名字符串或 Rax 元素;
    • props:标签的属性;
    • children 从第三个参数开始为元素的⼦节点,有多少个⼦节点就创建多少个;
      1
      2
      3
      4
      5
      6
      7
      createElement(type, [props], [...children])
      import { createElement } from 'rax';
      createElement(
      'div',
      { id: 'foo' },
      createElement('p', null, 'hello world')
      );
  2. cloneElement

    以 Rax 元素为模板克隆并返回新的 Rax 元素,将传⼊的 props 与原始元素的 props 浅层合并后返回新元素的 props。新的⼦元素将取代现有的⼦元素,⽽来⾃原始元素的 key 和 ref 将被保留。

    • element:Rax 元素;
    • props:标签的属性;
    • children :从第三个参数开始为元素的⼦节点,有多少个⼦节点就创建多少个;
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      cloneElement(element, [props], [...children])
      import cloneElement from 'rax-clone-element';
      import View from 'rax-view';
      import Text from 'rax-text';
      function Hello({ name }) {
      const Banner = <Text>Hello Rax!</Text>;
      return cloneElement(Banner);
      }
      function App() {
      return <View>
      <Hello></Hello>
      </View>
      }
  3. isValidElement

    ⽤于判断传⼊的对象是否为有效 Rax 元素,返回值为 true 或 false

    • object:为 Rax 元素,校验通过返回 true,校验失败返回 false
      1
      2
      3
      4
      5
      6
      7
      8
      9
      isValidElement(object)

      import isValidElement from 'rax-is-valid-element';
      const Hello = <h1>Hello </h1>;
      const App = () => <div>{Hello}</div>;
      console.log('Hello is valid? ', isValidElement(Hello));
      // => true
      console.log('App is valid? ', isValidElement(App));
      // => false
  4. createFactory

    通过⼯⼚⽅法创建 Rax 组件实例,该⽅法就是对 createElement() 的封装;

    • type: 为类型参数
      1
      2
      3
      4
      5
      6
      7
      8
      9
      createFactory(type)
      import { createElement } from 'rax';
      import createFactory from 'rax-create-factory';

      // createFactory(type);
      const factory = createFactory('li');
      const li1 = factory(null /** props */, 'Hello Rax!'/** children */);
      const li2 = factory(null /** props */, 'Hello Rax!'/** children */);
      createElement('ul', null, li1, li2);
  5. Children

    Children 提供了⽤于处理 props.children 不透明数据结构的实⽤⽅法

    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
    // Children.map(children, function[(thisArg)])
    import Children from 'rax-children';
    function Hello({ children }) {
    return Children.map(children, (child, i) => {
    if ( i < 1 ) return;
    return child;
    });
    }
    function App() {
    return <Hello>
    <Text>Hello</Text>
    <Text>Rax</Text>
    </Hello>
    }

    // 与 Children.map() 类似,但不返回处理后的节点数组,仅遍历节点,多用于处理数据
    // Children.forEach(children, function[(thisArg)])
    function Hello({ children }) {
    Children.forEach(children, (child, i) => {
    if ( i < 1 ) {
    child.props.children = 'Hello' + child.props.children
    }; });
    return children
    }
    function App() {
    return <Hello>
    <Text>World</Text>
    <Text>Rax</Text>
    </Hello>
    }

    // 返回 children 中的元素总数据,等同于通过 map 或 forEach 调用回调函数的次数
    // Children.count(children)
    function Hello({ children }) {
    const count = Children.count(children);
    return children
    }
    function App() {
    return <Hello>
    <Text>World</Text>
    <Text>Rax</Text>
    </Hello>
    }

    // 验证 children 是否是只有一个子节点(一个 React 元素),如果有则返回它,否则此方法会抛出错误
    // Children.only(children)
    function Hello({ children }) {
    const only = Children.only(children);
    return only ? children : null;
    }
    function App() {
    return <Hello>
    <Text>World</Text>
    </Hello>
    }

    // 将 children 这个复杂的数据结构以数组的方式扁平展开并返回
    // Children.toArray(children)
    function Hello({ children }) {
    const [state, setState] = useState('Rax');
    return Children.toArray(children).filter(child => child.props.children === state);
    }
    function App() {
    return <Hello>
    <Text>Rax</Text>
    <Text>World</Text>
    </Hello>
    }

Rax 的核⼼是组件。你可以像嵌套 html 标签那样嵌套 Rax 组件,因为它类似于标记,使得编写 jsx 变得很容易。因为我们使⽤的是 javascript,我们可以改变 props.children。我们可以给他们传递特殊的属性,来决定是否渲染他们并且可以按照我们的意愿去操作他们。 Children 提供了⽤于处理 props.children 不透明数据结构的实⽤⽅法。从本质上来讲,props.children 可以是任何的类型,⽐如数组、函数、对象等等。

Component
  1. memo

    在函数组件,如果你的函数组件在给定相同 props 的情况下渲染相同的结果

    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
    import { memo, useState } from 'rax';
    import View from 'rax-view';
    import Text from 'rax-text';
    const useUpdate = () => {
    const [, setState] = useState(0);
    return () => setState(num => num + 1);
    };
    const HelloMemo = memo((props) => {
    console.log('memo-render');
    return <Text>{props.children}</Text>
    });
    const HelloNormal = (props) => {
    console.log('normal-render');
    return <Text>{props.children}</Text>
    }
    function App() {
    console.log('render')
    const update = useUpdate();
    const [state, setState] = useState(1);
    return (
    <View>
    <HelloNormal>Rax</HelloNormal> // 会 rerender
    <HelloMemo>Hello</HelloMemo> // 不会 rerender
    <View>{state}</View>
    <View onClick={() => setState(num => num + 1)}>Update</View>
    </View>
    )
    }
Hooks

⽀持的Hooks包括:

  • useState
  • useEffect
  • useLayoutEffect
  • useContext
  • useRef
  • useCallback
  • useMemo
  • useReducer
Refs
  1. createRef

    创建一个能够通过 ref 属性附加到 Rax 元素的 ref。当你需要访问节点时,可以通过 ref.current 得到

    1
    2
    3
    4
    5
    6
    7
    8
    import { createRef, useEffect } from 'rax';
    function App() {
    const inputRef = createRef();
    useEffect(() => {
    inputRef.current.focus();
    }, [inputRef.current]);
    return <input type="text" ref={inputRef} />;
    }
  2. forwardRef

    Ref转发,会创建⼀个 Rax 组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另⼀个组件中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import { forwardRef } from 'rax';
    import View from 'rax-view';
    import Text from 'rax-text';

    const MyInput = forwardRef((props, ref) => (
    <input type="text" ref={ref}></input>
    ));

    function App() {
    const ref = createRef();

    const focus = () => {
    ref.current.focus();
    };

    return (
    <View>
    <MyInput ref={ref}></MyInput>
    <View onClick={focus}>Click</View>
    </View>
    )
    }
Fragment

用于减少不必要嵌套的组件

1
2
3
4
5
6
7
8
9
<Fragment>
<header>A heading</header>
<footer>A footer</footer>
</Fragment>
// JSX 也提供了短语法,小程序暂未支持
<>
<header>A heading</header>
<footer>A footer</footer>
</>
Context

创建⼀个 Context 对象。当 Rax 渲染⼀个订阅了这个 Context 对象的组件,这个组件会从组件树中离⾃身最近的那个匹配的 Provider 中读取到当前的 context 值。

不建议,如果有需要可以使⽤store

1
2
import { createContext } from 'rax';
const MyContext = createContext(defaultValue);
PropTypes

要在组件的 props 上进行类型检查,只需配置特定的 propTypes 属性 -> 建议使用 TS

1
2
3
4
5
6
7
8
9
10
11
12
13
import PropTypes from 'prop-types'; 
MyComponent.propTypes = {
// 可以将属性声明为 js 原生属性,默认情况下这些属性都是可选的
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可以被渲染的元素(包括数字、字符串、元素或数组
optionalNode: PropTypes.node
}
version

获取当前Rax core版本

1
2
3
import { version } from 'rax';
console.log('version: ', version);
// ==> version: 1.0.4
其他扩展Hooks
名称 描述
useMountedState 获取当前mounted状态
useMounted 组件mounted回调
useUnmount 组件unmounted回调
useInterval setInterval基础上,在组件mount前clearInterval避免错误发送
useOnceEffect effect执⾏⼀次
useTimeout 似useInterval,在组件mount前clearTimeout避免错误发送
useAsyncEffect ⽤于异步的effect
useOnceAsyncEffect 异步effect执⾏⼀次
usePromise 适⽤于promise场景
useFetch 适⽤于fetch请求场景
useImport 动态引⼊组件
useCountDown 返回倒计时时分秒等信息

Uni API

基于Rax 跨端开发的能⼒,推出了 Uni API,抹平了Web、Weex、多端⼩程序的差异;

基础
名称 描述
env 判断和获取运⾏时环境(如isWeb、isWeex、isMiniApp etc)
canIUse 判断 API 是否可⽤
request ⽤于发起⽹络请求 注意:此 API 不⽀持 promise 调⽤
unitTool ⼯具库,px2rpx, rpx2px
应用
名称 描述
getApp 取全局唯⼀应⽤实例
getCurrentPages 获取当前⻚⾯栈。数组中第⼀个元素为⾸⻚,最后⼀个元素为当前⻚⾯
getLaunchOptionsSync 获取⼩程序启动时的参数
unitTool ⼯具库,px2rpx, rpx2px
onError 错误事件的监听
onUnhandledRejection 错误事件的监听的promise拒绝事件
offError 取消错误事件的监听
onUnhandledRejection 取消错误事件的监听的promise拒绝事件
设备
名称 描述
scan 获取全局调⽤扫⼀扫功能的 API
getClipboard 获取当前⻚⾯栈获取系统剪贴板的内容
setClipboard 设置系统剪贴板的内容
systemInfo 获取系统信息
makePhoneCall 拨打电话
文件
名称 描述
download 下载资源到本地
getInfo 下载资源信息
getSavedInfo 获取保存的⽂件
openDocument 在新⻚⾯打开预览
removedSaved 移除保存的⽂件
upload 上传⽂件到服务器
界面
名称 描述
alert 警告框
confirm 模态对话框
getScrollOffset 获取元素移动位置信息
getBoundingClientRect 获取元素getBoundingClientRect
getMenuButtonBoundingClientRect 解获取菜单按钮(右上⻆胶囊按钮)的布局位置信息
showLoading/hideLoading 显示/关闭 loading 提示框
showToast/hideToast 显示/关闭 Toast 提示框
showTabBar/hideTabBar 显示/关闭 tabBar
actionSheet 显示操作菜单
intersectionObserver ⽤于推断某些节点是否可以被⽤户看⻅、有多⼤⽐例可以被⽤户看⻅
onPullDownRefresh 开启下拉刷新
startPullDownRefresh/stopPullDo wnRefresh 开始/关闭下拉刷新
createTransition 创建⼀个过渡动画
createAnimation 创建⼀个过渡动画实例
setNavigationBarColor 设置⻚⾯导航条颜⾊
setNavigationBarTitle 设置⻚⾯导航条⽂案
pageScrollTo 滚动到制定位置
多媒体
名称 描述
chooseImage 本地选择相册或拍照
chooseMedia 拍摄或从⼿机相册中选择图⽚或视频
chooseVideo 拍摄视频或从⼿机相册中选视频
compressImage 压缩图⽚
createAudioContext/create 、VideoContext 创建⾳视频
getImageInfo 获取照⽚信息
previewImage 全屏预览图⽚
saveImage 保存图⽚到本地相册
RecorderManager 获取录⾳管理器
路由
名称 描述
navigate go、replace、back、push、relaunch、switchTab
缓存
名称 描述
getStorage 从本地缓存中异步获取指定 key 的内容
getStorageSync 从本地缓存中同步获取指定 key 的内容
removeStorage 从本地缓存中异步移除指定 key
removeStorageSync 从本地缓存中同步移除指定 key
setStorage 将数据异步存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容
setStorageSync 将数据同步存储在本地缓存中指定的 key 中。会覆盖掉原来该 key 对应的内容

https://rax.js.org/docs/api/about

Rax⼩程序组件

基础元件

即通⽤的universal组件,⽀持Web、各种⼩程序;

  • 属性
属性名 类型 描述
style object 为元素设置内联样式
className string 类选择器,允许以⼀种独⽴于⽂档元素的⽅式来指定样式
  • 事件
事件名 类型 描述
onClick function 当组件被点击时触发的事件

⽀持的基础元件包括:

基础元件 描述
Text ⽤于显示⽂本,在 web 中实际上是⼀个 span 标签⽽⾮ p 标签
View 最基础的组件,它⽀持 Flexbox、touch handling 等功能,并且可以任意嵌套,像 web 中的 div 。 ⽀持任意⾃定义属性的透传
TextInput TextInput 是唤起⽤户输⼊的基础组件;当定义 multiline 输⼊多⾏⽂字时其功能相当于 textarea;
Link Link 是基础的链接组件,同 a 标签。它带有默认样式; ⼩程序场景使⽤ navigator 标签
Icon 图标组件
Image 展示图⽚
Video 视频播放组件
ScrollView 包装了滚动操作的组件。需要⼀个确定的⾼度来保证 ScrollView 的正常展现
Waterfall 实现瀑布流容器
Portal 提供了“传送”能⼒,可以将任意 RaxNode 渲染⾄根节点(body),⻅example
Embed 内嵌内容容器,在 weex 下为 <web> 实现,在 web 下为<iframe> <embed> 实现,⼩程序中实现为<webview>
Countdown 倒计时组件
Swiper 轮播组件
Modal 弹出遮罩层的能⼒,为 Alert, Confirm 等对话框组件提供底层能⼒

基础组件

使⽤Fusion Mobile作为移动端的组件库

使⽤⽅式

1
2
npm install @alifd/meet -S
npm i build-plugin-fusion-mobile -D
1
2
3
4
5
6
7
8
9
10
{
"targets": [
"web",
"wechat-miniprogram"
],
"plugins": [
"@ali/build-plugin-rax-app-def",
"build-plugin-fusion-mobile"
]
}
1
2
3
4
5
6
7
8
9
10
import { createElement } from 'rax';
import { Button } from '@alifd/meet';
import '@alifd/meet/es/core/index.css';
export default function Home() {
return (
<>
<Button type="primary">Hello World</Button>
</>
);
}

https://rax.js.org/docs/components/meet-about

补充知识点