//定义全局class.primary-color{color:v-bind(primaryColor);}.border-color{color:v-bind(borderColor);}随着小程序用户的增多,越来越多的平台开始扩展小程序能力。比如传统的微信小程序,我厂的京东小程序,字节跳动和百度等很多平台都在加入。但是,目前的开发环境是“小步快迭代”。于是,“一套代码,多端运行”成为了很多团队的梦想。我们在最近的京彩云手机商城项目中使用了Taro+Vue3+NutUI3,践行了多端开发之路。开发背景(项目背景)京财云集需求管理、采购招投标、供应商管理、自助商城、合同履约协调、财务结算“六大管理能力”于一体,可高效完成多家供应商的引进和采购。全生命周期管理,通过智能采购分析,帮助企业自动匹配采购需求和采购计划,实现便捷高效的供应链管理。同时,产品希望项目不仅可以运行在PC端,还需要开发H5页面,方便嵌入到客户APP中,满足自建电商商城的客服需求。下一阶段,也希望该项目能够快速应用在小程序中。技术选型与介绍技术对比刚接到需求,就开始调研目前市面上的多端框架,如Taro、uni-app、chameleon等。为了找到更适合自己的框架,我们从以下几个方面进行了比较:开发工具uni-app应该是最好的,它的文档内容最翔实丰富,还自带IDE图形化开发工具(HBuilderX),轻点鼠标即可编译、测试、发布。其他框架使用CLI命令行工具,但值得注意的是,chameleon有单独的语法检查工具,而Taro单独编写了ESLint规则和规则集。技术栈mpvue、uni-app、Taro都支持TypeScript,还可以通过打字实现编辑器自动补全。除了API补全,得益于TypeScript对JSX的良好支持,Taro还可以自动补全组件。但是Taro可以对React和Vue都提供完整的支持,其他的只能支持一种前端框架。在CSS语法方面,所有框架都支持SCSS、LESS、Stylus,而Taro则多支持一种CSSModules。多终端支持目前uni-app、Taro、chameleon都可以支持市面上常见的小程序。性能对比无论是Taro还是uni-app,setData的优化都是小程序性能优化中最重要的,优化的方向主要有两个:尽可能降低setData的调用频率和尽可能减少单个setData传输的数据。我自己写了一个长列表测试。我分别写了太郎版、uni-app版、原生小程序版。前几页数据滚动的效率差不多,但是在第7页和第8页之后,我发现uni-app加载了一个新的页面。有时感觉很慢。推测是uni-app的长列表没有回收机制。花了一些时间来改进演示。往下滚动的时候,前面几页的数据会被抹掉,再往下滚动就感觉不到流畅度的差别了。所以总结Taro做了比较细致的性能优化,使用uni-app需要注意代码优化。综上所述,Taro和uni-app是目前市面上最好的多端框架。所有指标都具有可比性。但Taro对开发者更加开放和多元化,同时配合更符合京东风格的NutUI组件库。所以Taro+NutUI3成为我们的首选。先介绍一下我们要用到的工具Taro。Taro是一个开放的跨终端跨框架解决方案,支持使用React/Vue/Nerv等框架开发微信/京东/百度/支付宝/字节跳动/QQ小程序/H5/RN等应用。目前Taro已经进入3.x时代,更加高效精简的DOM/BOMAPI包(taro-runtime)可以同时实现React和Vue2/3的开发。@tarojs/runtime是Taro运行时适配器的核心,实现了一个精简的DOM、BOMAPI、事件系统、web框架和小程序框架的桥接层等,此时web框架可以使用Taro模拟的API渲染一个TaroDOM树,但它都运行在小程序的逻辑层上。小程序的xml模板需要提前写好。Taro是如何使用一个静态的模板文件来渲染这个动态的TaroDOM树的呢?Taro选择利用小程序可以引用其他特性的特性,将TaroDOM树的每一个DOM节点一一渲染。这时候只需要将TaroDOM树的序列化数据setData即可触发数据的相互引用,从而渲染出最终的UI。我们将在下面详细介绍更多原理。NutUI是作为京东风格的轻量级移动端Vue组件库引入的。在NutUI3版本中,采用了Vite+Vue3+ts的架构,全面支持小程序的适配。Taro也正式使用NutUI作为Vue技术栈的推荐组件库。NutUI如何支持小程序?对于每个组件,我们在原组件的目录结构中添加一个.taro.vue文件,专门处理Taro兼容性。使用时,可以根据需要安装普通的Vue3版本或者Taro版本。#Vue3项目npmi@nutui/nutui@next-S#NutUI小程序多终端项目npmi@nutui/nutui@taro-S使用时根据不同来源参考相应的组件。import{createApp}from'vue';//vueimport{Button}from'@nutui/nutui';//taroimport{Button}from'@nutui/nutui-taro';这样我们就可以在Taro组件库中使用这套了。业务拓展京彩云商城为了满足企业客户搭建自己的电子商务商城的需求,构建了一套完整的商城流程,包括首页(banner地图、导航、推荐等楼层)、分类、搜索、商品详情、店铺列表、店铺详情、购物车、订单、个人页面、地址选择等。同时,针对大批量采购,增加了订单提交和审批流程。同时,后期将丰富商城功能,为客户提供更高效快捷的采购服务。先来个视觉体验吧~####支持多平台嵌入,方便企业客户内部APP引入我们商城,更好的引流商城商品。只要在客户的app中加入我们的入口链接,使用cookies打开登录状态,就可以完美嵌入。我们通过设置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文件。我们希望通过一个接口返回主题颜色,进而实现主题的渲染。如何?得益于Vue3sfc的功能,我们可以直接在Vue文件的样式中编写css样式时使用v-bind绑定变量,从而实现在css样式中使用JS中的变量。constcolorState=reactive({primaryColor:'#f0250f',//默认颜色borderColor:#fef4f3});//获取App.vue中的全局主题router.isReady().then(async()=>{...constresult=awaitgetTheme();//获取主题界面if(result?.state===0){colorState.primaryColor=result.primaryColor;colorState.borderColor=result.borderColor;}});//定义全局class.primary-color{color:v-bind(primaryColor);}.border-color{color:v-bind(borderColor);}通过上面的定义,我们可以直接在代码中使用css类primary-color等实现动态样式。Taro+NutUI的应用随着Vue3的正式发布,更好的性能,更小的体积,更好的TypeScript集成,以及更能处理大规模用例的新API,所有开发者都开始拥抱Vue3。Taro顺势而为,很快开始在Taro3中支持Vue3代码转换,NutUI也紧随其后。首先完成了所有组件从Vue2到Vue3的升级,然后完成了Taro的适配,更好的服务开发。人员。目前Taro只提供一种开发方式:安装Taro命令行工具(TaroCLI)进行开发。您可以在安装TaroCLI后通过在终端中输入命令npmi-g@tarojs/cli来使用它。Taro的使用和开发官网都有完整的教程,这里不再赘述。下面重点看看Taro和NutUI是如何实现一套代码实现多个应用的??。我们先来看看小程序的结构。微信小程序主要分为逻辑层和视图层,以及它们下面的原生部分。逻辑层主要负责JS运行,视图层主要负责页面渲染。它们主要通过Event和Data进行通信,同时通过JSBridge调用原生API。这也是以微信小程序为首的大部分小程序的结构。小程序的原生部分每个平台都不一样,这部分是前端开发的黑盒。所以前端层面只需要关注逻辑层和视图层。因此,只需要在逻辑层调用相应的App()/Page()方法,并在方法中处理数据,提供生命周期/事件函数等,并在视图中提供相应的模板和样式进行渲染即可层来运行小程序。这也是大部分小程序开发框架所关注和处理的部分。所以对于前端来说,不管是Vue还是React是什么框架,最终的运行结果都是调用了浏览器的几个BOM/DOMAPI,比如:createElement、appendChild、removeChild等。因此,如前所述,Taro使用taro-runtime来完成这个API。接下来在React中实现了一个taro-react包,用于连接taro-runtime和React维护DOM树的核心react-reconciler,从而实现render功能,生成TaroDOMTree。Vue也会处理,在Vue的CreateVuePage方法中对齐一些runtime方法的处理,比如lifecycle或者watch。通过Taro内部的插件,Taro会生成一个TaroDOMTree,那么TaroDOMTree是如何对齐小程序并渲染到小程序页面的呢?首先,我们将小程序的所有组件一一模板化,从而得到对应的小程序组件模板。下图是小程序的视图组件经过模板处理后的外观:下一步,我们会遍历我们的TaroDOMTree,然后根据每个子元素的类型选择对应的小程序模板来渲染子元素,然后在每个模板中我们会遍历当前元素的子元素,递归遍历整个节点树。终于可以成功渲染到小程序上了。//Taro转换的Dom树{1:[{type:REPLACE,node:ELEMENT}],2:[{type:text,content:'text',children:[...]}],3:[{type:PROPS,props:{class:"content",number:1},...}],...10:[{type:ELEMENT,tage:"ul",childred:[{tag:"li",children:["item"]},...]}]}当然可以看到这是一个普通的虚拟dom树。类似于constnewVnode=h("div#container.two.classes",{on:{click:anotherEventHandler}},[h("span",{style:{fontWeight:"normal",fontStyle:"italic"}},"现在是斜体"),"这仍然只是普通文本",h("a",{props:{href:"/bar"}},"我带你去!"),]);然后,我们动态递归地处理这个dom树,将其转换成符合小程序的格式,从而在小程序上完美展示。Text......那么NutUI组件库是如何实现小程序的呢?关于适应?上面我们提到,NutUI为每个组件设置了一个单独的Taro文件,比如button.taro.vue。太郎的特别改编。其中view标签直接作为常量容器使用,更适合小程序的转换。我们来看看这个文件的内容:同时借助tarojs/plugin-html实现了一些dom和事件处理。//Dom转换if(inlineElements.has(nodeName){return"text"}elseif(specialElements.has(nodeName)){return"view"}elseif(...)//事件的处理onAddEvent(type,_hader_,_options,node){if(!isHtmlTags(node.nodeName))return;//click事件转换为tapif(type=="click"){defineMappedProp(node._handlers,type,"tap")}elseif(type=="input"){defineMappedProp...}}当然在项目优化和反射开发的过程中会遇到很多问题,值得记录下来,以便下次开发更好的服务。路由开始withTaro真正的路由并没有在Vue中实现,而是通过控制组件的真实/隐藏来模拟路由切换。所以历史上做了一个10层的限制。在使用Taro.navigateTo跳转的时候,很快就会了突破第10层,这就需要我们对navigateTo函数做一层封装,防止溢出。另外,因为没有真正的路由,所以whnA页面跳转到B页面,A页面并没有消失,只是通过显示:none隐藏,并给A页面一个唯一的随机id。尽管如此,我们在操作DOM元素或者代码中的一些setInterval方法时还是要特别注意。Taro不会每次进入页面都刷新,而Destroywithoutleaving、refresh、cleardata动作需要在生命周期函数中主动触发。缓存页面内容连接上面的内容,通过navigateTo完成路由跳转。当A页面进入B页面再回到A页面时,实际上A页面并没有被重新渲染。最后的数据将被保留。实现了类似Vue中keep-alive组件的效果。但是因为没有提供额外的生命周期函数,所以不会更新数据。即使强行更新驱动数据,由于上次渲染的缓存,页面也会出现闪烁变化,影响用户体验。所以建议每次beforeMount前清理一下当前页面数据,避免闪退。同时使用navigateTo小心跳转,使用redirectTo完成路由。监听页面滚动事件为了适应小程序,页面滚动事件只能通过onPageScroll来监听,所以当我想在组件中进行监听操作时,需要将这部分的逻辑提前到onPageScroll函数中,增加了抽象的成本。比如我需要开发一个tab,当滚动到某个位置时会被吸到最上面。可以在选项卡内部处理的逻辑是高级的,降低了它的可重用性。优化性能优化是每个项目的重点内容,我们总结了一些常用的优化点。总结作为第一个使用Taro+Vue3+NutUI3完成的项目,开发中虽然遇到了很多问题,但也收获不少。“一个代码,多端应用”的需求场景会越来越多,我们也会在更多业务中深入实践,完成自我提升。