- shareEmojiToGroup 回调 success,但是没有弹出转发框,表情也没发
wx.shareEmojiToGroup({ imagePath: this.data.url, needShowEntrance: false, success() { console.log("shareEmojiToGroup success"); }, fail(err) { console.log("shareEmojiToGroup fail", err); }, compelete() { console.log("shareEmojiToGroup compelete"); }, }); 同样的代码,换成 shareEmojiToGroup 就一切正常
04-13 - 云开发的涨价幅度,大家有好的迁移方案可以讨论下?
云开发费用普遍最少涨个20倍吧 [图片]
2022-07-05 - 小程序 云开发 企业付款到零钱
终于轮到我来装一次b了 之前总是有求于各位神,现在来回馈了。 各位用小程序云开发,要实现退款、企业零钱的可以看过来。 // 云函数入口文件 const cloud = require('wx-server-sdk') cloud.init() const config = { appid: '**************', //小程序Appid,填自己的小程序id envName: '*************', // 小程序云开发环境ID mchid: '***********', //商户号,填自己的商户号 pfx: require('fs').readFileSync('./apiclient_cert.p12'),这里是下载的api证书。证书怎么下在呢?网上有 partnerKey: '123111111111111111111111111111111111111111111111111', //此处填商户密钥 notify_url: ' ', //支付回调网址,这里可以随意填一个网址 spbill_create_ip: '127.0.0.1' //不用改 }; const db = cloud.database(); const TcbRouter = require('tcb-router'); //云函数路由 const rq = require('request'); const tenpay = require('tenpay'); //支付核心模块 这里要是报错,直接搜 nps + 报错内容 // 云函数入口函数 exports.main = async (event, context) => { const wxContext = cloud.getWXContext() console.log("提现走到了函数",event) const api = tenpay.init(config); var tixian = event.tixian // 申请企业付款到用户零钱 const orderNumber= 'dlbmoney' + new Date().getTime() + Math.floor(Math.random() * 1000) const datas = { partner_trade_no: orderNumber, openid: wxContext.OPENID, amount: tixian * 100, desc: "订单说明", check_name: "NO_CHECK", //不检查实名 spbill_create_ip:"123.151.79.109" } const result = await api.transfers(datas) return { event, openid: wxContext.OPENID, appid: wxContext.APPID, unionid: wxContext.UNIONID, } }
2021-07-07 - 2019-03-21
- 如何实现快速生成朋友圈海报分享图
由于我们无法将小程序直接分享到朋友圈,但分享到朋友圈的需求又很多,业界目前的做法是利用小程序的 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 - 小技巧!CSS 整块文本溢出省略特性探究
今天的文章很有意思,讲一讲整块文本溢出省略打点的一些有意思的细节。 文本超长打点 我们都知道,到今天(2020/03/06),CSS 提供了两种方式便于我们进行文本超长的打点省略。 感兴趣的小伙伴点击链接,了解详情~ http://github.crmeb.net/u/yi 对于单行文本,使用单行省略: { width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } [图片] 而对于多行文本的超长省略,使用 [代码]-webkit-line-clamp[代码] 相关属性,兼容性也已经非常好了: { width: 200px; overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } [图片] CodePen Demo -- inline-block 实现整块的溢出打点 问题一:超长文本整块省略 基于上述的超长打点省略方案之下,会有一些变化的需求。譬如,我们有如下结构: Sb Coco FEUIUX Designer前端工程师 [图片] 对于上述超出的情况,我们希望对于超出文本长度的整一块 -- 前端工程师,整体被省略。 如果我们直接使用上述的方案,使用如下的 CSS,结果会是这样,并非我们期待的整块省略: .person-card__desc { width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } [图片] 将 [代码]display: inline[代码] 改为 [代码]display: inline-block[代码] 实现整块省略 这里,如果我们需要实现一整块的省略,只需要将包裹整块标签元素的 [代码]span[代码] 的 [代码]display[代码] 由 [代码]inline[代码] 改为 [代码]inline-block[代码] 即可。 .person-card__desc span { display: inline-block; } [图片] 这样,就可以实现,基于整块的内容的溢出省略了。完整的 Demo,你可以戳这里: CodePen Demo - 整块超长溢出打点省略 问题二:iOS 不支持整块超长溢出打点省略 然而,上述方案并非完美的。经过实测,上述方案在 iOS 和 Safari 下,没能生效,表现为这样: [图片] 查看规范 - CSS Basic User Interface Module Level 3 - text-overflow,究其原因,在于 [代码]text-overflow[代码] 只能对内联元素进行打点省略。(Chrome 对此可能做了一些优化,所以上述非 iOS 和 Safari 的场景是正常的) 所以猜测是因为经过了 [代码]display: inline-block[代码] 的转化后,已经不再是严格意义上的内联元素了。 解决方案,使用多行省略替代单行省略 当然,这里经过试验后,发现还是有解的,我们在开头还提到了一种多行省略的方案,我们将多行省略的代码替换单行省略,只是行数 [代码]-webkit-line-clamp: 2[代码] 改成一行即可 [代码]-webkit-line-clamp: 1[代码]。 .person-card__desc { width: 200px; white-space: normal; overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; } .person-card__desc span { display: inline-block; } 这样,在 iOS/Safari 下也能完美实现整块的超长打点省略: [图片] CodePen Demo -- iOS 下的整块超长溢出打点省略方案 值得注意的是,在使用 [代码] -webkit-line-clamp[代码] 的方案的时候,一定要配合 [代码]white-space: normal[代码] 允许换行,而不是不换行。这一点,非常重要。 这样,我们就实现了全兼容的整块的超长打点省略了。 当然,[代码] -webkit-line-clamp[代码] 本身也是存在一定的兼容性问题的,实际使用的时候还需要具体去取舍。 最后 好了,本文到此结束,一个简单的 CSS 小技巧,希望对你有帮助 :) 感兴趣的小伙伴点击链接,了解详情~ http://github.crmeb.net/u/yi 作者:chokcoco
2021-03-15 - 手把手教你实现一个浏览器引擎(一)Start [译文]
第一部分:起步 我正在打造一个玩具HTML渲染引擎,与此同时,我觉得你也应该尝试一下。这是这个系列文章的第一篇: 第一部分:起步 第二部分:HTML 第三部分:CSS 第四部分:Style 第五部分:Boxes 第六部分:Block layout 第七部分:Painting 101 完整的系列文章将会通过描述我编写的代码,让大家学会如何制作自己的专属浏览器引擎。但是首先,让我解释一些东西。 我们准备做的是一个什么东西? 首先,我们先谈谈一些术语(terminology)。 浏览器引擎(browser engine) 是网络浏览器(web browser)的一部分,作用是“在幕后”从互联网上获取网页,并将其内容转换为你可以阅读,观看的形式。 Blink,Gecko,WebKit 和 Trident 都是浏览器引擎。 相反,浏览器自己的用户界面(UI),如:标签(tabs)、工具栏(toolbar),菜单(menu)等等,我们称之为 chrome。 Firefox 和 SeaMonkey 是两个采用不同chrome,相同Gecko 引擎的浏览器。 一个浏览器还有其他很多子组件(sub-components):一个HTTP 客户端,一个HTML解析器(parser),一个CSS解析器(parser),一个JavaScript引擎(包含解析器parsers、解释器interpreters、编译器compilers)等等。这些组件涉及到HTML,CSS等网络格式的解析,并转换成我们在浏览器看到的内容。有时,也将它们称之为布局引擎(layout engine)或者渲染引擎(rendering engine)。 为什么是一个玩具引擎? 一个完整的浏览器引擎是相当的复杂的。 Blink,Gecko,WebKit这些引擎每个都是需要通过数百万行代码实现的。甚至一些如 Servo 和 WeasyPrint 这样比较新,比较简单的渲染引擎都是数万行代码的级别。对于新人来说,不是一个简单能完成的事。 说到巨型复杂软件:如果你上过编译器或操作系统的课,你可能做过或者修改过一个“玩具型”编译器或者内核。这是一个为学习而设计的简单模型;这可能是除了作者以外没人会运行的代码。不过制作一个“玩具型”的系统是一个很有用的学习方式,有助于我们的真正的编程工作。如果你从未做过真正的编译器或者内核,理解它们的工作机制也能在我们写代码的时候帮助我们更好地使用它们。 在家里尝试 try this at home 我希望我已经说服你去做个尝试。如果你已有一定的编程经验,且懂得一些HTML和CSS的高阶概念的话,这个系列的内容就不会难倒你。 然而,如果你刚开始编程的话,或者有些地方不懂,可以自由提问,我尝试讲得更通俗易懂些。 在开始之前,先谈一下,你可以有哪些选择: 编程语言 你可以使用任何语言来编写渲染引擎,真的,你可以使用你熟悉或者喜欢的任何语言。或者如果听起来很有趣,也可以以此为借口来学习一种新语言。 如果你想开始对一些主流的浏览器引擎如:Gecko 或 WebKit做贡献的话,你可能要使用C++,因为它是这些引擎的主要语言,并且使用它可以使将代码与其代码进行比较变得更加容易。 我的玩具项目:robinson 是使用 Rust 编写的。我是 Moziila 的 Servo team 成员,因此我非常喜欢使用Rust编程。另外,我在该项目中的目标之一,是了解Servo的更多实现。Ronbison偶尔也会用到Servo简化版的数据结构和代码。 关于库与捷径 On Libraries and Shortcuts 在像这样的学习练习中,你需要决定到底是 直接使用他人的代码还是自己重写实现一遍。我的建议是,如果你想真正得理解的话,你应该自己重新实现一遍,不过千万不要愧于使用第三方库或者参考别人的代码。学习如何使用特定的库本身可能是一个有价值的练习。 我编写的Robinson,不仅要为了自己,而且还要作为这些文章和练习的示例代码。为了这样和那样的理由,我希望它尽可能的小且独立。目前为止,我没使用任何第三方代码除了 Rust 的标准库(这也避免了在语言仍处于开发阶段时使用相同版本的Rust来构建多个依赖项的麻烦。)当然,这些规则也不是一成不变的。举例来说,我可能决定之后使用第三方图形库而不是自己手写低级的绘制代码。 还有一种避免写代码的捷径就是,让这些功能都不要了吧。比如 robinson 是没有任何联网的代码,它仅仅可以读取本地文件。在一个玩具项目里,你可以随心所欲地跳过任何东西。因此,读这个系列文章,你可以随时跳过你不感兴趣的部分,直接阅读你觉得有趣的部分。在你回心转意时,再去补回前面的跳过的内容。 第一步:The DOM 你准备好写一些代码了吗?我们从一些小方面开始着手:DOM的数据结构。我们一起来看看 robinson 的 DOM Module DOM是由许多的节点(nodes)组成的树(tree),一个节点(node)有零个或者多个子节点(Child)。(另外,它还有许多其他属性或者方法,不过我们可以暂时忽略这部分) [代码]struct Node { // data common to all nodes: children: Vec<Node>, // data specific to each node type: node_type: NodeType, } [代码] 其实节点是有许多的节点类型(node types),不过目前我们将忽略其中的大多数,并当做只有两种类型的节点:元素(Element)或者文本节点(Text node)。在具有继承性的语言中,这些将是Node的子类型。在Rust里,他们可以是枚举(enum )类型: [代码]enum NodeType { Text(String), Element(ElementData), } [代码] 一个元素包含:一个标签名(tag name)、任意个属性(attributes),可以将属性其存储为从名称到值的映射。Robinson不支持任何命名空间,因此只是将标签名(tag name)和属性名(attribute name)存成简单的字符串类型。 [代码]struct ElementData { tag_name: String, attributes: AttrMap, } type AttrMap = HashMap<String, String>; [代码] 最后是一些便于创建新节点的构造方法: [代码]fn text(data: String) -> Node { Node { children: Vec::new(), node_type: NodeType::Text(data) } } fn elem(name: String, attrs: AttrMap, children: Vec<Node>) -> Node { Node { children: children, node_type: NodeType::Element(ElementData { tag_name: name, attributes: attrs, }) } } [代码] 就是这样!全面的DOM实现将包含更多数据和数十种方法,但这就是我们开始所需要的 练习 以下是一些建议的练习方法。你可以做一些感兴趣的练习,然后跳过所有您不感兴趣的练习。 开始一个新项目,自由选择一种语言,编写代码实现包含text nodes 和 elements的DOM tree 安装最新版本的Rust,然后下载和构建 Robinson,打开 [代码]dom.rs[代码] 然后继承 [代码]NodeType[代码] 追加实现其他类型,如comment nodes 编写代码输出一个漂亮的树形DOM nodes 在下篇文章里,我们将会添加一个解析器(parser),把HTML源代码(source code)转换成包含DOM nodes的树 参考 有关浏览器引擎内部的更多详细信息,请参阅 Tali Garsiel 精彩的 How Browsers Work 及其指向更多资源的链接。 有关参考代码,以下是“小型”开源渲染引擎的清单。其中大部分都比 robinson 大好几倍,但仍远远小于 Gecko 和 WebKit。 其中 WebWHirr 只有2000行代码,这是唯一一个我会称之为玩具的一个引擎。 CSSBox (Java) Cocktail (Haxe) gngr (Java) litehtml (C++) LURE (Lua) NetSurf (C) Servo (Rust) Simple San Simon (Haskell) WeasyPrint (Python) WebWhirr (C++) 你可能会发现这些项目可以给你很多灵感或者参考。如果你知道其他类似的项目或者如果你开始自己的项目,请让我知道!
2020-02-10 - 微信小程序swiper高度动态适配(子元素高度不固定)
示例代码地址 https://github.com/s568774056/swipe.git 对于整页都是swiper的情况下。例如下面这张图: [图片] 则可以使用如下css [代码] [代码] [代码]swiper,swiper-item{[代码] [代码] [代码][代码]height[代码][代码]: [代码][代码]100[代码][代码]vh [代码][代码]!important[代码][代码];[代码][代码]}[代码] [代码] [代码] [代码]或者 [代码] [代码] [代码] [代码][代码] [代码][代码] swiper,swiper-item{ height: calc(100vh - 75rpx) !important; } [代码][代码] [代码] [代码] 对于swiper占据部分高度的情况下。 [图片] 使用如下代码 原理为在[代码]swiper-item[代码][代码][代码]的最上面和最下面插入空view,并利用wx api获取两个之间的高度差,然后设置给[代码]swiper[代码]。 细节方面需要自己调整下。为什么小程序不把这个组件做好呢?还得自己计算- -! <swiper class='hide' bindanimationfinish="swiperChange" style="height:{{swiper_height}};" current="{{isIndex}}"> <swiper-item wx:for="{{roomList}}" wx:for-item='room' wx:for-index="index"> <view id="start{{index}}" class='start-view'></view> <block wx:for="{{imgUrls}}" wx:for-item='path' wx:for-index="img-index"> <image mode="aspectFill" src="{{path}}" /> </block> <view id="end{{index}}" class='start-view'></view> </swiper-item> </swiper> [代码][代码][代码][代码] swiper { margin-top: 45rpx; } Page({ data: { roomList: ['Room1', 'Room2', 'Room3'], imgUrls: [ 'https://images.unsplash.com/photo-1551334787-21e6bd3ab135?w=640', 'https://images.unsplash.com/photo-1551214012-84f95e060dee?w=640', 'https://images.unsplash.com/photo-1551446591-142875a901a1?w=640' ], swiper_height: 0, isIndex:0 }, onLoad: function () { this.autoHeight(); }, changeNavBar: function (e) { this.setData({ isIndex: e.detail }); }, swiperChange: function (e) { this.setData({ isIndex: e.detail.current }); this.autoHeight(); }, autoHeight() { let { isIndex } = this.data; wx.createSelectorQuery() .select('#end' + isIndex).boundingClientRect() .select('#start' + isIndex).boundingClientRect().exec(rect => { let _space = rect[0].top - rect[1].top; _space = _space + 'px'; this.setData({ swiper_height: _space }); }) } }) 参考文章https://developers.weixin.qq.com/community/develop/doc/00008aaf4a473056d1c69a8b253c04
2019-09-04 - 「笔记」订阅消息体验踩坑
前言 10月12日夜晚社区发了公告小程序模板消息能力调整通知,正式发布了 一次性订阅消息 这一能力,所以第一时间进行了体验。 本文主要是补充一下官方未提供的使用方法,和使用中与模板消息用法的不同。 文档地址 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html 使用方法 [代码]wx.requestSubscribeMessage({ tmplIds: ["模板id1","模板id2"], success: function (res) { //成功 }, fail(err) { //失败 console.error(err); } }) [代码] 第一个坑 如果不勾选红色方框内的内容,用户每次触发订阅消息功能都会弹出授权窗口,如果用户勾选了则不会出现弹窗。 [图片] 第二个坑 目前开发者工具(v1.02.191012)不支持调试,只能通过真机调试。 [图片] 第三个坑 微信不会为开发者保存订阅次数,需要自己在后台记录用户触发的次数。 超过次数调用接口下发订阅消息会返回失败。 [图片] 第四个坑 发送模板格式和原来的模板消息格式不一致,特别是data内的内容,订阅消息的字段key是和数据类型有关,value的参数需要严格按照设置的类型提交,具体使用参考后台的模板详情。 模板消息的格式: [代码]"data": { "keyword1": { "value": "内容", "color": "#000" }, "keyword2": { "value": "内容", "color": "#000" } } [代码] 订阅消息的格式: [代码]"data": { "thing1": { "value": "内容" }, "number2": { "value": 20 } [代码] 第五个坑 订阅消息申请模板的时候,需要选择所属类目,而且只能是自己小程序相关类目,模板消息是不需要选择对应类目的。 如果删除小程序类目,则会把订阅消息模板一起删除,需谨慎操作。 [图片] 第六个坑 长期订阅消息只针对特定行业开放,所以普通开发者并无法使用。 结束 暂时就先总结这些,有其它坑再补充。
2019-10-13