- 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 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 - 富文本editor怎么实现首行缩进?
可以通过 this.editCtx.format('textIndent', '2em') 的方式实现
2019-09-16 - 微信小程序开发之富文本编辑器
微信小程序开发之富文本编辑器 一年多去了,还有这么多人关注这个编辑器,那就索性把这个组件放上去,各位直接引用吧!如果您感觉很好用,很实用,也请大家给点一个赞!前言:富文本在Web开发上的地位大家可想而知,很多地方都需要用到富文本编辑器,比如开发类似新闻管理小程序、商品简介等。微信小程序在基础库2.7.0之后上线了一个editor富文本编辑器组件,这个组件是本次要讲的内容。组件相关的内容大家可以去看官方文档的内容,这里我们就不进行讲解。而我们要做的就是将官方的富文本组件进行二次开发达到一个好用而又实用的地步:https://developers.weixin.qq.com/miniprogram/dev/component/editor.html 先看效果图(以下只是一个基础的实用): [图片] 代码方案: 1.引入组件(组件的下载地址链接:https://pan.baidu.com/s/15D3ejvs30BZPwn94RgyNmw 提取码:hg66) 2、在你需要的使用的页面的JSON文件中引入该组件,引入方法如下: "usingComponents": { "hg-editor":"../../../components/hg-editor/hg-editor(根据自己的放置位置修改,其中/hg-editor/hg-editor是固定的)" } 3、在wxml文件中使用,使用案例如下,可选参数有四个 参数详解: [图片] showTabBar :是否显示工具栏(默认为true,显示,如果改为false则为不显示)placeholder:文本框提示文字,默认为“请输入相关内容”name:是编辑器的name属性,默认为空uploadImageURL:图片的上传地址,默认为空使用属性案例测试: bind:input可以获得用户输入的内容: onInputtingDesc: function (e) { let html = e.detail.html; //相关的html代码 let originText = e.detail.text; //text,不含有任何的html标签 this.setData({ ['topic.text']: html, ['topic.originText']: originText }); } 使用案例: [图片][图片][图片] 您的想法有多大,组件拓展的无限可能就有多大,欢迎各位留言,欢迎各位使用! 好用,就来收藏一下,更新不易,点个赞!
2022-04-22 - scroll-view的bindscrolltolower触发加载更多后,列表自动回滚到顶部?
第一次碰到,之前的项目还好好的,bindscrolltolower触发加载更多,然后ajax拿到的数据和之前已有的数据合并(追加到原数据后),页面会有一个刷新的情况出现,列表会自动回滚到顶部,而不是我刚才拖拽到的位置。 有谁知道咋解决么
2021-03-19 - [打怪升级]小程序评论回复和发贴组件实战(一)
[图片] 在学习成长的过程中,常常会遇到一些自己从未接触的事物,这就好比是打怪升级,每次打倒一只怪,都会获得经验,让自己进步强大。特别是我们这些做技术的,逆水行舟不进则退。下面分享下小程序开发中的打怪升级经历~ [图片] 先来看下实际效果图,小程序开发中有时会要做一些的功能复杂的组件,比如评论回复和发帖功能等,这次主要讲的是关于评论模块的一些思路和实战中的经验,希望能抛砖引玉,给大家一些启发,一同成长~ [代码片段]评论回复组件实战demo demo的微信路径: https://developers.weixin.qq.com/s/oHs5cMma7N9W demo的ID:oHs5cMma7N9W 如果你装了IDE工具,可以直接访问上面的demo路径 通过代码片段将demo的ID输入进去也可添加: [图片] [图片] [图片] 根据这个demo.gif,本人做了一个简单的流程图,帮助大家理解。下面罗列一些开发中需要“打的怪”: 1、组件目录结构 [代码]├─components ---小程序自定义组件 │ ├─plugins --- (重点)可独立运行的大型模块,可以打包成plugins │ │ ├─comment ---评论模块 │ │ │ │ index.js │ │ │ │ index.json │ │ │ │ index.wxml │ │ │ │ index.wxss │ │ │ │ services.js ---(重点)用来处理和清洗数据的service.js,配套模板和插件 │ └─submit ---评论模块子模块:提交评论 index.js index.json index.wxml index.wxss [代码] 为什么要单独做个评论页面页面(submit)? 因为如果是当前页面最下面input输入的形式,会出现一些兼容问题,比如: 不同手机的虚拟键盘高度不同,不好绝对定位和完全适配 弹窗输入框过小输入不方便,如果是大的textare时,容易误触下面评论的交。 注:目录结构,仅供参考。 2、NODE端API接口返回结构和页面结构 [代码]//node:API接口返回 { "data": { "commentTotal": 40, "comments": [ { "contentText": "喜欢就关注我", //评论内容 "createTime": 1560158823647, //评论时间 "displayName": "智酷方程式", //用户名 "headPortrait": "https://blz.nosdn.127.net/1/weixin/zxts.jpg", //用户头像 "id": "46e0fb0066666666", //评论ID 用于回复和举报 "likeTotal": 2, //点赞数 "replyContents": [ //回复评论 { "contentText": "@智酷方程式 喜欢就回复我", //回复评论内容 "createTime": 1560158986524, //回复时间 "displayName": "神秘的前端开发", //回复的用户名 "headPortrait": "https://blz.nosdn.127.net/1/2018cosplay/fourth/tesss.jpg", //回复的用户头像 "id": "46e0fb00111111111", //回复评论的ID "likeTotal": 2, //回复评论的点赞数 "replyContents": [], //回复的回复 盖楼 "replyId": "46e0fb001ec222222222", //回复评论的独立ID,用于统计 }, { "contentText": "@智酷方程式: 威武,学习学习", "createTime": 1560407232814, "displayName": "神秘的前端开发", "headPortrait": "https://blz.nosdn.127.net/1/2018cosplay/fourth/tesss.jpg", "id": "46e0fb00111111111", "likeTotal": 0, "replyContents": [], "replyId": "46e0fb001ec222222222", } ], "replyId": "", "topicId": "46e0fb001ec3333333", } ], "curPage": 1, //当前页面 //通过ID 判断 当前用户点赞了 哪些评论 "likes": [ "46e0fb00111111111", "46e0fb001ec222222222", "46e0fb0066666666", ], "nextPage": null, //下一页 "pageSize": 20, //一页总共多少评论 "total": 7, //总共多少页面 }, "msg": "success", "status": "success" } [代码] [代码]<!-- HTML 部分 --> <block wx:if="{{commentList.length>0}}"> <!-- 评论模块 --> <block wx:for="{{commentList}}" wx:for-item="item" wx:for-index="index" wx:key="idx"> <view class="commentItem" catchtap="_goToReply" data-contentid="{{item.id}}" data-replyid="{{item.id}}" data-battle-tag="{{item.displayName}}"> <view class="titleWrap"> <image class="logo" src="{{item.headPortrait||'默认图'}}"></image> <view class="authorWrap"> <view class="author">{{item.displayName}}</view> <view class="time">{{item.createTime}}</view> </view> <view class="starWrap" catchtap="_clickLike" data-index="{{index}}" data-like="{{item.like}}" data-contentid="{{item.id}}" data-topicid="{{item.topicId}}"> <text class="count">{{item.likeTotal||""}}</text> <view class="workSprite icon {{item.like?'starIconHasClick':'starIcon'}}"></view> </view> </view> <view class="text"> {{item.contentText}} </view> </view> <!-- 评论的评论 --> <block wx:for="{{item.replyContents}}" wx:for-item="itemReply" wx:for-index="indexReply" wx:key="idxReply"> <view class="commentItem commentItemReply" catchtap="_goToReply" data-contentid="{{itemReply.id}}" data-replyid="{{item.id}}" data-battle-tag="{{itemReply.displayName}}"> ... 和上面类似 </view> </block> </block> <!-- 加载更多loading --> <block wx:if="{{isOver}}"> <view class="more">评论加载完成</view> </block> </block> [代码] 通过node提供一个API接口,通过用户的openId来判断是否点赞,这里提供一个参考的JSON结构。 JSON尽量做成array循环的结构方便渲染,根据ID来BAN人和管理。底部加上加载更多的效果,同时,记得做一些兼容,比如默认头像等。 3、评论中的一些微信原生交互 这里建议很多交互如果不是必须要特别定制,可以才用微信原生的组件,效果和兼容性都有保障,而且方便简单。 对评论进行回复/举报 [代码]<!-- HTML部分 通过绑定事件:_goToReply 进行交互--> <view class="commentItem" catchtap="_goToReply" data-contentid="{{item.id}}" data-replyid="{{item.id}}" data-battle-tag="{{item.displayName}}"> ... 内部省略 </view> [代码] [代码]//JS部分 微信原生wx.showActionSheet 显示操作菜单交互 _goToReply(e) { // 上面的各种授权判断省略... let self = this; wx.showActionSheet({ itemList: ['回复', '举报'], success: function (res) { if (!res.cancel) { console.log(res.tapIndex); //前往评论 if (res.tapIndex == 0) { //判断是否是 评论的评论 self._goToComment(replyid); } //举报按钮 if (res.tapIndex == 1) { //弹出框 self.setComplain(contentid); } } else { //取消选择 } }, fail(res) { console.log(res.errMsg) } }); } //当选择“举报”的时候,二次调用 wx.showActionSheet 方法 setComplain(contentid){ let complainJson = ["敏感信息", "色情淫秽", "垃圾广告", "语言辱骂", "其它"]; wx.showActionSheet({ itemList: complainJson, success: async res => { if (!res.cancel) { //选择好后,提交举报 try { let complainResult = await request.postComplainReport(complainJson[index], openid, contentid); if (complainResult.msg == "success") { //提交成功后反馈 } else { } } catch (e) { console.log(e) } } } }); } [代码] 显示操作菜单 wx.showActionSheet 方法说明 属性 类型 说明 itemList Array.<string> 按钮的文字数组,数组长度最大为 6 itemColor string 按钮的文字颜色 success function 接口调用成功的回调函数 fail function 接口调用失败的回调函数 complete function 接口调用结束的回调函数(调用成功、失败都会执行) 使用这个方法,即是主流的做法,也能很好的兼容不同机型,同时给予用户“习惯性体验”。 原生评论排序切换 [图片] [代码]<!-- picker组件 html部分--> <picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}"> <view class="picker"> 当前选择:{{array[index]}} </view> </picker> [代码] [代码]// js部分 Page({ data:{ //查看评论类型切换 array: ["最佳", "最新", "只看自己"], //选择数组中的第几个显示 index:0 }, bindPickerChange(e) { console.log('picker发送选择改变,携带值为', e.detail.value) this.setData({ index: e.detail.value }) } }) [代码] picker组件是一个从底部弹起的滚动选择器,这里我们用它来切换不同评论的排序。每次切换都可以通过 bindchange获得对应的变化,通过 e.detail.value获取用户选择的索引值。 官方文档: https://developers.weixin.qq.com/miniprogram/dev/component/picker.html 4、传参跳转写评论页 [代码]let uriData = { logo: "xxx.jpg", type: "commentReply", title: "文章:小程序评论,动态发帖开发指北\n 作者:智酷方程式", openId:"xxxxxxxxxxx", replyId:"aaaaaa" //用户回复的是哪个评论的ID }; wx.navigateTo({ url: `/components/plugins/comment/submit/index?uriData=${encodeURIComponent(JSON.stringify(uriData))}` }); [代码] 这个可以用encodeURIComponent的方式处理下参数中的中文,避免跳转发布评论页接收数据时出现乱码。 5、发表评论页 [图片] 显示和控制评论的字数 [代码]<!-- html部分 关于textarea 的配置 --> <view class='feedback-cont'> <textarea auto-focus="true" value="{{replyName}}" maxlength="200" bindinput="textareaCtrl" placeholder-style="color:#999;" placeholder="留下评论,共同学习,一起进步" /> <view class='fontNum'>{{content.length}}/200</view> </view> <view class='feedback-btn' bindtap='commentSubmit'>提交</view> [代码] [代码]// js部分 Page({ data: { //初始化评论内容,如果是回复则通过传参变成 @xxxx的形式 content: "@xxxx", }, textareaCtrl: function (e) { if (e.detail.value) { this.setData({ content: e.detail.value }) } else { this.setData({ content: "" }) } } }) [代码] textarea 在小程序中改动不大,这个标签原有的一些属性都可以继续使用,通过配置maxlength来控制字数,同时,设置auto-focus="true"可以让用户进到这个发表评论页面时自动弹出虚拟键盘和光标定位在输入的区域。 当然,也可以将发表评论和评论展示区域做在一起,这个就要考虑到要么通过“小程序API”获取键盘高度,要么将“发布评论”置顶区域显示,也是可以做的,只是相对考虑的点会多些。当时开发评论组件的时候,考虑开发时间短和用户体验,权衡后,最终决定以上方案,希望能给到大家一些参考和借鉴,在其他组件开发中触类旁通。 总结,“组件化思想”对于无论做小程序、react/VUE还是其他项目来说,减少重复开发,提高复用性都是一个非常重要的点。评论功能其实只要理清楚整体思路,做起来难度并不大,通过一些原生组件,可以大大提高开发效率,同时保证良好的兼容性。 后面一期还将分享下功能点较多的发帖组件开发。 往期回顾: [填坑手册]小程序Canvas生成海报(一) [拆弹时刻]小程序Canvas生成海报(二) [填坑手册]小程序目录结构和component组件使用心得
2021-09-13 - msgSecCheck接口检测不出任何违规信息?
调用security.msgSecCheck根本检测不出来什么信息,在测试时,输入黄色信息,接口中的errcode同样的也是返回 0 errmsg:"ok"。但是不调用你们提供的接口又不能审核通过,这是想让我们开发者怎么做啊?能给个合理的解释吗?
2020-08-10 - 小程序陌生人社交、社区之分?
我想做个分享日常动态的小程序,大概就是一些碎碎念的东西。 功能上会存在发布日常、可以点赞、评论,但是不能发起私信。 请问这样类型的小程序,算是陌生人社交嘛?还是说可以算是社区论坛?ICP证实在是一座山啊!
2019-09-29 - 什么样的功能会被归类为社交-陌生人交友/熟人交友?
小程序两次审核被以包含“社交-陌生人交友/熟人交友”服务类目的缘由拒了 但是查看文档的时候看到所谓“社交-陌生人交友/熟人交友”指“即时沟通、互动、交友类服务”,但是我们的小程序里面,并不存在即时通讯、一对一聊天或者留言箱的功能,所谓交友模块,是让用户发布自身相关信息,而后转为微信/电话/邮箱联系,应该是不属于文档里的归类。 两次审核被拒,第一次被拒说明情况后通过了;第二次(为迎国庆改了UI)多次说明还是被拒,反馈也没有回复,只是重复原本的说法。 在其它帖子下看到,判断是否是交友,通常按照是不是存在一对一聊天功能,本小程序不包含该功能,到底算不算交友?
2019-10-04