- 微信小程序自定义导航栏组件(完美适配所有手机),可自定义实现任何你想要的功能
背景 在做小程序时,关于默认导航栏,我们遇到了以下的问题: Android、IOS手机对于页面title的展示不一致,安卓title的显示不居中 页面的title只支持纯文本级别的样式控制,不能够做更丰富的title效果 左上角的事件无法监听、定制 路由导航单一,只能够返回上一页,深层级页面的返回不够友好 探索 小程序自定义导航栏已开放许久>>了解一下,相信不少小伙伴已使用过这个功能,同时不少小伙伴也会发现一些坑: 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂 一探究竟 为了搞明白原理,我先去翻了官方文档,>>飞机,点过去是不是很惊喜,很意外,通篇大文尽然只有最下方的一张图片与这个问题有关,并且啥也看不清,汗汗汗… 我特意找了一张图片来 [图片] 分析上图,我得到如下信息: Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt 胶囊按钮高度为32pt, iOS和Android一致 动手分析 我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度 Android: [图片] iOS:[图片] 可以看出,iOS胶囊按钮与状态栏之间距离为:4px, Android为8px,是不是所有手机都是这种情况呢? 答案是:苹果手机确实都是4px,安卓大部分都是7和8 也会有其他的情况(可以自己打印getSystemInfo验证)如何快速便捷算出这个高度,请接着往下看 如何计算 导航栏分为状态栏和标题栏,只要能算出每台手机的导航栏高度问题就迎刃而解 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2 + 状态栏高度 注:由于胶囊按钮是原生组件,为表现一致,其单位在各种手机中都为px,所以我们自定义导航栏的单位都必需是px(切记不能用rpx),才能完美适配。 解决问题 现在我们明白了原理,可以利用胶囊按钮的位置信息和statusBarHeight高度动态计算导航栏的高度,贴一个实现此功能最重要的方法 [代码]let systemInfo = wx.getSystemInfoSync(); let rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null; //胶囊按钮位置信息 wx.getMenuButtonBoundingClientRect(); let navBarHeight = (function() { //导航栏高度 let gap = rect.top - systemInfo.statusBarHeight; //动态计算每台手机状态栏到胶囊按钮间距 return 2 * gap + rect.height; })(); [代码] gap信息就是不同的手机其状态栏到胶囊按钮间距,具体更多代码实现和使用demo请移步下方代码仓库,代码中还会有输入框文字跳动解决办法,安卓手机输入框文字飞出解决办法,左侧按钮边框太粗解决办法等等 胶囊信息报错和获取不到 问题就在于 getMenuButtonBoundingClientRect 这个方法,在某些机子和环境下会报错或者获取不到,对于此种情况完美可以模拟一个胶囊位置出来 [代码]try { rect = Taro.getMenuButtonBoundingClientRect ? Taro.getMenuButtonBoundingClientRect() : null; if (rect === null) { throw 'getMenuButtonBoundingClientRect error'; } //取值为0的情况 if (!rect.width) { throw 'getMenuButtonBoundingClientRect error'; } } catch (error) { let gap = ''; //胶囊按钮上下间距 使导航内容居中 let width = 96; //胶囊的宽度,android大部分96,ios为88 if (systemInfo.platform === 'android') { gap = 8; width = 96; } else if (systemInfo.platform === 'devtools') { if (ios) { gap = 5.5; //开发工具中ios手机 } else { gap = 7.5; //开发工具中android和其他手机 } } else { gap = 4; width = 88; } if (!systemInfo.statusBarHeight) { //开启wifi的情况下修复statusBarHeight值获取不到 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20; } rect = { //获取不到胶囊信息就自定义重置一个 bottom: systemInfo.statusBarHeight + gap + 32, height: 32, left: systemInfo.windowWidth - width - 10, right: systemInfo.windowWidth - 10, top: systemInfo.statusBarHeight + gap, width: width }; console.log('error', error); console.log('rect', rect); } [代码] 以上代码主要是借鉴了拼多多的默认值写法,android 机子中 gap 值大部分为 8,ios 都为 4,开发工具中 ios 为 5.5,android 为 7.5,这样处理之后自己模拟一个胶囊按钮的位置,这样在获取不到胶囊信息的情况下,可保证绝大多数机子完美显示导航头 吐槽 这么重要的问题,官方尽然没有提供解决方案…竟然提供了一张看不清的图片??? 网上有很多ios设置44,android设置48,还有根据不同的手机型号设置不同高度,通过长时间的开发和尝试,本人发现以上方案并不完美,并且bug很多 代码库 Taro组件gitHub地址详细用法请参考README 原生组件npm构建版本gitHub地址详细用法请参考README 原生组件简易版gitHub地址详细用法请参考README 由于本人精力有限,目前只计划发布维护好这2种组件,其他组件请自行修改代码,有问题请联系 备注 上方2种组件在最下方30多款手机测试情况表现良好 iPhone手机打电话和开热点导致导航栏样式错乱,问题已经解决啦,请去demo里测试,这里特别感谢moments网友提出的问题 本文章并无任何商业性质,如有侵权请联系本人修改或删除 文章少量部分内容是本人查询搜集而来 如有问题可以下方留言讨论,微信zhijunxh 比较 斗鱼: [图片] 虎牙: [图片] 微博: [图片] 酷狗: [图片] 知乎: [图片] [图片] 知乎是这里边做的最好的,但是我个人认为有几个可以优化的小问题 打电话或者开启热点导致样式错落,这也是大部门小程序的问题 导航栏下边距太小,看起来不舒服 搜索框距离2侧按钮组距离不对等 自定义返回和home按钮中的竖线颜色重了,并且感觉太粗 如果您看到了此篇文章,请赶快修改自己的代码,并运用在实践中吧 扫码体验我的小程序: [图片] 创作不易,如果对你有帮助,请移步Taro组件gitHub原生组件gitHub给个星星 star✨✨ 谢谢 测试信息 手机型号 胶囊位置信息 statusBarHeight 测试情况 iPhoneX 80 32 281 369 48 88 44 通过 iPhone8 plus 56 32 320 408 24 88 20 通过 iphone7 56 32 281 368 24 87 20 通过 iPhone6 plus 56 32 320 408 24 88 20 通过 iPhone6 56 32 281 368 24 87 20 通过 HUAWEI SLA-AL00 64 32 254 350 32 96 24 通过 HUAWEI VTR-AL00 64 32 254 350 32 96 24 通过 HUAWEI EVA-AL00 64 32 254 350 32 96 24 通过 HUAWEI EML-AL00 68 32 254 350 36 96 29 通过 HUAWEI VOG-AL00 65 32 254 350 33 96 25 通过 HUAWEI ATU-TL10 64 32 254 350 32 96 24 通过 HUAWEI SMARTISAN OS105 64 32 326 422 32 96 24 通过 XIAOMI MI6 59 28 265 352 31 87 23 通过 XIAOMI MI4LTE 60 32 254 350 28 96 20 通过 XIAOMI MIX3 74 32 287 383 42 96 35 通过 REDMI NOTE3 64 32 254 350 32 96 24 通过 REDMI NOTE4 64 32 254 350 32 96 24 通过 REDMI NOTE3 55 28 255 351 27 96 20 通过 REDMI 5plus 67 32 287 383 35 96 28 通过 MEIZU M571C 65 32 254 350 33 96 25 通过 MEIZU M6 NOTE 62 32 254 350 30 96 22 通过 MEIZU MX4 PRO 62 32 278 374 30 96 22 通过 OPPO A33 65 32 254 350 33 96 26 通过 OPPO R11 58 32 254 350 26 96 18 通过 VIVO Y55 64 32 254 350 32 96 24 通过 HONOR BLN-AL20 64 32 254 350 32 96 24 通过 HONOR NEM-AL10 59 28 265 352 31 87 24 通过 HONOR BND-AL10 64 32 254 350 32 96 24 通过 HONOR duk-al20 64 32 254 350 32 96 24 通过 SAMSUNG SM-G9550 64 32 305 401 32 96 24 通过 360 1801-A01 64 32 254 350 32 96 24 通过
2019-11-17 - 【类知乎小房子】自定义返回键 自定义标题栏 自定义主页按钮 及参数计算
自定义顶部标题和左上角按钮方法解析及实践 前言 之前有兄台发过设置custom的方法 但是没有具体的实现方法 以至于很多不了解小程序的开发者不能循序渐进的理解制作自定义标题的方法 在这里详细总结了计算各参数的方法 我也写了一个自定义标题组件 只需要引用 直接在页面中调用即可 但因为掺杂了业务代码 需要整理过后会放出来 具体方法 首先在app.json中 将window.navigateionStyle 设置为custom [图片] 使用 wx.getSystemInfoSync 获取系统的属性 其中有顶部状态栏的高度 使用 wx.getMenuButtonBoundingClientRect 获取右上角胶囊菜单的相关属性 包括胶囊菜单的高度、相距上下左右屏幕的绝对位置 [图片] 如上图 我们需要获取四个参数 来确定整个标题栏的各项参数和左侧自定义胶囊的位置 获取顶部状态栏高度sys.statusBarHeight 具体代码 [代码]var sys= wx.getSystemInfoSync() var menu = wx.getMenuButtonBoundingClientRect() var statusHeight = menu.statusBarHeight var titleHeight = menu.height var titleRowWidth = sys.right - menu.right var titleColumnHeight = menu.top - menu.statusBarHeight [代码] 注意 小程序原生组件会遮挡自定义头部组件 如 canvas组件 input textarea的提示信息placeholder 该问题可以使用cover-view将头部定义为原生组件 设置层级解决 20191125后续更新 wx.getMenuButtonBoundingClientRect()返回undefined的情况 wx.getMenuButtonBoundingClientRect()在安卓和IOS端均会出现获取不到值的情况(返回undefined) 官方给出的答案是已经修复了该问题 但实际测试还是会出现类似问题 该问题与 平台 和 微信基础库 (随微信版本更新)无关 导致我们无法获取胶囊按钮的属性 进而无法计算header的高度 该问题极难复现 我在自己的真机上遇到过2次 在我的应用中出现概率不到1% 应对方法1: 官方建议延迟100MS 或 在返回undefined的情况下 重新获取一次 应对方法2: 判断平台 给与预估的默认值 IOS端和不同安卓端 IOS各机型的高度为44px 安卓端我测试最多的情况是48px 但安卓端实际情况需要具体测试 做进一步兼容 代码如下 [图片] 这里wx.getMenuButtonBoundingClientRect()方法在低版本微信中是不能用的 而且低版本的微信中不能使用wx.canIUse方法判断该方法是否存在 因此用捕获错误的方式兼容 在menu的属性返回undefined时 用我们预估的值去兼容 另外github.com有一个通过手机型号 返回手机各项参数的库 其中一项就是头部状态栏的高度 如果你想更准确的适配更多机型 可以使用这个库 无论哪种方法都不是最优的解决方案 大家酌情按照场景进行适配
2021-03-03 - UNI-APP使用云开发跨全端开发实战讲解
UNI-APP 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。 本文为大家讲解如何采用云开发官方JS-SDK,接入云开发后端服务并支持UNI-APP全部端(不止于微信小程序) JS-SDK和UNI-APP适配器1.JS-SDK和适配器云开发官方提供的@cloudbase/js-sdk,主要用来做常规WEB、H5等应用(浏览器运行)的云开发资源调用,也是目前最为完善的客户端SDK。 目前市面上大部分的轻应用、小程序包括移动应用APP都是采用JS来作为开发语言的,所以我们可以对TA进行轻微改造,就可以轻松使用在各种平台中。 但是单独改造SDK包会有些许风险,比如在原SDK包升级时需要重新构造,就造成了无穷无尽的麻烦,改造成本相当大。 官方的产品小哥哥深知这种不适和痛苦,所以在@cloudbase/js-sdk 中提供一套完整的适配扩展方案,遵循此方案规范可开发对应平台的适配器,然后搭配 @cloudbase/js-sdk 和适配器实现平台的兼容性。 不了解的小伙伴肯定会有些茫然,我来用浅显的语言解释一下,就是@cloudbase/js-sdk 将底层的网络请求以及相关基础需求以接口的形式暴露出来,我们按照平台的特殊API来补充这些接口,sdk就可以根据这些补充的接口,无障碍的运行在平台中了。 如果我们想在UNI-APP中使用@cloudbase/js-sdk ,底层网络请求你需要来补充,因为sdk原本是适应浏览器的,TA不知道UNI-APP怎么对外发请求,所以你需要将uni.request 方法补充到TA暴露的接口中。补充完毕后,@cloudbase/js-sdk 就可以在UNI-APP中活泼的运行了。 我们将所有的uni方法全部补充到JS-SDK暴漏的接口中去,就形成了一个完整的适配器,我们将其成为uni-app适配器。 2.UNI-APP适配器UNI-APP的整体接口都是公开透明的,我们在开发UNI-APP时也都遵照同一套接口标准。所以小编已经将uni-app适配器制作完毕,大家只需要在使用时接入适配器就可以了。 我们在项目目录main.js中引入云开发JS-SDK,然后接入我们的UNI-APP适配器即可。 import cloudbase from '@cloudbase/js-sdk' import adapter from 'uni-app/adapter.js' cloudbase.useAdapters(adapter); cloudbase.init({ env: '',//云开发环境ID appSign: '',//凭证描述 appSecret: { appAccessKeyId: 1,//凭证版本 appAccessKey: ''//凭证 } }) 移动应用登录凭证云开发SDK在使用过程中,向云开发服务系统发送的请求都会需要验证请求来源的合法性。 我们常规 Web 通过验证安全域名,而由于 UNI-APP 并没有域名的概念,所以需要借助安全应用凭证区分请求来源是否合法。 登录云开发 CloudBase 控制台,在安全配置页面中的移动应用安全来源一栏:[图片] 点击“添加应用”按钮,输入应用标识:uni-app(也可以输入其他有标志性的名称),需要注意应用标识必须是能够标记应用唯一性的信息,比如微信小程序的 appId 、移动应用的包名等。[图片] 添加成功后会创建一个安全应用的信息,如下图所示:[图片] 我们需要保存一下上图中的版本(示例为1)、应用标识(示例为uni-app)、以及点击获取到的凭证(示例为demosecret) 在项目目录中,我们将main.js中的init部分补全 import cloudbase from '@cloudbase/js-sdk' import adapter from 'uni-app/adapter.js' cloudbase.useAdapters(adapter); cloudbase.init({ env: 'envid',//云开发环境ID,保证与你操作登录凭证一致 appSign: 'uni-app',//凭证描述 appSecret: { appAccessKeyId: 1,//凭证版本 appAccessKey: 'demosecret'//凭证 } }) 如此,你就可以正常的进行云开发的登录使用了。 需要注意以下4点: 你需要设置uni-app的各端安全域名为:request:tcb-api.tencentcloudapi.com、uploadFile:cos.ap-shanghai.myqcloud.com、download:按不同地域配置使用此种方法接入云开发是全端支持,并不会享有微信小程序生态的一些便利,微信小程序开发还是需要依赖正常请求调用过程(将云开发作为服务器来对待),但你可以判断wx来使用wx.cloud来兼容。使用云开发的匿名登录时,受各端实际情况影响,可能不能作为常久唯一登录id,需要根据自身业务建立统一账户体系,具体可使用自定义登录来进行。UNI-APP支持WEB网页端上线时,需要将网页域名配置到云开发安全域名中(防止WEB下载文件导致跨域)示例代码详解示例项目中已经基本构建了uni-app使用云开发的各种流程代码。 在页面中进行匿名登录: // index.vue import cloudbase from '@cloudbase/js-sdk' export default { data() { return { title: '登录中' } }, onLoad() { cloudbase.auth().anonymousAuthProvider().signIn().then(res => { this.title = '匿名登录成功' }).catch(err => { console.error(err) }) } } 调用云函数并收到返回结果: import cloudbase from '@cloudbase/js-sdk' export default { methods: { call: function() { cloudbase.callFunction({ name: "test", data: { a: 1 } }).then((res) => { console.log(res) }); } } } 操作数据库: import cloudbase from '@cloudbase/js-sdk' export default { methods: { database: function() { cloudbase.database().collection('test').get().then(res => { console.log(res) }) } } } 实时数据库监听: import cloudbase from '@cloudbase/js-sdk' export default { methods: { socket: function() { let ref = cloudbase.database().collection('test').where({}).watch({ onChange: (snapshot) => { console.log("收到snapshot", snapshot); }, onError: (error) => { console.log("收到error", error); } }); } } } 上传文件(框架限制,WEB端无法操作): import cloudbase from '@cloudbase/js-sdk' export default { methods: { upload: function() { uni.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album'], success: function(res) { console.log(res.tempFilePaths[0]) cloudbase.uploadFile({ cloudPath: "test-admin.png", filePath: res.tempFilePaths[0], onUploadProgress: function(progressEvent) { console.log(progressEvent); var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); } }).then((result) => { console.log(result) }); } }); } } } 下载文件(需要注意地域域名,配置安全域名): import cloudbase from '@cloudbase/js-sdk' export default { methods: { download: function() { cloudbase.downloadFile({ fileID: "cloud://demo-env-1293829/test-admin.png" }).then((res) => { console.log(res) }); } } } 部署步骤将项目下载后使用HBuilderX打开。按照获取移动安全凭证的指引,填写至mian.js相应处。打开目录命令行,npm i执行安装依赖。打开云开发控制台,开启匿名登录。新建一个默认的云函数,名称为test(逻辑内容直接返回event即可)新建一个数据库,名称为test(随便添加几个记录,设置权限为所有人可读)调整项目pages/index/index.vue中,21行代码,在登录成功后调用相应函数。以下是WEB端运行时展示:[图片] 关于uni-app适配器在util/adapter中,只进行了简单的测试,保证可用性,后续请关注官网获取最新适配器依赖此方法有别与uniCloud,是直接使用uni请求底层,依赖官方JS-SDK进行云开发服务的交互处理,在使用时注意区别。项目地址:https://github.com/AceZCY/UNI-for-CloudBase
2020-12-08 - uni-app对微信小程序云函数的适配
版权说明 本文首发于指尖魔法屋>uni-app对微信小程序云函数的适配. 转载请附上原地址 引言 熟悉uni-app的人应该都知道,uni-app并未对微信小程序云函数(本文统称云函数)进行相应的适配。但是,如果我们在某些业务场景的下需要使用云函数呢?我们知道,云函数可以复制到微信开发者工具,这样的话我们不得不每次编译一次就手动复制一次,不得不说麻烦至极。本文就问题做出以下解决方案。 本文环境 Hbuilder X [图片] 微信开发者工具 [图片] 创建云函数目录 首先,我们需要在uni-app项目文件夹下,创建一个云函数目录,路径随意,我这里是[代码]functions[代码]。然后先随便在里面放一些文件,这里以[代码]new_file.css[代码]为例。 修改[代码]manifest.json[代码] 在uni-app根目录下,修改[代码]manifest.json[代码]中的微信小程序项,结构如下 [代码]"mp-weixin" : { /* 小程序特有相关 */ "appid" : "wxd7de467f6e6cf741", "cloudfunctionRoot": "./functions/", // 这一行就是标记云函数目录的字段 "setting" : { "urlCheck" : false }, "usingComponents" : true } [代码] 编写[代码]vue.config.js[代码] 我们在项目根目录创建[代码]vue.config.js[代码]文件 写入以下内容(如路径不一样请做相应适配) [代码]const path = require('path') const CopyWebpackPlugin = require('copy-webpack-plugin') module.exports = { configureWebpack: { plugins: [ new CopyWebpackPlugin([ { from: path.join(__dirname, 'functions'), to: path.join(__dirname, 'unpackage/dist', process.env.NODE_ENV === 'production' ? 'build' : 'dev', process.env.UNI_PLATFORM, 'functions') } ]) ] } } [代码] 编译运行 发现提示如下内容 [图片] 说明未安装[代码]copy-webpack-plugin[代码]插件,我们手动安装一下。 [图片] 然后编译运行,发现微信开发者工具里面出现以下内容。 [图片] 截止目前,已打通Hbuilder X到微信开发者工具的自动复制,即已解决本文的核心内容。以下为进一步测试。 创建云函数 我们在云函数根目录上右键,在右键菜单中,可以选择创建一个新的 Node.js 云函数,我们将该云函数命名为check。开发者工具在本地创建出云函数目录和入口 index.js 文件,同时在线上环境中创建出对应的云函数。创建成功后,工具会提示是否立即本地安装依赖,确定后工具会自动安装 wx-server-sdk。我们会看到以下内容。 创建好后将其同步复制到uni-app项目,即可为以后自动同步行方便,又可避免在输出文件夹中云函数的意外丢失。至此,相关文件编写工作转至[代码]Hbuilder X[代码],云函数上传部署依旧在微信开发者工具。 [图片] 编写云函数 默认的云函数只是一个返回用户基本数据的内容,我们将其修改至满足我们的业务需求,以内容安全云调用为例。 在云函数文件中写入以下内容 [代码]// 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() // 云函数入口函数 exports.main = async(event, context) => { try { console.log('待检测文本:' + event.content); let result = await cloud.openapi.security.msgSecCheck({ content: event.content }) console.log('result:' + JSON.stringify(result)); if (result && result.errCode.toString() === '87014') { return { code: 300, msg: '内容含有违法违规内容', data: result } } else { return { code: 200, msg: 'ok', data: result } } } catch (err) { if (err.errCode.toString() === '87014') { return { code: 300, msg: '内容含有违法违规内容', data: err } } return { code: 400, msg: '调用security接口异常', data: err } } } [代码] 权限申明 在函数目录下,创建一个[代码]config.json[代码],文档说会自动创建,但是我实际操作时未自动创建。[代码]config.json[代码]内容如下。 [代码]{ "permissions": { "openapi": [ "security.msgSecCheck" ] } } [代码] 然后在函数目录右键,上传并部署。 小程序调用云函数 [代码]wx.cloud.init() wx.cloud.callFunction({ name: 'check', data: { "content": this.contents.join() } }).then(res => { console.log(res.result) if (res.result.code == 300) { uni.showModal({ title: "温馨提示", content: "你所输入的内容可能含有违法违规内容,不支持进行下一步操作" }) return } else { ... // 你要进行的操作 } }) [代码] 效果展示 [图片]
2019-11-23 - 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 Canvas 功能生成一张带有小程序码的图片,然后引导用户下载图片到本地后再分享到朋友圈。相信大家在绘制分享图中应该踩到 Canvas 的各种(坑)彩dan了吧~ 这里首先推荐一个开源的组件:painter(通过该组件目前我们已经成功在支付宝小程序上也应用上了分享图功能) 咱们不多说,直接上手就是干。 [图片] 首先我们新增一个自定义组件,在该组件的json中引入painter [代码]{ "component": true, "usingComponents": { "painter": "/painter/painter" } } [代码] 然后组件的WXML (代码片段在最后) [代码]// 将该组件定位在屏幕之外,用户查看不到。 <painter style="position: absolute; top: -9999rpx;" palette="{{imgDraw}}" bind:imgOK="onImgOK" /> [代码] 重点来了 JS (代码片段在最后) [代码]Component({ properties: { // 是否开始绘图 isCanDraw: { type: Boolean, value: false, observer(newVal) { newVal && this.handleStartDrawImg() } }, // 用户头像昵称信息 userInfo: { type: Object, value: { avatarUrl: '', nickName: '' } } }, data: { imgDraw: {}, // 绘制图片的大对象 sharePath: '' // 生成的分享图 }, methods: { handleStartDrawImg() { wx.showLoading({ title: '生成中' }) this.setData({ imgDraw: { width: '750rpx', height: '1334rpx', background: 'https://qiniu-image.qtshe.com/20190506share-bg.png', views: [ { type: 'image', url: 'https://qiniu-image.qtshe.com/1560248372315_467.jpg', css: { top: '32rpx', left: '30rpx', right: '32rpx', width: '688rpx', height: '420rpx', borderRadius: '16rpx' }, }, { type: 'image', url: this.data.userInfo.avatarUrl || 'https://qiniu-image.qtshe.com/default-avatar20170707.png', css: { top: '404rpx', left: '328rpx', width: '96rpx', height: '96rpx', borderWidth: '6rpx', borderColor: '#FFF', borderRadius: '96rpx' } }, { type: 'text', text: this.data.userInfo.nickName || '青团子', css: { top: '532rpx', fontSize: '28rpx', left: '375rpx', align: 'center', color: '#3c3c3c' } }, { type: 'text', text: `邀请您参与助力活动`, css: { top: '576rpx', left: '375rpx', align: 'center', fontSize: '28rpx', color: '#3c3c3c' } }, { type: 'text', text: `宇宙最萌蓝牙耳机测评员`, css: { top: '644rpx', left: '375rpx', maxLines: 1, align: 'center', fontWeight: 'bold', fontSize: '44rpx', color: '#3c3c3c' } }, { type: 'image', url: 'https://qiniu-image.qtshe.com/20190605index.jpg', css: { top: '834rpx', left: '470rpx', width: '200rpx', height: '200rpx' } } ] } }) }, onImgErr(e) { wx.hideLoading() wx.showToast({ title: '生成分享图失败,请刷新页面重试' }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') }, onImgOK(e) { wx.hideLoading() // 展示分享图 wx.showShareImageMenu({ path: e.detail.path, fail: err => { console.log(err) } }) //通知外部绘制完成,重置isCanDraw为false this.triggerEvent('initData') } } }) [代码] 那么我们该如何引用呢? 首先json里引用我们封装好的组件share-box [代码]{ "usingComponents": { "share-box": "/components/shareBox/index" } } [代码] 以下示例为获取用户头像昵称后再生成图。 [代码]<button class="intro" bindtap="getUserInfo">点我生成分享图</button> <share-box isCanDraw="{{isCanDraw}}" userInfo="{{userInfo}}" bind:initData="handleClose" /> [代码] 调用的地方: [代码]const app = getApp() Page({ data: { isCanDraw: false }, // 组件内部关掉或者绘制完成需重置状态 handleClose() { this.setData({ isCanDraw: !this.data.isCanDraw }) }, getUserInfo(e) { wx.getUserProfile({ desc: "获取您的头像昵称信息", success: res => { const { userInfo = {} } = res this.setData({ userInfo, isCanDraw: true // 开始绘制海报图 }) }, fail: err => { console.log(err) } }) } }) [代码] 最后绘制分享图的自定义组件就完成啦~效果图如下: [图片] tips: 文字居中实现可以看下代码片段 文字换行实现(maxLines)只需要设置宽度,maxLines如果设置为1,那么超出一行将会展示为省略号 代码片段:https://developers.weixin.qq.com/s/J38pKsmK7Qw5 附上painter可视化编辑代码工具:点我直达,因为涉及网络图片,代码片段设置不了downloadFile合法域名,建议真机开启调试模式,开发者工具 详情里开启不校验合法域名进行代码片段的运行查看。 最后看下面大家评论问的较多的问题:downLoadFile合法域名在小程序后台 开发>开发设置里配置,域名为你图片的域名前缀 比如我文章里的图https://qiniu-image.qtshe.com/20190605index.jpg。配置域名时填写https://qiniu-image.qtshe.com即可。如果你图片cdn地址为https://aaa.com/xxx.png, 那你就配置https://aaa.com即可。
2022-01-20 - CSV/Excel文件一键转成云开发数据库的json文件
使用Excel导入云开发的数据库,数据量比较大的时候会出现一些问题,我们可以将Excel转成CSV文件,让CSV的第一行为字段名(要是英文哦),然后使用以下代码将CSV文件转成json文件。 第一步,安装Nodejs环境,然后使用vscode新建一个 csv2json.js 的文件,将下面的代码拷贝进来; 第二步,在vscode的资源管理器里右键csv2json.js,在终端中打开,然后输入命令 npm install csvtojson replace-in-file 第三步,把要转化的csv文件放在同一个目录,这里换成你的文件即可,也就是下面的china.csv换成你的csv文件; 第四步,后面的代码都不用管,然后打开vscode终端,输入 node csv2json.js 执行,就会生成两个文件,一个是json文件,一个是可以导入到云开发数据库的data.json //用vscode打开文件之后,npm install csvtojson replace-in-file const csv=require('csvtojson') const replace = require('replace-in-file'); const fs = require('fs') const csvFilePath='china.csv' //把要转化的csv文件放在同一个目录,这里换成你的文件即可 //后面的代码都不用管,然后打开vscode终端,就会生成两个文件,一个是json文件,一个是可以导入到 csv() .fromFile(csvFilePath) .then((jsonObj)=>{ // console.log(jsonObj); var jsonContent = JSON.stringify(jsonObj); console.log(jsonContent); fs.writeFile("output.json", jsonContent, 'utf8', function (err) { if (err) { console.log("保存json文件出错."); return console.log(err); } console.log("JSON文件已经被保存为output.json."); fs.readFile('output.json', 'utf8', function (err,data) { if (err) { return console.log(err); } var result = data.replace(/},/g, '}\n').replace(/\[/,'').replace(/\]/,'') fs.writeFile('data.json', result, 'utf8', function (err) { if (err) return console.log(err); }); }); }); })
2019-12-25