- app微信支付投诉率大概会被涉嫌交易纠纷
因为技术比较好,我们app在通竞品里面做的比较好,就是很明显比他们好很多的,然后我们投放就比较多用户付费,一些商家就找水军来恶意投诉,什么进来什么核心功能点都没有点,就买一个会员,然后过几分钟就开始申请退款,退款理由也是胡说八道的,什么自动扣款,不知道怎么付款,产品功能缺陷,,实际这些问题,我们早都解决了,竞品可能会存在,甚至有些应用名字都写错了,写成竞品的来投诉我,有些用户一下直接买好几笔,然后每笔都投诉。 我们也有客服入口,都在线的,他们也不找,直接微信申请退款,现在面对这样的情况不知道怎么处理,因为担心微信投诉率太高了,涉嫌交易纠纷。 另外大概app投诉率多少会涉嫌校验纠纷,我们作为商户有点担心。
2024-07-15 - 企业微信群发小程序,如何禁止长按小程序卡片的转发功能?
想实现的功能就是如图一,转发按钮不见,通过企业微信分享小程序卡片,或者群发小程序卡片到企业微信群里面,请问怎么实现,我没有看到有配置项 图一: [图片] 图二: [图片]
2021-12-22 - 关于小游戏wx.createUserInfoButton显示不出的问题的踩坑分享
关注https://mp.weixin.qq.com/s/yD5G_XH9GiVUrZZnEZA-Ug这个文章公众号,一起进步一起成长
2018-04-26 - 我方著作权名称被第三方未发布的小游戏名字占用,如何找回?
我方有版著、文网游备案和版号授权等小游戏发布所需要的资质,但发布小游戏时发现小游戏名在被占,通过申诉被驳回。现如何找回? 1、通过微信搜索该小游戏名称搜不到,说明第三方只是占用小游戏名称而未发布; 2、按微信发布的资质要求,除非我方发布,而任何第三方是发布不了的,因为版著、文网游备案都在我方; 3、我们是创业公司,这种现象伤不起,有可能有人故意抢名字而不发布,而资质齐全的人想做却做不了; 4、如果发现小游戏名字被占,微信官方能否提供抢占方的联系方式,以便双方协商。 疫情期间,创业更加维艰,小游戏名字侵权申诉几个来回就是两周过去了,压力极大,望微信小游戏评审给予解决方式指导,以便尽快上线,我们团队能活下来。 [图片]
2020-04-22 - 小游戏资质提交审核指引Q&A
小游戏资质提交审核指引 温馨提醒:微信公众平台的账号名称是该账号的品牌表现,小游戏账号命名需符合平台规范。如需提前了解,或查询你的小游戏未符合平台规范 原因,可点击此处查阅平台命名规范 一、资质提交入口: 1.微信公众平台 -> 首页 -> 小程序发布流程 -> 小程序备案 -> 选择游戏情况 -> 资质提交(首次提交资质材料) [图片] 2.微信公众平台 -> 首页 -> 菜单栏左下角 -> 账号设置 -> 游戏设置 -> 资质管理 -> 前往管理(首次or后续更新资质材料)[图片] 二、主体迁移:微信公众平台 -> 首页 -> 菜单栏左下角 -> 账号设置 -> 基本设置 -> 主体信息 -> 小程序主体变更 -> 提交资质审核申请 [图片] 注:审核提交信息后预计1-2个工作日内处理完毕,审核请留意微信公众平台通知中心的通知。 说明:游戏资质文档规范及示例 一、各资质文档基本要求: (1)所有游戏需提交:《游戏自审自查报告》、《著作权自我声明》、《代备案授权书》 文档规范要求:上传文件,非个人主体请务必加盖清晰规范账号主体公章,个人主体请在落款处清晰规范签署个人签名并捺指印 查看示例: 《游戏自审自查报告》、《著作权自我声明-非个人主体》、《著作权自我声明-个人主体》、《代备案授权书-非个人主体》、《代备案授权书-个人主体》 (2)选填材料一个《计算机软件著作权登记证书》 文档规范要求:上传【原件或加盖著作权人鲜章的复印件】之扫描件,复印件务必清晰规范加盖著作权人公章或著作权人签名 查看示例:《计算机软件著作权登记证书》 注:游戏名称含有“软件”、“人名”、“英文”,《计算机软件著作权登记证书》为必填材料。 (3)牌类游戏需提交:《计算机软件著作权登记证书》、《网络游戏出版物号核发单》、《产品合规报告》、《产品运营报告》、《内容一致承诺函》、《关于使用微信支付服务的合法性承诺书》、《棋牌类网络游戏经营自查报告》、《游戏自审自查报告》、《著作权自我声明》、《代备案授权书》 文档规范要求:上传【原件或复印件】之扫描件,复印件非个人主体请务必加盖清晰规范账号主体公章,个人主体请清晰规范签署个人签名 查看示例:《计算机软件著作权登记证书》、《网络游戏出版物号核发单》、《产品合规报告》、《产品运营报告》、《内容一致承诺函》、《关于使用微信支付服务的合法性承诺书》、《棋牌类网络游戏经营自查报告》、《游戏自审自查报告》、《著作权自我声明-非个人主体》、《代备案授权书-非个人主体》 (4)开通虚拟支付游戏需提交:《网络游戏出版物号核发单》、《计算机软件著作权登记证书》、《游戏自审自查报告》、《内容一致承诺函》、《著作权自我声明》、《代备案授权书》 《网络游戏出版物号核发单》文档规范要求: 上传【原件】之扫描件 查看示例:《网络游戏出版物号核发单》 《计算机软件著作权登记证书》文档规范要求: 上传【原件或加盖著作权人鲜章的复印件】之扫描件,复印件务必清晰规范加盖著作权人公章或著作权人签名 查看示例:《计算机软件著作权登记证书》 《游戏自审自查报告》文档规范要求: 上传文件,请务必加盖清晰规范账号主体公章 查看示例: 《游戏自审自查报告》 《内容一致承诺函》文档规范要求: 上传文件,请务必加盖清晰规范账号主体公章 查看示例:《内容一致承诺函》 《著作权自我声明》文档规范要求: 上传文件,非个人主体请务必加盖清晰规范账号主体公章,个人主体请在落款处清晰规范签署个人签名并捺指印 查看示例:《著作权自我声明-非个人主体》、《著作权自我声明-个人主体》 《代备案授权书》文档规范要求: 上传文件,非个人主体请务必加盖清晰规范账号主体公章,个人主体请在落款处清晰规范签署个人签名并捺指印 查看示例:《代备案授权书-非个人主体》、《代备案授权书-个人主体》 (5)文化互动类目需提交:2个,《商标注册证》、《游戏自审自查报告》 《商标注册证》文档规范要求: 文档规范要求:上传【原件或复印件】之扫描件,复印件请务必加盖清晰规范商标注册人公章,商标注册人为个人请清晰规范签署个人签名 查看示例:《商标注册证》 《游戏自审自查报告》文档规范要求: 上传文件,非个人主体请务必加盖清晰规范账号主体公章,个人主体请在落款处清晰规范签署个人签名 查看示例: 《游戏自审自查报告》 (6)各个文件的格式、数量和大小要求 文件格式: 《网络游戏出版物号核发单》及《网络游戏出版物号核发单》授权书格式为 JPEG、JPG 《计算机软件著作权登记证书》文件为 JPEG、JPG、PNG、BMP、GIF、PDF 《计算机软件著作权登记证书》授权书为 JPEG、JPG、PNG、BMP 《游戏自审自查报告》文件为 JPEG、JPG、PNG、BMP、GIF 《内容一致承诺函》文件为 JPEG、JPG、PNG、BMP、GIF 《关于使用微信支付服务的合法性承诺书》文件为 JPEG、JPG、PNG、BMP 《棋牌类网络游戏经营自查报告》文件为 JPEG、JPG、PNG、BMP 《著作权自我声明》文件为 JPEG、JPG、PNG、BMP 《代备案授权书》文件为 JPEG、JPG、PNG、BMP 《产品合规报告》文件为 PDF 《产品运营报告》文件为 PDF 文件大小: 《网络游戏出版物号核发单》及《网络游戏出版物号核发单》授权书单个文件大小:≤ 200KB 《计算机软件著作权登记证书》及《计算机软件著作权登记证书》授权书单个文件大小:≤ 2000KB 《产品合规报告》、《产品运营报告》、《游戏自审自查报告》和《内容一致承诺函》大小不超过5M 《软著自我声明》、《代备案授权书》、《关于使用微信支付服务的合法性承诺书》和《棋牌类网络游戏经营自查报告》文件大小不超过2M 文件数量: 《网络游戏出版物号核发单》文件限制最多1张(多于1张请按顺序自行合并) 《网络游戏出版物号核发单》授权书限制最多2张(多于2张请按顺序自行合并) 《计算机软件著作权登记证书》限制最多1张(多于1张请按顺序自行合并) 《计算机软件著作权登记证书》授权书限制最多2张(多于2张请按顺序自行合并) 二、关于《计算机软件著作权登记证书》: (1)《计算机软件著作权登记证书》著作权人:提审软著证书的著作权人需与版号著作权人保持一致 《计算机软件著作权登记证书》著作权人说明示例图: [图片] (2)《计算机软件著作权登记证书》颁发日期:《计算机软件著作权登记证书》的颁发日期需在版号证书颁发日期前 《计算机软件著作权登记证书》颁发日期说明示例图: [图片] (备注:《计算机软件著作权登记证书》颁发日期为2015年5月6日,《网络游戏出版物号核发单》颁发日期为2016年11月8日) 三、关于各资质文档刊载游戏名称:各资质文件中的游戏名称,需与提审游戏名称保持完全一致 游戏名称一致说明示例图: [图片] 四、关于授权书: (1)提交入口:登录微信公众平台(mp.weixin.qq.com),进入公众平台菜单栏左下角->账号设置->游戏设置->资质管理->前往管理-> 在《授权书》入口上传相关授权书,该入口支持多个文档上传 [图片] (2)应用场景: 请针对小游戏资质软著授权、小游戏品牌合作等素材露出、使用他人的商标或IP等场景上传相关授权书及授权人的权利证明,包括但不限于著作权授权(不限于美术作品著作权、文字作品著作权、音乐作品著作权、计算机软件著作权);版号、备案信息中的运营单位授权他人发布小游戏;使用文学作品或影视作品名称或内容的小游戏;使用他人商标的小游戏;品牌联合推广等。 示例文档:《著作权授权书》、《运营授权书》、《商标授权书》 特别说明:若《网络游戏出版物号核发单》运营单位、《计算机软件著作权登记证书》著作权人与提审主体不一致,即《网络游戏出版物号核发单》运营单位委托他人发布小游戏的,请在《授权书》入口上传《计算机软件著作权登记证书》著作权人、《网络游戏出版物号核发单》运营单位、向提审主体出具的多份运营授权书。授权链条示例拆解,详见以下图表: [图片] [图片] 五、规范要求: (一)单份授权书 (1)明确标明授权人与被授权人准确名称 (2)写明授权作品的基本信息(软件名称及简写、版本号,计算机软件著作权登记证书登记号) (3)明确标明授权范围和期限 (4)授权方的盖公章或亲笔签名(个人) (5)授权书资质文件不得超过有效期 (二)多份授权书 (1)前后几份授权书之间需要有连续性 (2)在后授权书的授权范围不能超过在先授权书 (3)在后授权书的授权时间不能超过在先授权书 (4)注明是否有转授权的权利 文档规范要求:上传文件,务必加盖公章授权方盖公章或亲笔签名(个人) 查看示例:《著作权授权书》、《运营授权书》、《商标授权书》 六、其他易遗漏事项温馨提醒 (1)清晰:小游戏资质文件关键信息需清晰可见 (2)公章/签名:各资质文档需加盖公章或亲笔签名 附:如果你还不了解如何提审版本,请点击此处查看版本提审指引
2024-11-01 - 提交审核时,计算机软件著作权登记证书后面有选填,是不是就不需要了?
计算机软件著作权登记证书(选填) 著作权人(选填) 授权书(选填) 这三个变成选填了,是不是发布的时候只需要上传游戏自审自查报告就可以了 [图片]
2020-04-24 - 微信小程序审核需要 软件著作权吗?
如题 微信小程序审核需要 软件著作权吗?
2021-05-09 - 急急急,游戏提交审核 怎么还要苹果开发者账号
[图片] 怎么会是必填??????????????????????要这个有何用?
2020-12-19 - useExtendedLib.weui=true时,usingComponents中组件路径怎么写?
[图片] [图片] [图片]
2020-05-09 - ios13网络请求pending时间过长,有人遇到问题吗?
[图片] ios13.3,iphone xs max,网络请求耗时6秒 [图片] ios10.3,iphone6s,在相同的网络状态下,网络请求只有300ms,相差了20倍,主要时间是被pending了,导致网络请求要几秒钟后才能到后台接口,这个pending时间是微信服务器做了限制吗?为什么要做这个限制。新机型比旧机型差了20倍,这是什么原因呢?
2020-06-11 - 第三方平台wx.checkSession和getPhoneNumber问题
开发流程: 进入页面接口报401时, 1、弹窗弹出一瞬间wx.login获取到最新code,然后通过点击弹窗的按钮getPhoneNumber获取到 encryptedData和 iv ,弹窗关闭, 用wx.checkSession进行检测, a、success时,把code, encryptedData和 iv 传给后端进行解析 b、fail时,则进行步骤1的行为 在wx.checkSession 遇到两种极端情况 1、有些人账号一直进入success,即使删除工具的登陆缓存,还是会一直进入success 2、有的人账号一直进入fail,明明在wx.checkSession 之前已经wx.login居然会检测失败(以上情况只有开发者工具会这样,手机端会一直进入success) 然后针对一直进入fail的情况,我不再用wx.checkSession进行检测,把code, encryptedData和 iv 直接传给后端进行解析,结果居然能解析成功!! 由于怀疑不用code也可以解析,我进行了测试,发现code还是必须要传的,但是第一次登陆的code和第二次登陆的code居然都可以解析出电话号码 所以我的问题是: 一、session_key的时效性是怎么样的?难道删除开发工具的的登陆缓存不能导致session_key失效吗? 二、wx.login后再wx.checkSession进入fail是因为什么导致的? 三、明明wx.checkSession 进入fail里了,为何code传给后端,还能解析成功?既然解析能成功,为何进入了fail事件? 四、getPhoneNumber获取到的encryptedData和 iv 不用跟最新wx.login的code 也能进行解析吗?
2019-04-19 - session_key是小程序自身存在的还是login获取的
如题,session_key是否为小程序的自有属性?即: 小程序进入生命周期起就拥有session_key并拥有自己的有效期会过期并自动刷新,而login用于获取当前session_key并有可能刷新session_key 如果不是的话,是否当没有调用wx.login时session_key就不存在。且获取的session_key在失效并没有获得时就会消失处于无session_key状态 这两种情况到底哪种才是正解,还是都有问题? 先说下会产生这个问题的背景: 一个单页面小程序需要获取用户信息。此时, 所需要做的事情有: 通过login拿到code 用户触发按钮拿到加密信息及密钥等 把code和加密信息等传给服务端 后端用code获取session_key,并解密出明文 [图片] 大概是这样一个流程。其中加密数据(encryptedData)是基于session_key加密的。 那么在没有login的情况下这个session_key肯定是存在的。所以会产生session_key是否是自有属性的这个问题。 基于这个背景的另一个问题是: 如果login获取code在用户点击按钮回调的外部(onLoad),没法确认用户点击按钮触发getNumber时,login已经成功获取回调取得code 而如果login在在用户点击按钮回调的内部,login可能会刷新session_key,导致给后端拿到的session_key并不是加密用户信息的session_key 这种情况该如何解决呢?
2019-04-15 - 咨询几个关于session_key的问题
这几天又涉及到解密的几个功能,对 session_key 还是有很多疑惑: 文档上说 session_key 是有有效期的, 可以通过 wx.checkSession 去检验,过期了,执行wx.login,就能获取新的 session_key 1:所以想问一下,如果 session_key 过期了,但是我们不去执行 wx.login (我们自己有个utoken的登录状态) 那微信会自己生成新的 session_key 吗? 2: 如果说微信不生成新的 session_key,那么理应我们去解密的时候是不会解密失败的? 因为都用着旧的 session_key。 3:但如果微信生成新的 session_key,那我们用 wx.checkSession 去检验,不就是还没过期吗? (这个有效期是怎么判断的) 4:我们之前使用授权手机号的一个情况: (前提:我们没有wx.checkSession后执行wx.login,而是根据我们的utoken过期后,再去执行wx.login) 这样用户授权手机号,就会存在解密失败的情况,这说明 session_key 过期后,微信生成了新的 session_key ,那么我在执行 wx.login后,是不是这个 session_key 又要更新了? (因为我拿着第一次的密文去重试解密的时候,解密失败,可见又生成了新的 session_key) 综合以上,还是想细致的了解一下: 1:session_key 都什么情况下会更新,哪些更新是我们触发的,哪些是微信触发的 2:session_key的有效期是怎么判断的?
2019-05-22 - Wxml2Canvas -- 快速生成小程序分享图通用方案
Wxml2Canvas库,可以将指定的wxml节点直接转换成canvas元素,并且保存成分享图,极大地提升了绘制分享图的效率。目前被应用于微信游戏圈、王者荣耀、刺激战场助手等小程序中。 github地址:https://github.com/wg-front/wxml2canvas 一、背景 随着小程序应用的日渐成熟,多处场景需要能够生成分享图便于用户进行二次传播,从而提升小程序的传播率以及加强品牌效应。 对于简单的分享图,比如固定大小的背景图加几行简短文字构成的分享小图,我们可以利用官方提供的canvas接口将元素直接绘制, 虽然繁琐了些,但能满足基本要求。 对于复杂的分享图,比如用户在微信游戏圈发表完话题后,需要将图文混排的富文本内容生成分享图,对于这种长度不定,内容动态变化的图片生成需求,直接利用官方的canvas接口绘制是十分困难的,包括但不限于文字换行、表情文字图片混排、文字加粗、子标题等元素都需要一一绘制。又如王者荣耀助手小程序,需要将十人对局的详细战绩绘制成分享图,包含英雄数据、装备、技能、对局结果等信息,要绘制100多张图片和大量的文字信息,如果依旧使用官方的接口一步一步绘制,对开发者来说简直就是一场噩梦。我们急需一种通用、高效的方式完成上述的工作。 在这样的背景下,wxml2cavnas诞生了,作为一种分享图绘制的通用方案,它不仅能快速的绘制简单的固定小图,还能直接将wxml元素真实地转换成canvas元素,并且适配各种机型。无论是复杂的图文混排的富文本内容,还是展现形式多样的战绩结果页,都可以利用wxml2cavnas完美地快速绘制并生成所期望的分享图片。 二、Wxml2Canvas介绍及示例 1. 介绍 Wxml2Cavnas库,是一个生成小程序分享图的通用方案,提供了两种绘制方式: 封装基础图形的绘制接口,包括矩形、圆形、线条、图片、圆角图片、纯文本等,使用时只需要声明元素类型并提供关键数据即可,不需要再关注canvas的具体绘制过程; wxml直接转换成canvas元素,使用时传入待绘制的wxml节点的class类名,并且声明绘制此节点的类型(图片、文字等),会自动读取此节点的computedStyle,利用这些数据完成元素的绘制。 2. 生成图示例 下面是两张极端复杂的分享图。 2.1 游戏圈话题 [图片] 点击查看完整长图 2.2.2 王者荣耀战绩 [图片] 点击查看完整大图 三、小程序的特性及局限 小程序提供了如下特性,可供我们便捷使用: measureText接口能直接测量出文本的宽度; SelectorQuery可以查询到节点对应的computedStyle。 利用第一条,我们在绘制超长文本时便于文本的省略或者换行,从而避免文字溢出。 利用第二条,我们可以根据class类名,直接拿到节点的样式,然后将style转换成canvas可识别的内容。 但是和html的canvas相比,小程序的canvas局限性很多。主要体现在如下几点: 不支持base64图片; 图片必须下载到本地后才能绘制到画布上; 图片域名需要在管理平台加入downFile安全域名; canvas属于原生组件,在移动端会置于最顶层; 通过SelectorQuery只能拿到节点的style,而无法获取文本节点的内容以及图片节点的链接。 针对以上问题,我们需要将base64图片转换jpg或png格式的图片,实现图片的统一下载逻辑,并且离屏绘制内容。针对第五条,好在SelectorQuery可以获取到节点的dataset属性,所以我们需要在待绘制的节点上显示地声明其类型(imgae、text等),并且显示地传入文本内容或图片链接,后文会有示例。 四、Wxml2Canvas使用方式 1. 初始化 首先在wxml中创建canvas节点,指定宽高: [代码] <canvas canvas-id="share" style="height: {{ height * zoom }}px; width: {{ width * zoom }}px;"> </canvas> [代码] 引入代码库,创建DrawImage实例,并传入如下参数: [代码] let DrawImage = require('./wxml2canvas/index.js'); let zoom = this.device.windowWidth / 375; let width = 375; let height = width * 3; let drawImage = new DrawImage({ element: 'share', // canvas节点的id, obj: this, // 在组件中使用时,需要传入当前组件的this width: width, // 宽高 height: height, background: '#161C3A', // 默认背景色 gradientBackground: { // 默认的渐变背景色,与background互斥 color: ['#17326b', '#340821'], line: [0, 0, 0, height] }, progress (percent) { // 绘制进度 }, finish (url) { // 画完后返回url }, error (res) { console.log(res); // 画失败的原因 } }); [代码] 所有的数字参数均以iphone6为基准,其中参数width和height决定了canvas画布的大小,规定值是在iphone6机型下的固定数值; zoom参数的作用是控制画布的缩放比例,如果要求画布自适应,则应传入 windowWidth / 375,windowWidth为手机屏幕的宽度。 2. 传入数据,生成图片 执行绘制操作: [代码] drawImage.draw(data, this); [代码] 执行绘制时需要传入数据data,数据的格式分为两种,下面展开介绍。 2.1 基础图形 第一种为基础的图形、图文绘制,直接使用官方提供接口,下面代码是一个基本的格式: [代码] let data = { list: [{ type: 'image', url: 'https://xxx', class: 'background_image', // delay: true, x: 0, y: 0, style: { width: width, height: width } }, { type: 'text', text: '文字', class: 'title', x: 0, y: 0, style: { fontSize: 14, lineHeight: 20, color: '#353535', fontFamily: 'PingFangSC-Regular' } }] } [代码] 如上,type声明了要元素的类型,有image、text、rect、line、circle、redius_image(圆角图)等,能满足绝大多数情况。 class类名指定了使用的样式,需要在style中写出,符合css样式规范。 delay参数用来异步绘制元素,会把此元素放在第二个循环中绘制。 x,y用来指定元素的起始坐标。 将css样式与元素分离的目的是便于管理与复用。 此种方式每个元素都相互独立,互不影响,能够满足自由度要求高的情况,可控性高。 2.2 wxml转换 第二种方式为指定wxml元素,自动获取,下面是示例: [代码] let data = { list: [{ type: 'wxml', class: '.panel .draw_canvas', limit: '.panel' x: 0, y: 0 }] } [代码] 如上,type声明为wxml时,会查找所有类名为draw_canvas的节点,并且加入到绘制队列中。 class传入的第一个类名限定了查询的范围,可以不传,第二个用来指定查找的节点,可以定义为任意不影响样式展现的通用类名。 limit属性用来限定相对位置,例如,一个文本的位置(left, top) = (50, 80), class为panel的节点的位置为(left, top) = (20, 40),则文本canvas上实际绘制的位置(x, y) = (50 - 20, 80 -40) = (30, 40)。如果不传入limit,则以实际的位置(x, y) = (50, 80)绘制。 由于小程序节点元素查询接口的局限,无法直接获取节点的文本内容和图片标签的src属性,也无法直接区分是文本还是图片,但是可以获取到dataset,所以我们需要在节点上显示地声明data-type来指明类型,再声明data-text传入文字或data-url传入图片链接。下面是个示例: [代码] <view class="panel"> <view class="panel__img draw_canvas" data-type="image" data-url="https://xxx"></view> <view class="panel__text draw_canvas" data-type="text" data-text="文字">文字</view> </view> [代码] 如上,会查询到两个节点符合条件,第一个为image图片,第二个为text文本,利用SelectorQuery查询它们的computedStyle,分别得到left、top、width、height等数据后,转换成canvas支持的格式,完成绘制。 除此之外,下面的示例功能更加丰富: [代码] <view class="panel"> <view class="panel__text draw_canvas" data-type="background-image" data-radius="1" data-shadow="" data-border="2px solid #000"></view> <view class="panel__text draw_canvas" data-type="text" data-background="#ffffff" data-padding="2 3 0 0" data-delay="1" data-left="10" data-top="10" data-maxlength="4" data-text="这是个文字">这是个文字</view> </view> [代码] 如上,第一个data-type为background-image,表示读取此节点的背景图片,因为可以通过computedStyle直接获取图片链接,所以不需要显示传入url。声明data-radius属性,表示要将此图绘成乘圆形图片。data-border属性表示要绘制图片的边框,虽然也可以通过computedStyle直接获取,但是为了避免非预期的结果,还是要声明传入,border格式应符合css标准。此外,图片的box-shadow等样式都会根据声明绘制出来。 第二个文本节点,声明了data-background,则会根据节点的位置属性给文字增加背景。 data-padding属性用来修正背景的位置和宽高。data-delay属性用来延迟绘制,可以根据值的大小,来控制元素的层级,data-left和data-top用来修正位置,支持负值。data-maxlength用来限制文本的最大长度,超长时会截取并追加’…’。 此外,data-type还有inline-text,inline-image等行内元素的绘制,其实现较为复杂,会在后文介绍。 五、Wxml2Canvas实现原理 1. 绘制流程 整个绘制流程如下: [图片] 因为小程序的限制,只能在画布上绘制本地图片,所以统一先对图片提前下载,然后再绘制,为了避免图片重复下载,内部维护一个图片列表,会对相同的图片链接去重,减少等待时间。 2. 基本图形的实现 基础图形的绘制比较简单,内部实现只是对基础能力的封装,使用者不用再关注canvas的绘制过程,只需要提供关键数据即可,下面是一个图片绘制的实现示例: [代码] function drawImage (item, style) { if(item.delay) { this.asyncList.push({item, style}); }else { if(item.y < 0) { item.y = this.height + item.y * zoom - style.height * zoom; }else { item.y = item.y * zoom; } if(item.x < 0) { item.x = this.width + item.x * zoom - style.width * zoom; }else { item.x = item.x * zoom; } ctx.drawImage(item.url, item.x, item.y, style.width * zoom, style.height * zoom); ctx.draw(true); } } [代码] 如上,x,y值坐标支持传入负值,表示从画布的底部和右侧计算位置。 3. Wxml转Canvas元素的实现 3.1 computedStyle的获取 首先需要获取wxml的样式,代码示例如下: [代码] query.selectAll(`${item.class}`).fields({ dataset: true, size: true, rect: true, computedStyle: ['width', 'height', ...] }, (res) => { self.drawWxml(res); }) [代码] 3.2 块级元素的绘制 对于声明为image、text的元素,默认为块级元素,它们的绘制都是独立进行的,不需要考虑其他的元素的影响,以wxml节点为圆形的image为例,下面是部分代码: [代码] if(sub.dataset.type === 'image') { let r = sub.width / 2; let x = sub.left + item.x * zoom; let y = sub.top + item.y * zoom; let leftFix = +sub.dataset.left || 0; let topFix = +sub.dataset.top || 0; let borderWidth = sub.borderWidth || 0; let borderColor = sub.borderColor; // 如果是圆形图片 if(sub.dataset.radius) { // 绘制圆形的border if(borderWidth) { ctx.beginPath() ctx.arc(x + r, y + r, r + borderWidth, 0, 2 * Math.PI) ctx.setStrokeStyle(borderColor) ctx.setLineWidth(borderWidth) ctx.stroke() ctx.closePath() } // 绘制圆形图片的阴影 if(sub.boxShadow !== 'none') { ctx.beginPath() ctx.arc(x + r, y + r, r + borderWidth, 0, 2 * Math.PI) ctx.setFillStyle(borderColor); setBoxShadow(sub.boxShadow); ctx.fill() ctx.closePath() } // 最后绘制圆形图片 ctx.save(); ctx.beginPath(); ctx.arc((x + r), (y + r) - limitTop, r, 0, 2 * Math.PI); ctx.clip(); ctx.drawImage(url, x + leftFix * zoom, y + topFix * zoom, sub.width, sub.height); ctx.closePath(); ctx.restore(); }else { // 常规图片 } } [代码] 如上,块级元素的绘制和基础图形的绘制差异不大,理解起来也很容易,不再多述。 3.3 令人头疼的行内元素的绘制 当wxml的data-type声明为inline-image或者inline-text时,我们认为是行内元素。行内元素的绘制是一个难点,因为元素之前存在关联,所以不得不考虑各种临界情况。下面展开细述。 3.3.1 纯文本换行 对于长度超过一行的行内元素,需要计算出合适的换行位置,下图所示的是两种临界情况: [图片] [图片] 如上图所示,第一种情况为最后一行只有一个文字,第二种情况最后一行的文字长度和宽度相同。虽然长度不同,但都可通过下面代码绘制: [代码] let lineNum = Math.ceil(measureWidth(text) / maxWidth); // 文字行数 let sinleLineLength = Math.floor(text.length / lineNume); // 向下取整,保证多于实际每行字数 let currentIndex = 0; // 记录文字的索引位置 for(let i = 0; i < lineNum; i++) { let offset = 0; // singleLineLength并不是精确的每行文字数,要校正 let endIndex = currentIndex + sinleLineLength + offset; let single = text.substring(currentIndex, endIndex); // 截取本行文字 let singleWidth = measureWidth(single); // 超长时,左移一位,直至正好 while(singleWidth > maxWidth) { offset--; endIndex = currentIndex + sinleLineLength + offset; single = text.substring(currentIndex, endIndex); singleWidth = measureWidth(single); } currentIndex = endIndex; ctx.fillText(single, item.x, item.y + i * style.lineHeight); } // 绘制剩余的 if(currentIndex < text.length) { let last = text.substring(currentIndex, text.length); ctx.fillText(last, item.x, item.y + lineNum * style.lineHeight); } [代码] 为了避免计算太多次,首先算出大致的行数,求出每行的文字数,然后移位索引下标,求出实际的每行的字数,再下移一行继续绘制,直到结束。 3.3.2 非换行的图文混排 [图片] 上图是一个包含表情图片和加粗文字的混排内容,当使用Wxml2Canvas查询元素时,会将第一行的内容分为五部分: 文本内容:这是段文字; 表情图片:发呆表情(非系统表情,image节点展现); 表情图片:发呆表情; 文本内容:这也; 加粗文本内容:是一段文字,这也是文字。 对于这种情况,执行查询computedStyle后,会返回相同的top值。我们把top值相同的元素聚合在一起,认为它们是同一行内容,事实也是如此。因为表情大小的差异以及其他影响,默认规定top值在±2的范围内都是同一行内容。然后将top值的聚合结果按照left的大小从左往右排列,再一一绘制,即可完美还原此种情况。 3.3.3 换行的图文混排 当混排内容出现了换行情况时,如下图所示: [图片] 此时的加粗内容占据了两行,当我们依旧根据top值归类时,却发现加粗文字的left值取的是第二行的left值。这就导致加粗文字和第一部分的文字的top值和left值相同,如果直接绘制,两部分会发生重叠。 为了避免这种尴尬的情况,我们可以利用加粗文字的height值与第一部分文字的height值比较,显然前者是后者的两倍,可以得知加粗部分出现了换行情况,直接将其放在同组top列表的最后位置。换行的部分根据lineHeight下移绘制,同时做记录。 最后一部分的文本内容也出现了换行情况,同样无法得到真正的起始left值,并且其top值与上一部分换行后的top值相同。此时应该将他的left值追加加粗换行部分的宽度,正好得到真正的left值,最后再绘制。 大多数的行内元素的展现形式都能以上述的逻辑完美还原。 六、总结 基于基础图形封装和wxml转换这两种绘制方式,可以满足绝大多数的场景,能够极大地减少工作量,而不需要再关注内部实现。在实际使用中,二者并非孤立存在,而更多的是一起使用。 [图片] 如上图所示,对于列表内容我们利用wxml读取绘制,对于下部的白色区域,不是wxml节点内容,我们可以使用基础图形绘制方式实现。二者的结合更加灵活高效。 目前Wxml2Canvas已经在公司内部开源,不久会放到github上,同时也在不断完善中,旨在实现更多的样式展现与提升稳定性和绘制速度。 如果有更好的建议与想法,请联系我。
2019-02-28