NutUI3 多端开发实践

随着小程序用户增多,越来越多的平台开始扩展自己的小程序能力。如传统微信小程序,我厂的京东小程序,字节和百度等众多平台都在加入。但是当前的开发大环境,却是"小步快跑,快速迭代"。那么,"一套代码,多端运行"成为很多团队实践的梦想。我们在最近的京采云移动端商城项目中使用 Taro + Vue3 + NutUI3 , 实践了一下多端开发之路。

NutUI3 多端开发实践_第1张图片

开发背景(项目背景)

京采云将需求管理、寻源招标、供应商管理、自助式商城、履约协同、财务结算“六大管理能力”集于一体,能够高效完成多供应商的引入和全生命周期管理,并通过智能化采购分析帮助企业将采购需求和采购方案自动匹配,实现便捷、高效的供应链管理。同时,产品希望项目不只能在 PC 端运行,同时还要求开发 H5 页面方便嵌入客户 APP 中,满足客服自建电商商城的需求,且在下一阶段还希望项目能够在小程序中快速应用。
NutUI3 多端开发实践_第2张图片

技术选型和介绍

技术对比

刚接到需求,我们着手调查了市面上目前存在的多端框架,例如 Taro , uni-app , chameleon 等。
为了寻找更适合我们的框架,从以下几个方面做了对比:

  1. 开发工具

uni-app 应该是一骑绝尘,它的文档内容最为翔实丰富,还自带了 IDE 图形化开发工具(HBuilderX),鼠标点点点就能编译测试发布。其它的框架都是使用 CLI 命令行工具,但值得注意的是 chameleon 有独立的语法检查工具,Taro 则单独写了 ESLint 规则和规则集。

  1. 技术栈

mpvue、uni-app、Taro 均支持 TypeScript,也都能通过 typing 实现编辑器自动补全。除了 API 补全之外,得益于 TypeScript 对于 JSX 的良好支持,Taro 也能对组件进行自动补全。但是 Taro 对 React 和 Vue 都能完整的提供支持,其他都只能支持一种前端框架。

而 CSS 语法方面,所有框架均支持 SCSS、LESS、Stylus,Taro 则多一个 CSS Modules 的支持。

  1. 多端支持

目前 uni-app、Taro 和 chameleon 都能支持市面上常见的小程序。

  1. 性能对比

不管是 Taro 还是 uni-app,setData的优化都是小程序性能优化中最为重要之事,且优化主要有两个方向:

  • 尽可能减少 setData 调用的频次
  • 尽可能减少单次 setData 传输的数据

我们自己动手写了一个长列表测试,分别写了 Taro 版、uni-app 版、原生小程序版,前几页数据滚动时效率都差不多,但是7、8页过去后,发现 uni-app 加载新页面时有变慢的感觉。

推测 uni-app 的长列表没有 recycle 机制,花了点时间把 demo 改进了下,滚动下面时把前面几页的数据干掉,然后再滚动就感受不到流畅度的差别了。

所以得出结论:Taro 在性能优化上做的更细致,使用 uni-app 需要自己注意代码优化。

综上所述,Taro 和 uni-app 作为市面上最为优秀的多端框架。在各项指标上都不相上下。但是 Taro 对开发者更加开放且更加多元化,同时配合更符合京东风格的 NutUI 组件库。所以 Taro + NutUI3 成为我们首选。

我们先介绍一下我们将要使用的工具

Taro 介绍

Taro 是一个开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发 微信 / 京东 / 百度 / 支付宝 / 字节跳动 / QQ 小程序 / H5 / RN 等应用。NutUI3 多端开发实践_第3张图片

当前 Taro 已进入 3.x 时代,一套更加高效,精简的 DOM/BOM API 包(taro-runtime)可以实现同时对齐 React 和 Vue 2/3 的开发。

@tarojs/runtime 是 Taro 的运行时适配器核心,它实现了精简的 DOM、BOM API、事件系统、Web 框架和小程序框架的桥接层等

这时 Web 框架就可以使用 Taro 模拟的 API 渲染出一颗 Taro DOM 树,但是这一切都运行在小程序的逻辑层。而小程序的 xml 模板需要提前写死,Taro 如何使用一个静态的模板文件去渲染这颗动态的 Taro DOM 树呢?

Taro 选择了利用小程序 可以引用其它 的特性,把 Taro DOM 树的每个 DOM 节点对应地一个个渲染。这时只需要把 Taro DOM 树的序列化数据进行 setData,就能触发数据的相互引用,从而渲染出最终的 UI。 更多原理我们在下面详细介绍。

NutUI 介绍

作为一个京东风格的轻量级移动端 Vue 组件库,在 NutUI 3 的版本中,采用了 Vite + Vue3 + ts 的架构,同时全面支持小程序的适配。Taro 官方也将 NutUI 作为 Vue 技术栈的推荐组件库。

NutUI 是如何实现支持小程序的?

针对每个组件,我们在原有组件的目录结构中新增 .taro.vue 文件来专门处理 Taro 兼容。而在使用的时候,可以根据你的需求,安装常规 Vue3 版本还是 Taro 版本。

#Vue3 项目  
npm i @nutui/nutui@next -S 
# NutUI 小程序多端项目 
npm i @nutui/nutui@taro -S

而使用的时候,根据不同的源引用对应的组件即可。

import { createApp } from 'vue';
// vue
import { Button } from '@nutui/nutui';
// taro
import { Button } from '@nutui/nutui-taro';

这样,我们就可以在 Taro 中使用这套组件库了。

业务开发

京采云商城为了满足企业客户自建电商商城,搭建了一套完整的商城流程,包括首页(banner 图,导航,推荐等多个楼层),分类,搜索,商品详情,店铺列表,店铺详情,购物车,订单,个人页面,地址 选择等。同时针对大批量采购,增加了订单提报和审批的流程。同时后期将会更加丰富商城功能,为客户提供更高效,快捷的采购服务。

先从视觉上感受一下~

NutUI3 多端开发实践_第4张图片

#### 支持多平台嵌入

为了方便企业客户内 app 引入我们商城,更好的引流商城商品。我们只要客户的 app 内添加我们的入口链接,使用 Cookie 打通登陆态,即可完美嵌入。

我们设置 Cookie 的 domain 参数,来实现不同域名之间访问同一个 Cookie。

document.cookie = "Cookie=testcookie;  domain=test.com;path=/";

主题定制

为了更好的服务各种接入平台,保持与接入平台的风格一致,我们必须实现主题可配置化,根据接入平台的主题色,传入不同的参数实现主题一致的效果。

首先,我们在开发的时候,提取出公共的 SCSS 文件,其中包含我们常见的主题样式变量。

//主题色
$primary-color: #478ef2;

//按钮颜色
$bg-color-selected: #fef4f3;
$bg-color-disabled: #fcd4cf;

//边框颜色
$border-color: #ececec;

// 更多
......

我们在开发过程中,我们直接使用对应的样式变量,既方便我们后期维护,也简单实现了主题一处修改,全局应用的要求。
但是这样我们每次修改主题色都需要修改这个 SCSS 文件,我们希望通过一个接口来返回主题色,然后实现主题的渲染。如何实现呢?
得益于 Vue3 sfc 的功能,我们可以直接在 Vue 文件中的 style 书写 css 样式的时候,可以使用 v-bind 来绑定变量,从而实现 css 样式中使用 JS 中的变量。

const colorState = reactive({
    primaryColor: '#f0250f',   //默认颜色
    borderColor:#fef4f3
});
//在 App.vue 中获取全局主题
router.isReady().then(async () => {
  ...
  const result = await getTheme();  //获取主题的接口
    if (result?.state === 0) {
        colorState.primaryColor = result.primaryColor;
        colorState.borderColor = result.borderColor;
        }
});


通过以上的定义,我们可以在代码中直接使用 css 类 primary-color 等实现动态样式。

Taro + NutUI 的应用

随着 Vue 3 的正式发布,更好的性能,更小的体积,更好的 TypeScript 集成,更好的处理大规模用例的新 API ,所有的开发者开始拥抱 Vue3 。

Taro 紧随潮流,迅速在 Taro3 中开始支持 Vue3 代码的转换,而 NutUI 也紧随其后,首先完成了所有组件 Vue2 到 Vue3 的升级,紧接着完成了对 Taro 的适配,更好的服务开发人员。

目前 Taro 仅提供一种开发方式:安装 Taro 命令行工具(Taro CLI)进行开发。通过在终端输入命令 npm i -g @tarojs/cli 安装 Taro CLI 之后就可以使用了。具体的 Taro 如何使用和开发,在官网上和都有完整的教程,这里我们就不做重点介绍。

下面我们重点研究一下 Taro 和 NutUI 是如何实现一套代码应用多端的。

我们先来看一下小程序的架构。
微信小程序主要分为逻辑层和视图层,以及在他们之下的原生部分。逻辑层主要负责 JS 运行,视图层主要负责页面的渲染,它们之间主要通过 Event 和 Data 进行通信,同时通过 JSBridge 调用原生的 API。这也是以微信小程序为首的大多数小程序的架构。

NutUI3 多端开发实践_第5张图片

小程序原生部分,各个平台是不一样的,而且这部分对于前端开发这就是一个黑盒。所以前端层面只需要关注逻辑层和视图层。

NutUI3 多端开发实践_第6张图片

因此,只需要在逻辑层调用对应的 App()/Page() 方法,且在方法里面处理 data、提供生命周期/事件函数等,同时在视图层提供对应的模版及样式供渲染就能运行小程序了。这也是大多数小程序开发框架重点考虑和处理的部分。

那么对前端来讲,无论什么框架 Vue or React,最终运行结果都是调用了浏览器的几个 BOM/DOM 的 API ,如:createElementappendChildremoveChild 等。因此,上文也提到过,Taro 使用 taro-runtime 完成了这套 API。

接下来,在 React 中实现了一个 taro-react 包,用来连接 taro-runtime 和 React 维护 DOM 树的核心 react-reconciler,从而实现 render 函数,生成 Taro DOM Tree。Vue 同样处理,在 Vue 的 CreateVuePage 方法中对齐 一些运行时方法的处理,如生命周期或者 watch 等。

通过内部的 Taro 插件,Taro就会生成一个Taro DOM Tree,那么Taro DOM Tree 如何对齐小程序,从而渲染到小程序页面上呢?

首先,我们将小程序的所有组件挨个进行模版化处理,从而得到小程序组件对应的模版,如下图就是小程序的 view 组件经过模版化处理后的样子: