- 企微H5在iphone12机型上使用 wx.previewFile 无效?
企微H5在iphone12机型上使用 wx.previewFile 无效?
2021-04-30 - 小程序实现的列表上下拖拽排序
先来看看效果 快速拖拽排序测试演示视频地址:https://v.qq.com/x/page/r3207k4fxe1.html 完整拖拽排序效果演示视频地址:https://v.qq.com/x/page/y3207g6agur.html [图片] 采用技术:uni-app 接下来分析分析实现该效果所需要用到的标签 元素是通过拖拽进行排序的,此处采用的是官方出的 <movable-area> <movable-view> 两位标签大佬解决移动的问题 (主要是相信官方支持的动画会比自己搞更加丝滑一些)。支持拖拽到上下边界,检查可视区域的位置并自动进行滚动, 此处就需要我们的 <scroll-view> 标签大佬坐镇了。标签的选择搞定了,再来了解了解这些标签要用到的重点属性 movable-view 想要移动就必须作为 movable-area 的直接子元素,且 movable-area 必须设置 width,height 属性 (还有些提示可以查看文档)。movable-view 的 x, y 属性决定了 movable-view 再 movable-area 所处的位置 (是不是猜出了要搞些什么东东了)scroll-view 滚动到指定位置可以通过控制 scroll-top 的属性值来进行控制滚动 接下来就是怎么个实现思路,先来捋捋实现的步骤 列表该如何渲染如何控制拖拽元素的跟随如何使拖拽中的元素与相交互的元素进行位置调换如何判断拖拽元素至上下边界滚动屏幕如何使页面的滚动与拖拽时的滚动互不影响 描述完宏观的蓝图,接下来就是代码小细节,客官请随我来 一、解决列表渲染问题 /** * 上面说到 movable-view 可以通过 x,y 决定它的位置, 且 movable-area 需要设置 widht,height 属性 * 配置完这些属性 movable-view 就可以再 movable-area 愉快的拖拽玩耍了 * 思路: * 1. 通过列表的数量乘于显示列表项的高度得出最终可拖拽区域的总高度,赋值给 movable-area * 2. 扩展列表项一些字段,此处使用 y 保存当前项距离顶部位置, idx 保存当前项所在列表的下标 / // 伪代码 // js initList(list) { this.areaHeight = list.length * this.height; // aeraHieght 可拖拽区域总高度, height 为元素所需高度 this.internalList = list.map((item, idx) => { return { ...item, y: idx * this.height, // movable-view 当前项所处的高度 idx: idx, // 当前项所处于列表的下标,用于比较 animation: true, // 主要用于控制拖拽的元素要关闭动画, 其他的元素可以保留动画 } }) } // html 二、 如何控制拖拽元素的跟随 // 主要是通过监听 movable-view 的 touchstart touchmove touchend 三个事件完成拖拽动作的起始、移动、结束。 // methods { _dragStart(e){ // 取得触摸点距离行顶部距离 this.deviationY = (e.mp.touches[0].clientY - this.wrap.top) % this.height; this.internalList[idx].animation = false; // 关闭当前拖拽元素的动画属性 this.activeIdx = idx; // 保存当前拖拽元素的下标 }, _dragMove(e) { const activeItem = this.internalList[this.activeIdx]; if (!activeItem) return; // 实时取得触摸点的位置信息 const clientY = e.mp.touches[0].clientY; let touchY = clientY - this.wrap.top - this.deviationY + this.scrollTop; if (touchY <= 0 || touchY + this.height >= this.areaHeight) return; activeItem.y = touchY; // 拖拽元素的移动秘密就在于此 } } 三、如何使拖拽中的元素与相交互的元素进行位置调换 // 上述代码解决了当前拖拽元素的位置移动问题, 接下来就需要解决拖拽元素和上下元素交互的问题 // methods { __dragMove(e){ // ...同上代码一致 // 上下元素交互位置代码实现 for(let item of this.internalList) { if (item.idx !== activeItem.idx) { if (item.idx > activeItem.idx) { // 如果当前元素下标大于拖拽元素下标,则检查当前拖拽位置是否大于当前元素中心点 if (touchY > item.idx * this.height - this.height / 2) { [activeItem.idx, item.idx] = [item.idx, activeItem.idx]; // 对调位置 item.y = item.idx * this.height; // 更新对调后的位置 break; // 退出循环 } } else { // 如果当前元素下标小于拖拽元素下标,则检查当前拖拽位置是否小于当前元素中心点 if (touchY < item.idx * this.height + this.height / 2) { [activeItem.idx, item.idx] = [item.idx, activeItem.idx]; item.y = item.idx * this.height; break; } } } } } } 四、如何判断拖拽元素至上下边界滚动屏幕 // 将 movable-area 包裹在 scroll-view 标签中, 通过控制 scroll-top 的值来进行滚动 // 思路: 判断当前拖拽元素的位置信息与当前屏幕可视区域进行比较 // methods { _dragMove(e) { // ...同上代码 // 检查当前位置是否处于可视区域 if (activeItem.idx + 1 * this.height + this.height / 2 > this.scrollTop + this.wrap.top) { this.viewTop = this.scrollTop + this.height; // 往上滚动一个元素的高度 } else if (activeItem.idx * this.height - this.height / 2 < this.scrollTop ) { this.viewTop = this.scrollTop - this.height; // 往下滚动一个元素的高度 } } } 五、如何使页面的滚动与拖拽时的滚动互不影响 // 事实上我是通过一种取巧的方式, scroll-veiw 有一个 scroll-y 属性可以控制滚动方向 // 思路: // 1.不进行滚动的时候将 scroll-y 置为 true , 使用默认的滚动效果 // 2.当进入拖拽排序状态时则将 scroll0y 置为 false, 滚动通过拖拽代码比较计算滚动位置 完整代码: 主要小程序上的插槽不允许往外传值、所以自定义元素实现的方式相比于H5实现Vue的方式比较别扭。 因为有多个地方需要用到排序功能,所以边抽离了 js 部分进行混入。 // DargSortMixin.js 文件 export default { props: { list: { type: Array, default() { return []; }, }, sort: { type: Boolean, default: false, }, height: { type: Number, default: 66, }, }, data() { return { areaHeight: 0, // 区域总高度 internalList: [], // 列表 activeIdx: -1, // 移动中激活项 deviationY: 0, // 偏移量 // 包裹容器信息 wrap: { top: 0, height: 0, }, viewTop: 0, // 指定滚动高度 scrollTop: 0, // 容器实时滚动高度 scrollWithAnimation: false, canScroll: true, }; }, created() { // 组件使用选择器,需用使用this const query = this.createSelectorQuery(); query .select('#scroll-wrap') .boundingClientRect(rect => { if (rect) { this.wrap = { top: rect.top, height: rect.height, }; } }) .exec(); }, watch: { list: { handler(val) { this.initList(val); }, immediate: true, }, }, methods: { getList() { return this.internalList .sort((a, b) => { return a.idx - b.idx; }) .map(item => { let newItem = { ...item }; delete newItem.y; delete newItem.idx; delete newItem.animation; return newItem; }); }, initList(list) { this.areaHeight = list.length * this.height; this.internalList = list.map((item, idx) => { return { ...item, y: idx * this.height, idx, animation: true, }; }); }, _dragStart(e, idx) { // 取得触摸点距离行顶部距离 this.deviationY = (e.mp.touches[0].clientY - this.wrap.top) % this.height; this.internalList[idx].animation = false; // 关闭动画 this.activeIdx = idx; this.scrollWithAnimation = true; this.canScroll = false; }, _dragMove(e) { const activeItem = this.internalList[this.activeIdx]; if (!activeItem) return; // 保存触摸点位置和长按时中心一致 const clientY = e.mp.touches[0].clientY; let touchY = clientY - this.wrap.top - this.deviationY + this.scrollTop; if (touchY <= 0 || touchY + this.height >= this.areaHeight) return; activeItem.y = touchY; // 设置位置 // 检查元素和上下交互元素的位置 for (const item of this.internalList) { if (item.idx !== activeItem.idx) { if (item.idx > activeItem.idx) { if (touchY > item.idx * this.height - this.height / 2) { [activeItem.idx, item.idx] = [item.idx, activeItem.idx]; // 对调位置 item.y = item.idx * this.height; // 更新位置 break; } } else { if (touchY < item.idx * this.height + this.height / 2) { [activeItem.idx, item.idx] = [item.idx, activeItem.idx]; // 对调位置 item.y = item.idx * this.height; // 更新位置 break; } } } } // 检查当前位置是否处于可视区域 if ( (activeItem.idx + 1) * this.height + this.height / 2 > this.scrollTop + this.wrap.height ) { this.canScroll = true; activeItem.y = activeItem.idx * this.height; this.$nextTick(() => { this.viewTop = this.scrollTop + this.height; }); } else if (activeItem.idx * this.height - this.height / 2 < this.scrollTop) { this.canScroll = true; activeItem.y = activeItem.idx * this.height; this.$nextTick(() => { this.viewTop = this.scrollTop - this.height; }); } }, _dragEnd(e) { const activeItem = this.internalList[this.activeIdx]; if (!activeItem) return; activeItem.animation = true; activeItem.disabled = true; activeItem.y = activeItem.idx * this.height; this.activeIdx = -1; this.scrollWithAnimation = false; this.canScroll = true; }, _onScroll(e) { this.scrollTop = e.detail.scrollTop; }, }, }; // TheDragSortAreaList.vue 文件 import DragSortMixin from '@/mixins/DragSortMixin'; export default { name: 'TheDragSortTableList', mixins: [DragSortMixin], }; .active-item { z-index: 10; } .drag-item { background: $theme-color; color: $white !important; .count { color: $white !important; } }
2020-11-27 - 小程序多端框架全面测评:chameleon、Taro、uni-app、mpvue、WePY
作者:coldsnap 原文:小程序多端框架全面测评 Fundebug经授权转载,版权归原作者所有。 最近前端届多端框架频出,相信很多有代码多端运行需求的开发者都会产生一些疑惑:这些框架都有什么优缺点?到底应该用哪个? 作为 Taro 开发团队一员,笔者想在本文尽量站在一个客观公正的角度去评价各个框架的选型和优劣。但宥于利益相关,本文的观点很可能是带有偏向性的,大家可以带着批判的眼光去看待,权当抛砖引玉。 那么,当我们在讨论多端框架时,我们在谈论什么: 多端 笔者以为,现在流行的多端框架可以大致分为三类: 1. 全包型 这类框架最大的特点就是从底层的渲染引擎、布局引擎,到中层的 DSL,再到上层的框架全部由自己开发,代表框架是 Qt 和 Flutter。这类框架优点非常明显:性能(的上限)高;各平台渲染结果一致。缺点也非常明显:需要完全重新学习 DSL(QML/Dart),以及难以适配中国特色的端:小程序。 这类框架是最原始也是最纯正的的多端开发框架,由于底层到上层每个环节都掌握在自己手里,也能最大可能地去保证开发和跨端体验一致。但它们的框架研发成本巨大,渲染引擎、布局引擎、DSL、上层框架每个部分都需要大量人力开发维护。 2. Web 技术型 这类框架把 Web 技术(JavaScript,CSS)带到移动开发中,自研布局引擎处理 CSS,使用 JavaScript 写业务逻辑,使用流行的前端框架作为 DSL,各端分别使用各自的原生组件渲染。代表框架是 React Native 和 Weex,这样做的优点有: 开发迅速 复用前端生态 易于学习上手,不管前端后端移动端,多多少少都会一点 JS、CSS 缺点有: 交互复杂时难以写出高性能的代码,这类框架的设计就必然导致 [代码]JS[代码] 和 [代码]Native[代码] 之间需要通信,类似于手势操作这样频繁地触发通信就很可能使得 UI 无法在 16ms 内及时绘制。React Native 有一些声明式的组件可以避免这个问题,但声明式的写法很难满足复杂交互的需求。 由于没有渲染引擎,使用各端的原生组件渲染,相同代码渲染的一致性没有第一种高。 3. JavaScript 编译型 这类框架就是我们这篇文章的主角们:[代码]Taro[代码]、[代码]WePY[代码] 、[代码]uni-app[代码] 、 [代码]mpvue[代码] 、 [代码]chameleon[代码],它们的原理也都大同小异:先以 JavaScript 作为基础选定一个 DSL 框架,以这个 DSL 框架为标准在各端分别编译为不同的代码,各端分别有一个运行时框架或兼容组件库保证代码正确运行。 这类框架最大优点和创造的最大原因就是小程序,因为第一第二种框架其实除了可以跨系统平台之外,也都能编译运行在浏览器中。(Qt 有 Qt for WebAssembly, Flutter 有 Hummingbird,React Native 有 [代码]react-native-web[代码], Weex 原生支持) 另外一个优点是在移动端一般会编译到 React Native/Weex,所以它们也都拥有 Web 技术型框架的优点。这看起来很美好,但实际上 React Native/Weex 的缺点编译型框架也无法避免。除此之外,编译型框架的抽象也不是免费的:当 bug 出现时,问题的根源可能出在运行时、编译时、组件库以及三者依赖的库等等各个方面。在 Taro 开源的过程中,我们就遇到过 Babel 的 bug,React Native 的 bug,JavaScript 引擎的 bug,当然也少不了 Taro 本身的 bug。相信其它原理相同的框架也无法避免这一问题。 但这并不意味着这类为了小程序而设计的多端框架就都不堪大用。首先现在各巨头超级 App 的小程序百花齐放,框架会为了抹平小程序做了许多工作,这些工作在大部分情况下是不需要开发者关心的。其次是许多业务类型并不需要复杂的逻辑和交互,没那么容易触发到框架底层依赖的 bug。 那么当你的业务适合选择编译型框架时,在笔者看来首先要考虑的就是选择 DSL 的起点。因为有多端需求业务通常都希望能快速开发,一个能够快速适应团队开发节奏的 DSL 就至关重要。不管是 React 还是 Vue(或者类 Vue)都有它们的优缺点,大家可以根据团队技术栈和偏好自行选择。 如果不管什么 DSL 都能接受,那就可以进入下一个环节: 生态 以下内容均以各框架现在(2019 年 3 月 11 日)已发布稳定版为标准进行讨论。 1. 开发工具 就开发工具而言 [代码]uni-app[代码] 应该是一骑绝尘,它的文档内容最为翔实丰富,还自带了 IDE 图形化开发工具,鼠标点点点就能编译测试发布。 其它的框架都是使用 CLI 命令行工具,但值得注意的是 [代码]chameleon[代码] 有独立的语法检查工具,[代码]Taro[代码] 则单独写了 ESLint 规则和规则集。 在语法支持方面,[代码]mpvue[代码]、[代码]uni-app[代码]、[代码]Taro[代码] 、[代码]WePY[代码] 均支持 TypeScript,四者也都能通过 [代码]typing[代码] 实现编辑器自动补全。除了 API 补全之外,得益于 TypeScript 对于 JSX 的良好支持,Taro 也能对组件进行自动补全。 CSS 方面,所有框架均支持 [代码]SASS[代码]、[代码]LESS[代码]、[代码]Stylus[代码],Taro 则多一个 [代码]CSS Modules[代码] 的支持。 所以这一轮比拼的结果应该是: uni-app > Taro > chameleon > WePY、mpvue [图片] 2. 多端支持度 只从支持端的数量来看,[代码]Taro[代码] 和 [代码]uni-app[代码] 以六端略微领先(移动端、H5、微信小程序、百度小程序、支付宝小程序、头条小程序),[代码]chameleon[代码] 少了头条小程序紧随其后。 但值得一提的是 [代码]chameleon[代码] 有一套自研多态协议,编写多端代码的体验会好许多,可以说是一个能戳到多端开发痛点的功能。[代码]uni-app[代码] 则有一套独立的条件编译语法,这套语法能同时作用于 [代码]js[代码]、样式和模板文件。[代码]Taro[代码] 可以在业务逻辑中根据环境变量使用条件编译,也可以直接使用条件编译文件(类似 React Native 的方式)。 在移动端方面,[代码]uni-app[代码] 基于 [代码]weex[代码] 定制了一套 [代码]nvue[代码] 方案 弥补 [代码]weex[代码] API 的不足;[代码]Taro[代码]则是暂时基于 [代码]expo[代码] 达到同样的效果;[代码]chameleon[代码] 在移动端则有一套 SDK 配合多端协议与原生语言通信。 H5 方面,[代码]chameleon[代码] 同样是由多态协议实现支持,[代码]uni-app[代码] 和 [代码]Taro[代码] 则是都在 H5 实现了一套兼容的组件库和 API。 [代码]mpvue[代码] 和 [代码]WePY[代码] 都提供了转换各端小程序的功能,但都没有 h5 和移动端的支持。 所以最后一轮对比的结果是: chameleon > Taro、uni-app > mpvue > WePY [图片] 3. 组件库/工具库/demo 作为开源时间最长的框架,[代码]WePY[代码] 不管从 Demo,组件库数量 ,工具库来看都占有一定优势。 [代码]uni-app[代码] 则有自己的插件市场和 UI 库,如果算上收费的框架和插件比起 [代码]WePy[代码] 也是完全不遑多让的。 [代码]Taro[代码] 也有官方维护的跨端 UI 库 [代码]taro-ui[代码] ,另外在状态管理工具上也有非常丰富的选择(Redux、MobX、dva),但 demo 的数量不如前两个。但 [代码]Taro[代码] 有一个转换微信小程序代码为 Taro 代码的工具,可以弥补这一问题。 而 [代码]mpvue[代码] 没有官方维护的 UI 库,[代码]chameleon[代码] 第三方的 demo 和工具库也还基本没有。 所以这轮的排序是: WePY > uni-app 、taro > mpvue > chameleon [图片] 4. 接入成本 接入成本有两个方面: 第一是框架接入原有微信小程序生态。由于目前微信小程序已呈一家独大之势,开源的组件和库(例如 [代码]wxparse[代码]、[代码]echart[代码]、[代码]zan-ui[代码] 等)多是基于原生微信小程序框架语法写成的。目前看来 [代码]uni-app[代码] 、[代码]Taro[代码]、[代码]mpvue[代码] 均有文档或 demo 在框架中直接使用原生小程序组件/库,[代码]WePY[代码] 由于运行机制的问题,很多情况需要小改一下目标库的源码,[代码]chameleon[代码] 则是提供了一个按步骤大改目标库源码的迁移方式。 第二是原有微信小程序项目部分接入框架重构。在这个方面 Taro 在京东购物小程序上进行了大胆的实践,具体可以查看文章《Taro 在京东购物小程序上的实践》。其它框架则没有提到相关内容。 而对于两种接入方式 Taro 都提供了 [代码]taro convert[代码] 功能,既可以将原有微信小程序项目转换为 Taro 多端代码,也可以将微信小程序生态的组件转换为 Taro 组件。 所以这轮的排序是: Taro > mpvue 、 uni-app > WePY > chameleon 流行度 从 GitHub 的 star 来看,[代码]mpvue[代码] 、[代码]Taro[代码]、[代码]WePY[代码] 的差距非常小。从 NPM 和 CNPM 的 CLI 工具下载量来看,是 Taro(3k/week)> mpvue (2k/w) > WePY (1k/w)。但发布时间也刚好反过来。笔者估计三家的流行程度和案例都差不太多。 [代码]uni-app[代码] 则号称有上万案例,但不像其它框架一样有一些大厂应用案例。另外从开发者的数量来看也是 [代码]uni-app[代码] 领先,它拥有 20+ 个 QQ 交流群(最大人数 2000)。 所以从流行程度来看应该是: uni-app > Taro、WePY、mpvue > chameleon [图片] 5. 开源建设 一个开源作品能走多远是由框架维护团队和第三方开发者共同决定的。虽然开源建设不能具体地量化,但依然是衡量一个框架/库生命力的非常重要的标准。 从第三方贡献者数量来看,[代码]Taro[代码] 在这一方面领先,并且 [代码]Taro[代码] 的一些核心包/功能(MobX、CSS Modules、alias)也是由第三方开发者贡献的。除此之外,腾讯开源的 [代码]omi[代码] 框架小程序部分也是基于 Taro 完成的。 [代码]WePY[代码] 在腾讯开源计划的加持下在这一方面也有不错的表现;[代码]mpvue[代码] 由于停滞开发了很久就比较落后了;可能是产品策略的原因,[代码]uni-app[代码] 在开源建设上并不热心,甚至有些部分代码都没有开源;[代码]chameleon[代码] 刚刚开源不久,但它的代码和测试用例都非常规范,以后或许会有不错的表现。 那么这一轮的对比结果是: Taro > WePY > mpvue > chameleon > uni-app 最后补一个总的生态对比图表: [图片] 未来 从各框架已经公布的规划来看: [代码]WePY[代码] 已经发布了 [代码]v2.0.alpha[代码] 版本,虽然没有公开的文档可以查阅到 [代码]2.0[代码] 版本有什么新功能/特性,但据其作者介绍,[代码]WePY 2.0[代码] 会放大招,是一个「对得起开发者」的版本。笔者也非常期待 2.0 正式发布后 [代码]WePY[代码] 的表现。 [代码]mpvue[代码] 已经发布了 [代码]2.0[代码] 的版本,主要是更新了其它端小程序的支持。但从代码提交, issue 的回复/解决率来看,[代码]mpvue[代码] 要想在未来有作为首先要打消社区对于 [代码]mpvue[代码]不管不顾不更新的质疑。 [代码]uni-app[代码] 已经在生态上建设得很好了,应该会在此基础之上继续稳步发展。如果 [代码]uni-app[代码] 能加强开源开放,再加强与大厂的合作,相信未来还能更上一层楼。 [代码]chameleon[代码] 的规划比较宏大,虽然是最后发的框架,但已经在规划或正在实现的功能有: 快应用和端拓展协议 通用组件库和垂直类组件库 面向研发的图形化开发工具 面向非研发的图形化页面搭建工具 如果 [代码]chameleon[代码] 把这些功能都做出来的话,再继续完善生态,争取更多第三方开发者,那么在未来 [代码]chameleon[代码] 将大有可为。 [代码]Taro[代码] 的未来也一样值得憧憬。Taro 即将要发布的 [代码]1.3[代码] 版本就会支持以下功能: 快应用支持 Taro Doctor,自动化检查项目配置和代码合法性 更多的 JSX 语法支持,1.3 之后限制生产力的语法只有 [代码]只能用 map 创造循环组件[代码] 一条 H5 打包体积大幅精简 同时 [代码]Taro[代码] 也正在对移动端进行大规模重构;开发图形化开发工具;开发组件/物料平台以及图形化页面搭建工具。 结语 那说了那么多,到底用哪个呢? 如果不介意尝鲜和学习 DSL 的话,完全可以尝试 [代码]WePY[代码] 2.0 和 [代码]chameleon[代码] ,一个是酝酿了很久的 2.0 全新升级,一个有专门针对多端开发的多态协议。 [代码]uni-app[代码] 和 [代码]Taro[代码] 相比起来就更像是「水桶型」框架,从工具、UI 库,开发体验、多端支持等各方面来看都没有明显的短板。而 [代码]mpvue[代码] 由于开发一度停滞,现在看来各个方面都不如在小程序端基于它的 [代码]uni-app[代码] 。 当然,Talk is cheap。如果对这个话题有更多兴趣的同学可以去 GitHub 另行研究,有空看代码,没空看提交: chameleon: https://github.com/didi/chameleon mpvue: https://github.com/Meituan-Dianping/mpvue Taro: https://github.com/NervJS/taro uni-app: https://github.com/dcloudio/uni-app WePY: https://github.com/Tencent/wepy (按字母顺序排序)
2019-06-18 - 小程序框架对比 ( WePY / mpvue / Taro )
摘要: 对比小程序框架。 原文:小程序第三方框架对比 ( wepy / mpvue / taro ) 公众号:前端小苑 Fundebug经授权转载,版权归原作者所有。 [图片] 众所周知如今市面上端的形态多种多样,手机Web、ReactNative、微信小程序, 支付宝小程序, 快应用等,每一端都是巨大的流量入口,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。但面对目前市面上成熟的小程序第三方框架如何针对自己的需求进行选择也是一个麻烦事,本文针对当前市面上的三大转译框架进行一个综合对比,希望能对大家的技术选择有所帮助,如有哪里不妥的地方希望大家指正。 小程序开发有哪些痛点? 频繁调用 setData及 setData过程中页面跳闪 组件化支持能力太弱(几乎没有) 不能使用 less、scss 等预编译器 request 并发次数限制 为什么使用第三方框架? 只要熟悉vue或react即可快速上手,学习成本低 一套代码可在多端编译运行(微信,支付宝,h5,RN) 支付宝小程序暂不完善 组件化开发,完美解决组件隔离,组件嵌套,组件通信等问题 支持使用第三方 npm 资源 使小程序可支持 Promise,解决回调烦恼 可使用 Generator Function / Class / Async Function 等特性,提升开发效率 对小程序本身的优化,如生命周期的补充,性能的优化等等 支持样式编译器: Scss/Less,模板编译器,代码编译器:Babel/Typescript。 小程序框架对比:WePY / mpvue / Taro 在这里我通过对目前已开源的三种常用小程序框架做一个综合对比, 还有一个叫nanchi的基于react的小程序转译框架,由于没来的及研究暂不做比较。 WePY 腾讯团队开源的一款类vue语法规范的小程序框架,借鉴了Vue的语法风格和功能特性,支持了Vue的诸多特征,比如父子组件、组件之间的通信、computed计算属性、wathcer监听器、props传值、slot槽分发,Mixin混入等。WePY发布的第一个版本是2016年12月份,也就是小程序刚刚推出的时候,到目前为止,WePY已经发布了52个版本, 最新版本为1.7.2; mpvue 美团团队开源的一款使用 Vue.js 开发微信小程序的前端框架。使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力。mpvue在发布后的几天间获得2.7k的star,上升速度飞起,截至目前为止已经有13.7k的star; Taro 京东凹凸实验室开源的一款使用 React.js 开发微信小程序的前端框架。它采用与 React 一致的组件化思想,组件生命周期与 React 保持一致,同时支持使用 JSX 语法,让代码具有更丰富的表现力,使用 Taro 进行开发可以获得和 React 一致的开发体验,同时因为使用了react的原因所以除了能编译h5, 小程序外还可以编译为ReactNative; [图片] [图片] 生命周期 同为vue规范的mpvue和wepy的生命周期和各种方法不尽相同。 WePY wepy生命周期基本与原生小程序相同,再此基础上糅合了一些vue的特性; 对于WePY中的methods属性,因为与Vue中的使用习惯不一致,非常容易造成误解,这里需要特别强调一下:WePY中的methods属性只能声明页面wxml标签的bind、catch事件,不能声明自定义方法,这与Vue中的用法是不一致的。 [图片] [图片] 简单示例Taro与React生命周期完全相同 [图片] 列表渲染 在列表渲染上三者也分别有不同的应用方法 wepy当需要循环渲染WePY组件时(类似于通过wx:for循环渲染原生的wxml标签),必须使用wepy定义的辅助标签。 [图片] mpvue使用v-for与vue一致,只是需要注意一点,嵌套列表渲染,必须指定不同的索引! [图片] taro的列表循环用法基本与react相同,有一点需要注意,在 React 中,JSX 是会编译成普通的 JS 的执行,每一个 JSX 元素,其实会通过 createElement 函数创建成一个 JavaScript 对象(React Element),因此实际上你可以这样写代码 React 也是完全能渲染的: [图片] 但是 Taro 中,JSX 会编译成微信小程序模板字符串,因此你不能把 map 函数生成的模板当做一个数组来处理。当你需要这么做时,应该先处理需要循环的数组,再用处理好的数组来调用 map 函数。例如上例应该写成: [图片] 事件处理 mpvue目前全支持小程序的事件处理器,引入了 Vue.js 的虚拟 DOM ,在前文模版中绑定的事件会被挂在到 vnode 上,同时 compiler 在 wxml 上绑定了小程序的事件,并做了相应的映射,所以在真实点击的时候通过 runtime 中 handleProxy 事件类型分发到 vnode 的事件上,同 Vue 在 WEB 的机制一样,可以做到无损支持。同时还顺便支持了自定义事件和 $emit 机制。 事件映射表,左侧为 WEB 事件,右侧为 小程序 对应事件 [图片] 踩坑注意(官方文档): 列表中没有的原生事件也可以使用例如 bindregionchange 事件直接在 dom 上将bind改为@ @regionchange,同时这个事件也非常特殊,它的 event type 有 begin 和 end 两个,导致我们无法在handleProxy 中区分到底是什么事件,所以你在监听此类事件的时候同时监听事件名和事件类型既 <map @regionchange=“functionName” @end=“functionName” @begin=“functionName”> 小程序能力所致,bind 和 catch 事件同时绑定时候,只会触发 bind ,catch 不会被触发,要避免踩坑 事件修饰符 .stop 的使用会阻止冒泡,但是同时绑定了一个非冒泡事件,会导致该元素上的 catchEventName 失效! .prevent 可以直接干掉,因为小程序里没有什么默认事件,比如submit并不会跳转页面 .capture 支持 1.0.9 .self 没有可以判断的标识 .once也不能做,因为小程序没有 removeEventListener, 虽然可以直接在 handleProxy 中处理,但非常的不优雅,违背了原意,暂不考虑 其他 键值修饰符 等在小程序中压根没键盘,所以… wepy事件绑定区别于vue,根据原生小程序事件提供了语法优化 [图片] Taro 元素的事件处理和 DOM 元素的很相似。但是有一点语法上的不同: Taro 事件绑定属性的命名采用驼峰式写法,而不是小写。 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串 (DOM 元素的写法)。 例如,传统的微信****小程序模板: [图片] Taro 中稍稍有点不同: [图片] 在 Taro 中另一个不同是你不能使用 catchEvent 的方式阻止事件冒泡。你必须明确的使用 stopPropagation。例如,阻止事件冒泡你可以这样写: [图片] request请求 wepy对wx.request做了接受参数的修改,值得一提的是它提供了针对全局的intercapter拦截器。 [图片] 拦截器 [图片] taro对request进行了二次封装,可以使用Taro.request(OBJECT)发起网络请求,支持 Promise 化使用。 [图片] [图片] [图片] mpvue没有对request做特殊优化,与原生相同,可以自己根据需要进行封装 状态管理 wepy 可引用Redux和Mbox,目前wepy的脚手架内已经集成了redux,选择需要即可; mpVue使用vuex; taro使用Redux; 如何选择适合自己的项目 如果只需要做一个微信小程序则根据自己的擅长框架选择mpvue或taro 如果是当前老项目想像向程序迁移同时老项目又是使用vue开发,建议使用mpvue或wepy 如果是老项目使用react开发且需要部分迁移小程序,建议使用taro 如果是新项目且新项目需要同时支持微信小程序和支付宝小程序, 建议使用原生开发,因为目前框架的转译支付宝小程序支持并不是很好,且出了问题不好定位修改, 但如果是小demo不涉及太多逻辑的项目都可以使用框架作为尝鲜; 但如果是涉及太多交互逻辑的则不建议使用框架转译,由于支付宝小程序在视图层基本与小程序一致所以建议手动更改替换部分方法和全局替换一些属性或文件名,如wxml替换为axml这种, 手动转换时间比大概是四比一; 当然如果人手足够一端开发一个是最好的… 时刻前端新鲜技术推送,定期前端精品文章分享,欢迎关注公众号前端小苑。
2019-06-21 - 调用getCurExternalContact时返回permission denied
如题,调用getCurExternalContact时返回getCurExternalContact:permission denied wx.config {"errMsg":"preVerifyJSAPI:ok","checkResult":{"scanQRCode":false}} wx.agentConfig{"errMsg":"agentConfig:ok","checkResult":{"wwapp.initWwOpenData":true,"wwapp.getOpenData":true}} 两个都没问题
2020-06-03 - 小程序请求的流式数据onChunkReceived返回的如何处理?
[图片] [图片]
2023-06-29 - wx.request流式返回的坑这么多吗?
1、RequestTask.onChunkReceived() 注册的函数在:开发者工具、安卓、iOS上均不运行。我以为代码问题,调试好久才发现在Mac真机调试时时没有问题的。已经是最简单的测试代码了,都不运行。 2、iOS、Mac真机环境没有TextDecoder构造函数,开发工具却又有。在Mac真机流式返回了,要转成字符串发现没有TextDecoder,试了iOS环境也没有,不应该啊,难道TextDecoder还要自己实现? 3、RequestTask.onChunkReceived() 流式返回,发现返回的ArrayBuffer的实际大小和Header中的Content-Length不一致,很多时候一个chunk的byteLength就比Content-Length值大了。我还怀疑是Content-Length错了。但同一个资源在浏览器端实际大小就Content-Length完全一样。 这些问题是在封装wx.request过程中发现的。没有遇到过的就不用说了,基本可以排除是代码的问题了。要么各种环境下官方没有对齐,要么是wx.request的bug。 机型:iPhone15 iOS17.3.1、MacBook Pro M1 系统版本Mac os 14.4 (23E214) 开发工具版本:(1.06.2402040 darwin-arm64) 调试基础库:2.33.0--3.4.0都试过 代码段(因分享大小限制,删除了TS类型文件,所以会报TS错,不影响运行):https://developers.weixin.qq.com/s/vORaygmO7AQG onChunkReceived不运行的代码: originRequest(){ const requestTask = wx.request({ url: 'https://picsum.photos/340/195', enableChunked: true, success(res){ console.log('success:', res) }, fail(err){ console.warn('fail:', err); } }); requestTask.onHeadersReceived(h=>console.log('header', h)) requestTask.onChunkReceived((chunk)=>console.log('chunk', chunk)) } Mac真机环境没有TextDecoder的报错: [图片] Mac真机环境chunk和Content-Length不一致: [图片]
2024-04-07 - 关于onChunkReceived在不同客户端输出结果不一致bug
1.代码复现片段 [图片] 2.开发者工具console结果展示 [图片] 3.安卓consoel结果展示 [图片] 4.苹果console结果展示 [图片] 目前遇到的主要问题是ios与安卓结果不一致无法进行处理
02-25 - 小程序基础库 3.7.4 更新
小程序基础库 3.7.4 已经开始灰度开发者,请大家基于业务情况关注相关变更。如遇问题请及时在本帖下方留言或在 小程序交流专区 发表标题包含「基础库3.7.4」的帖子反馈。本次更新如下: 更新 框架 小游戏安卓真机调试支持 Tracing 和网络更新 框架 小游戏 wx.getGameLogManager 修改API设计 详情 更新 框架 Android 上提高 request、downloadFile、uploadFile 并行请求数量上限更新 框架 渲染缓存新增 capture 模式 详情更新 框架 鸿蒙支持 worker更新 框架 小游戏支持KHR_parallel_shader_compile 拓展修复 框架 iOS request enableChunked onChunkReceived 回调丢失 详情 微信团队 2024年12月31日
01-07