- 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 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 - 数组再分的实现
实现数组再分 开发的时候遇到了一个比较少见的关于数组的操作,如何根据数组中的某个键的属性值是否相同,重新整合数组中的值,如同代码示例中的根据数组的name属性,将name相同的数组元素重新组合在一起。最初的设想是for循环找出每个元素之后,内嵌一个for循环进行比对,找出相应数据存放,结果是数组中的数据重复打印。于是从网上搜索并解决问题,以下便是代码示例。 代码示例 [代码]//实验代码 未分组变量 arrayDemo: [{ "name": "z", "age": 15, "high": 10, "phone": 12345678911 }, { "name": "q", "age": 15, "high": 10, "phone": 12345678910 }, { "name": "w", "age": 15, "high": 10, "phone": 12345678912 }, { "name": "e", "age": 15, "high": 10, "phone": 12345678913 }, { "name": "r", "age": 15, "high": 10, "phone": 12345678914 }, { "name": "z", "age": 15, "high": 10, "phone": 12345678915 }, { "name": "z", "age": 15, "high": 10, "phone": 12345678916 }, { "name": "f", "age": 15, "high": 10, "phone": 12345678917 } ] //调用数组排列方法 this.arrayGroup(arrayDemo); /** * 数组分组 */ arrayGroup: function(array) { var groups = []; //存放新数组 for (var i = 0; i < array.length; i++) { //遍历数组每一项 // 读取每条数据的名称 取出 分类的条件 var groupName = array[i].name; var groupValue = { // 符合分类条件的属性值组合成对象放入新数组中value属性中 'age': array[i].age, 'high': array[i].high, 'phone': array[i].phone } var groupItem = { //新数组中存放的对象 'name': '', value: [] } groupItem.name = groupName; groupItem.value.push(groupValue); if (i == 0) { //设置为基准值进行对比 groups.push(groupItem); } else { //遍历剩余数组项 var index = -1; //第二层循环找到属性值相同的数组成员并且放入新数组中 for (var k = 0; k < groups.length; k++) { if (groupName == groups[k].name) { index = k; break; } } if (index == -1) { //没有找到 groups.push(groupItem); } else { groups[k].value.push(groupValue); //将属性值存放到新数组中 } } } console.log('groups', groups); } [代码] 结果示例 [图片] 解决这个问题之后,鉴于花费在这个问题上的时间,重新搜集了有关数组的操作方法记录下来,以减少下次花费时间。 数组相关方法扩展 filter() filter()方法创建一个新数组, filter为数组中的每个元素调用一次 callback 函数,并利用调用callback函数返回true或等价于true的值的元素创建一个新数组。 [代码]filter语法: var newArray = arr.filter(callback(element[, index[, array]])[, thisArg]) /** * filterdemo 过滤掉所有小于10的数组项 */ filterDemo: function() { var filterArray = [12, 14, 8, 9, 100]; var filterResult = filterArray.filter(function(item) { if (item > 10) { return true; } }); console.log('filterResult', filterResult) } [代码] [图片] map() map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。 [代码]//map语法: var new_array = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg]) /** * map方法示例 所有数组成员乘以5 */ mapDemo: function() { var mapArray = [1, 2, 3, 4, 5]; var mapResult = mapArray.map(function(item) { return item * 5 }) console.log('mapResult', mapResult); } [代码] [图片] foreach() foreach()方法对数组中的每个元素执行一次提供的函数。 [代码]语法: array.forEach(function(currentValue, index, arr), thisValue) /** * forEach 代码示例 */ forEachDemo: function() { var arr = [1, 5, 8, 9] arr.forEach(function(item) { console.log('item', item) }) } /** * forEachDemo 无法使用break跳出循环 */ forEachDemo: function() { var arr = [1, 5, 8, 9] arr.forEach(function(item) { if (item == 1) { break } console.log('item', item) }) } /** * forEach 被调用的时候,不会直接改变调用它的对象,但是对象可能会被callback改变原数组为 var words = ['one', 'two', 'three', 'four'];调用foreach后 原数组被改变 */ forEachDemo: function() { var words = ['one', 'two', 'three', 'four']; words.forEach(function(word) { console.log(word); if (word === 'two') { words.shift(); } }); } [代码] [图片] foreach无法使用break跳出循环 [图片] forEach 被调用的时候,不会直接改变调用它的对象,但是对象可能会被callback改变 [图片] for-in for-in常用来遍历对象,以任意顺序去遍历一个对象可枚举的属性 [代码] /** * for-in 实例 输出对象的属性 */ forInDemo: function() { var obj = { name: 'ar', color: 'yellow', day: 'sunday', number: 6, age:15 } for (var key in obj) { console.log(obj[key]) } } [代码] [图片] 在合适的场景下选用合适的数组操作方法,可以使得复杂的代码变得更加的易读和简练,更容易让人理解。
2019-06-30