- 微信访问网站被限制的相关问题
一、哪种行为或内容不应在朋友圈出现? 我们鼓励用户自发地分享所见所闻,但反对所有违反《微信外部链接内容管理规范》的内容或行为。 二、如果我的链接违反了《微信外部链接内容管理规范》将会被怎样处理? 对于违反《微信外部链接内容管理规范》的内容,一经发现将立即进行处理,包括但不限于停止链接内容在朋友圈继续传播、停止对相关域名或IP地址进行访问、屏蔽相关链接等。 由微信公众平台或开放平台帐号施行或者发起的,一经查实,前述帐号、主体也将按照微信相关规则进行处罚,包括但不限于限制或禁止使用部分或全部功能、帐号封禁直至注销等,并公告处理结果;微信也有权依照本规范及相关协议、专项规则的规定,拒绝再向前述主体提供服务。 三、我的链接被禁止在微信访问,如何才能恢复正常访问? [图片]注: 1、链接的封禁时间将根据链接的累计违规次数(最近半年)来判定。被禁止访问的链接若不发起解封申请,将不予解封。若出现解封申请的数量过多,审核团队无法较快处理的情况,对于超出封禁时间的链接,审核通过后立即解封。 2、首次违规的链接修改完可申请解封,经平台评估符合规范的链接可申请解除处理,第二次封禁12小时,第三次封禁一天,第四次及以上封禁一周。之后若未修改完成不予解封。对于重复、情节严重或多次违规的行为,平台将视具体情节采取不同程度的阶梯处罚措施。 四、我的链接在朋友圈分享了之后仅自己可见,怎么办? 1、若此域名未在工信部ICP备案,分享频率会受到限制,请先完成备案。点击这里了解详情。 2、请根据《微信外部链接内容管理规范》检查该页面所用的域名、IP地址下是否存在违规内容。若存在,请修改页面内容。 3、确认域名、IP地址不存在违规内容,可以通过电子邮件发送至腾讯指定邮箱:moment@tencent.com进行反馈。 邮件标题请采用如下格式: 【链接解封反馈】“反馈人或企业” + “页面主题” 正文请附上仅自己可见的链接以及情况说明。 Q:公众号发的图文消息是否受影响? A:微信公众号图文消息的域名是已备案域名:qq.com。因此,公众号推送的图文消息不受频率限制的影响。 Q:未备案域名分享频率是否会受到限制? A:未备案的一级域名每天分享至朋友圈的次数将有限制。 Q:不备案会出现什么情况? A:未备案域名,分享达一定次数后,再分享将仅自己可见。 Q:公众号阅读原文或编辑文案中插入了网址需要备案吗? A:阅读原文或文中插入的网址没有强制备案要求。若用户点击此网址后并将其分享到朋友圈,需遵循备案要求。 Q:为何个别域名已经备案了,在朋友圈还是分享仅自己可见? A:可查看该域名是否违反了《微信外部链接内容管理规范》,具体可点击查看:朋友圈管理常见问题 五、如果我的应用被禁止在朋友圈分享,如何才能解封? 1、请根据《微信外部链接内容管理规范》检查应用是否存在违规内容,若存在,请进行修改。 2、修改后,可以通过电子邮件发送至腾讯指定邮箱:moment@tencent.com申请解封。 注:若公众帐号功能被封禁,请按公众平台的相应提示等待解封,目前此邮箱(moment@tencent.com)不接受公众帐号解封申请。 邮件标题请采用如下格式: 【应用解封反馈】“反馈人或企业” + “应用名称” 正文请附上开放平台应用appid和分享链接,以及情况说明。 六、如果我的链接因被他人恶意利用生成违规内容而限制在微信内分享,怎么办? 1.点击“申请恢复访问”按钮,跳转“更多信息页”查看具体被恶意利用的链接; 2.根据违规链接核实被注入情况,修复漏洞,清理违规内容。(腾讯安全应急响应中心博客:xss漏洞解决方案https://security.tencent.com/index.php/blog/msg/53) 3.确认漏洞彻底修复后,提交解封申请。 被注入页面违规内容样式示例: [图片]
2019-11-21 - 微信号被封禁,无法正常使用
涉微信号封停问题我们无法核实具体情况,建议联系微信帐号客服处理。可通过任意微信客户端搜索小程序”腾讯客服“提交对应问题,等待客服答复即可。 腾讯客服电话:0755-83765566(服务时间09:00-22:00) 客服公众号:腾讯客服Tencent_KF 微信小程序:腾讯客服 微信支付客服:95017 客服帮助中心:http://kf.qq.com/index.html
2019-11-20 - 临时录音文件播放只能播放一次
录音结束后生成tempFilePath路径文件,第一次可以成功播放,播放成功后第二次点击 innerAudioContext.onPlay()捕获不了, innerAudioContext.onError()也捕获不了,是因为播放一次就把生成的临时文件清除了吗?tempFilePath对应的文件有效期是多少?有没有规定? [图片]
2018-09-19 - (20)长连开发经验分享
在微信小程序/小游戏的开发中,网络传输主要是依靠http的短连接和webSocket 长连接来完成的。 在一般web服务中,大多使用短连接来向服务器请求资源,与服务器的交互频率低,次数少。而在一些需要与服务器交互频繁,需要及时收到服务器推送的场景,比如直播、多人实时游戏,更适合使用 webSocket 进行通讯。 这次的小故事主要分享 webSocket 在微信小程序/小游戏开发上的一些经验。 长连的生命周期介绍 webSocket的生命周期一共有4个状态:connecting、open、closing、closed。我们可以通过 socketTask 的 readyState 属性来获取当前 webSocket 长连的状态。webSocket 的生命周期过程和 API 间的调用关系可以简单的入下图所示。 [图片] 注意:只有长连处在 open 状态,才能够正常的收发消息,其他状态均会报错。 客户端长连的断开机制 当小游戏进入到后台运行超过5秒时,客户端会禁止小游戏的所有网络连接。这是一个非常频繁的断线逻辑,十分考验程序断线错误处理逻辑。建议大家可以在用户点击右上角按钮退出小程序/小游戏时,主动帮用户断线,待用户切回时再重接上去。 当 webSocket 长连超过一段时间没有任何网络传输时,客户端会主动关闭这条长连,以节省资源。开发者可以设置业务心跳,每隔一段时间与后台进行一次通讯,维持长连。 如何选择长连的接口 API接口主要有两类,一类是前缀为 “wx” 的接口,一类 “socketTask” 的接口。举例,同样是连接长连后发送一条消息,两种写法区别如下。 [图片] 最初小游戏只允许存在1个 webSocket 连接时,并没开放 socketTask 的管理方式。随着小游戏的能力提升,可支持同时存在的 webSocket 连接个数变多,在使用 wx.connectSocket 创建 webSocket 连接时会返回 socketTask 任务对象,便于去管理每一条连接链路。 推荐开发者尽量使用 socketTask 的方式去管理 webSocket 链接,每一条链路的生命周期都更加可控。同时存在多个 webSocket 的链接的情况下使用 wx 前缀的方法可能会带来一些和预期不一致的情况。例如:当存在多条连接时,wx.onSocketOpen、wx.sendSocketMessage、wx.onSocketMessage 等接口会只作用于第一条连接的长连。且wx.onSocketOpen 接口不能多次注册 webSocket 长连的回调函数,仅最后一次生效。使用 socketTask 任务的方式则不会出现上述问题。 开发与调试的建议 01微信提供了 webSocket 最基础的接口能力,开发者可以在其基础上进行封装,根据业务需要扩展能力。比如封装一个 offSocketOpen 的方法来取消注册 socketOpen 的回调函数。 02 长连并没有像短连那样“一问一答”的交互形式。在某些场景下,开发者需要这种与服务器的交互。建议前端与后台协议,每条客户端上行的信息,服务器都下发一个对应的回包,去“模拟短连”。比如开发者向服务器询问1+1和1+2等于多少,服务器返回了3和2,便可清晰知道哪一个数字对应着哪一个请求的答案。此外,还可以设置业务超时逻辑,便于判断上传是否丢包 03 在 webSocket 发送数据时,数据格式可以选择string或者ArrayBuffer。这里要注意的是,由于小游戏禁止了 Function() 和 eval()语法。所以像 protobufjs 这类用了这些语法的库是不能直接拿来用的。 04 在测试调试长连的时,目前开发者工具不支持通过设置 offline 模拟长连断网的情况(短连是支持的),所以在测试断线重连的一些情况时,可以辅助一些第三方工具,或者用真机调试以及“拔网线”的方式来测试。 05 在进行多人游戏测试时,在开发者工具中熟练使用“自定义编译条件”,以及“多账号调试”这两个功能可以极大的提升开发测试效率。 06 长连占用的系统资源,会导致手机发热比较明显。所以在不需要使用 webSocket 的场景下,建议及早断开长连,需要时再连接。 异常断线的监控 监控长连是否异常断线,在长连的使用中,尤其在小游戏多人对战中是尤为重要的。socketError 事件并不能认为是异常断线。 首先 socketError 事件并不一定会导致断线,其次若是由客户端机制断开的长连,是不会触发 socketError 事件的。 最简单的方式可以通过 onClose 回调函数触发时系统传入的 code 是否为1000来判断。当然开发者自身也可以通过代码判断是否是自身调用的 close 函数触发的 onclose 事件,监控异常断线。 希望大家在实际应用中能帮助到到大家。
2018-09-29 - (21)独立分包与分包预下载
在「小程序 · 小故事」的第一期,我们曾和大家一起分享过「分包加载」的故事。随着小程序功能越来越多样,页面也越来越多,但不同页面的访问频率是有一定差异的。 分包加载允许开发者将小程序划分为主包和若干个分包,将较少用到的页面或功能划分到若干个分包中,主包内只保留最频繁使用的页面和公共的代码。小程序启动时默认只加载主包,再按需加载分包。这一机制保证了在小程序包大小增加的情况下,依然能保持良好的启动速度。 为满足小程序承载的功能不断丰富的需要,小程序的代码包大小上限已提高到 8M。随着小程序应用场景和使用范围的扩大,在实践中,我们发现分包加载仍有一定的局限性。尤其是越来越多的 H5 服务迁移到小程序后,对于小程序的启动速度有更高要求。为了更好的提升小程序的加载速度和使用体验,小程序近期开放了「独立分包」和「分包预下载」两个新的能力,进一步丰富了分包加载的功能和使用场景。 01独立分包 1 技术背景 由于技术实现的差异,小程序首次启动时需要进行代码包的下载,因此在启动性能上与网页相比有一定劣势。通过对小程序启动耗时的分析,我们发现代码包大小对小程序启动速度是有最直接的影响。 一方面,代码包越大,下载时间就越长; 另一方面,代码包越大,通常意味着小程序页面结构和代码逻辑复杂,启动时代码注入执行的时间越长。 采用分包加载一定程度上解决了代码包下载耗时过长的问题。但小程序中的某些场景(如广告页、活动页、支付页等),通常功能不是很复杂且相对独立,对启动性能有很高的要求。在现有方案中,启动这一页面需要依赖整个主包的下载,如果页面在分包中,还需等待分包的下载,启动性能有严重的瓶颈。此时如果依赖开发者进行代码重构,重新分包,不仅工作量大,而且会影响其他分包的使用体验。为了解决这一问题,我们提出了「独立分包」方案。 2 功能简介 独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。 开发者可以将部分对启动性能要求很高的页面放到特殊的独立分包中。当小程序从独立分包页面启动时,只需要下载分包就可以直接运行,可以很大程度上提高分包页面的启动速度,实现小程序的秒开。 [图片] 由于小游戏中没有页面的概念,也没有小程序中多种入口的使用场景,因此小游戏目前没有支持独立分包。 3 配置方法 独立分包的配置方法十分简单,只需要在原有分包配置的基础上定义 independent 字段,即可将一个分包设置为独立分包,例如: [图片] 4 使用限制 独立分包虽然属于分包的一种,但其不依赖主包独立使用,因此在加载流程和运行环境上与普通分包相比有一些差异。除了分包本身的限制外,独立分包还有以下限制: ● 独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、模板、wxss、自定义组件等; ● App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为; ● 独立分包中暂时不支持使用插件。 为了小程序有更好的使用体验,我们不建议开发者把过多的小程序逻辑放置到独立分包中,也不建议在小程序中过度的使用独立分包,例如把每个页面都放到一个独立分包中。 关于独立分包的详细内容请参见 独立分包 · 小程序 02 分包预下载 1 技术背景 在使用「分包加载」后,虽然能够显著提升小程序的启动速度,但是当用户在使用小程序过程中跳转到分包内页面时,需要等待分包下载完成后才能进入页面,造成页面切换的延迟,影响小程序的使用体验。分包预下载便是为了解决首次进入分包页面时的延迟问题而设计的。如果能够在用户进入分包页面之前就预先将分包下载完毕,那么进入分包页面的延迟就能够尽可能降低。 此前,小游戏中已经提供了「基于API」的分包预下载能力。在设计小程序分包预下载能力时,我们设计了「基于配置」和「基于API」两种分包预下载形式,「基于配置」的方式使用简单,且便于对预下载的使用情况进行控制,防止开发者滥用;「基于API」的方式使用起来更灵活,能够动态的调整预下载策略。综合考虑用户的使用感受和内测阶段第三方开发者的反馈后,我们最终决定首先推出「基于配置」的分包预下载能力。 2 功能简介 开发者可以预先配置某个页面可能会跳转到的分包(对于独立分包,也可以预下载主包),在进入小程序某个页面时,由基础库在后台自动预下载可能需要的分包。用户在进行页面跳转时,分包通常已经下载完成,不需要额外等待,可以有效提升进入后续分包页面时的启动速度。此外,考虑到用户的流量和存储空间,小程序也会对预下载的大小和网络进行一定的限制。 [图片] 3 配置方法 开发者可以通过在 app.json 中增加 preloadRule 字段,控制进入某个页面时进行预下载的分包,并设置触发预下载的网络环境。 [图片] [图片] 4 使用限制 对于手机用户而言,数据流量和存储空间是非常重要的资源。一方面,分包预下载能够提升小程序用户的使用体验;另一方面,过度的预下载也会破坏分包按需使用的原则,过度的占用用户的存储空间,消耗数据流量。如果开发者每次启动小程序时都将所有分包进行下载,会消耗很多不必要的流量和存储空间。 为了在分包预下载的效果和对用户资源的消耗上取得平衡,我们限制了同一个分包中的页面预下载总大小不得超过2M,并鼓励开发者按需设置分包预下载的网络条件。 关于独分包预下载详细内容请参见 分包预下载 · 小程序 03 小结 独立分包与分包预下载进一步丰富了分包加载的功能,大大拓展了分包加载的使用场景。同时,独立分包和分包预下载是相辅相成的,配合使用可以获得更好的效果。 例如,开发者可以将一个活动推广页放到一个独立分包中,利用独立分包的特性能够提升活动页面的加载速度,提升转化率。在页面中开发者可以引导有需要的用户跳转到小程序其他页面,使用小程序的更丰富的功能。在这一过程中,可以利用分包预下载能力,将主包或相关分包进行预下载,降低页面跳转的延迟,留住更多用户。 开发者在使用这两个新能力的过程中,如果遇到问题或者有什么建议,欢迎在微信开放社区(https://developers.weixin.qq.com)进行反馈,我们会根据开发者的反馈,不断的优化和丰富分包加载功能,减少功能限制,提升小程序的加载性能和使用体验。
2018-10-14 - 小程序应用官方上下拉刷新示例
在实际开发中,我在wxml文件布局中,主要有数据遍历列表,是否有记录提示,加载提示。 layer-top 和 layer-bottom 块补充主要是因为小程序整个页面刷新端是page,因此layer-top,layer-bottom补充才有利于上拉加载减少误差。 pageLoading 主要用于页面加载数据缓慢,出现假数据的情况,设置新的数据多少会出现延时的,当延时再重新切换正常数据,用户视觉体验会有些不好。 [代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"g-doc" hidden = "{{pageLoading}}"[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"g-hd"[代码][代码]>[代码][代码] [代码][代码]tab[代码][代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"g-bd"[代码][代码]>[代码][代码] [代码][代码]<!-- layer-top 等同于 g-hd的高度 -->[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"layer-top"[代码][代码]></[代码][代码]view[代码][代码]> [代码][代码] [代码][代码]<[代码][代码]block[代码] [代码]wx:if[代码] [代码]= [代码][代码]"{{dataList.length}}"[代码][代码]>[代码][代码] [代码][代码]<block [代码][代码]wx:for[代码] [代码]= [代码][代码]"{{dataList}}"[代码] [代码]wx:key[代码] [代码]= [代码][代码]"*this"[代码][代码]>[代码][代码] [代码][代码]{{item}}[代码][代码] [代码][代码]</[代码][代码]block[代码][代码]>[代码][代码] [代码][代码]<!-- 加载条 start -->[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loadmore"[代码] [代码]hidden[代码][代码]=[代码][代码]"{{!loadBar.Loading}}"[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loading"[代码][代码]></[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loadmore__tips"[代码][代码]>加载中</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码][代码] [代码] [代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loadmore"[代码] [代码]hidden[代码][代码]=[代码][代码]"{{loadBar.Loading}}"[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loadmore__tips"[代码] [代码]hidden[代码][代码]=[代码][代码]'{{!loadBar.more}}'[代码][代码]>加载更多</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"weui-loadmore__tips"[代码] [代码]hidden[代码][代码]=[代码][代码]'{{loadBar.more}}'[代码][代码]>没有更多了</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]<!-- 加载条 end -->[代码][代码] [代码][代码]</[代码][代码]block[代码][代码]>[代码][代码] [代码][代码]<[代码][代码]block[代码] [代码]wx:else>[代码][代码] [代码][代码]暂无记录[代码][代码] [代码][代码]</[代码][代码]block[代码][代码]>[代码][代码] [代码][代码]<!-- layer-top 等同于 g-ft 的高度 -->[代码] [代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"layer-bottom"[代码][代码]></[代码][代码]view[代码][代码]>[代码] [代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码] [代码] [代码][代码]<[代码][代码]view[代码] [代码]class[代码][代码]=[代码][代码]"g-ft"[代码][代码]>[代码][代码] [代码][代码]add[代码][代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码][代码] [代码][代码]</[代码][代码]view[代码][代码]>[代码]在JSON中 [代码]{[代码] [代码]"enablePullDownRefresh": true,[代码] [代码]"backgroundTextStyle": "dark",[代码][代码]"navigationBarBackgroundColor": "#fff",[代码][代码]"navigationBarTitleText": "单页",[代码][代码]"navigationBarTextStyle": "black",[代码] [代码]}[代码] 在js中 [代码]var[代码] [代码]onLoadNumber = 1;[代码][代码]Page({[代码][代码] [代码][代码]data: {[代码][代码] [代码][代码]pageLoading: [代码][代码]true[代码][代码],[代码][代码] [代码][代码]page: 1,[代码][代码] [代码][代码]pageSize: 20,[代码][代码] [代码][代码]dataList: [[代码][代码] [代码][代码]// {}[代码][代码] [代码][代码]],[代码][代码] [代码][代码]loadBar:{[代码][代码] [代码][代码]Loading:[代码][代码]false[代码][代码],[代码][代码] [代码][代码]more:[代码][代码]true[代码][代码] [代码][代码]}[代码][代码] [代码][代码]},[代码][代码] [代码][代码]onLoad: [代码][代码]function[代码] [代码](options) {[代码][代码] [代码][代码]var[代码] [代码]self = [代码][代码]this[代码][代码];[代码] [代码] [代码][代码]try[代码] [代码]{[代码] [代码] [代码][代码]self.dataLayer();[代码] [代码] [代码][代码]setTimeout(()=>{[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]pageLoading: [代码][代码]false[代码][代码] [代码][代码]})[代码][代码] [代码][代码]},300)[代码] [代码] [代码][代码]} [代码][代码]catch[代码] [代码](e) {[代码][代码] [代码] [代码] [代码][代码]}[代码] [代码] [代码][代码]},[代码][代码] [代码][代码]/**[代码][代码] [代码][代码]*下拉刷新[代码][代码] [代码][代码]**/[代码][代码] [代码][代码]onPullDownRefresh: [代码][代码]function[代码] [代码]() {[代码][代码] [代码][代码]var[代码] [代码]self = [代码][代码]this[代码][代码];[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]page: 1[代码][代码] [代码][代码]});[代码][代码] [代码][代码]self.dataLayer([代码][代码]function[代码] [代码](isData) {[代码][代码] [代码][代码]setTimeout(() => {[代码][代码] [代码][代码]wx.stopPullDownRefresh() [代码][代码]//停止下拉刷新[代码][代码] [代码][代码]}, 800);[代码][代码] [代码][代码]});[代码][代码] [代码][代码]},[代码][代码] [代码][代码]dataLayer: [代码][代码]function[代码] [代码](callback) {[代码] [代码] [代码][代码]var[代码] [代码]self = [代码][代码]this[代码][代码];[代码] [代码] [代码][代码]var[代码] [代码]url = [代码][代码]"api/api.do"[代码][代码];[代码] [代码] [代码][代码]var page = self.data.page;[代码][代码] [代码][代码]var pageSize = self.data.pageSize;[代码] [代码] [代码][代码]let data = {[代码][代码] [代码][代码]page: page,[代码][代码] [代码][代码]pageSize: pageSize,[代码][代码] [代码][代码]}[代码] [代码] [代码][代码]var[代码] [代码]loadBar = self.data.loadBar || {};[代码][代码] [代码][代码]loadBar.Loading = [代码][代码]true[代码][代码]; [代码][代码]// 加载中[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]loadBar: loadBar[代码][代码] [代码][代码]});[代码] [代码] [代码] [代码] [代码][代码]wx.request({[代码][代码] [代码][代码]url: url,[代码][代码] [代码][代码]data: data,[代码][代码] [代码][代码]header: {[代码][代码] [代码][代码]'content-type'[代码][代码]: [代码][代码]'application/json'[代码] [代码]// 默认值[代码][代码] [代码][代码]},[代码][代码] [代码][代码]method: [代码][代码]"GET"[代码][代码],[代码][代码] [代码][代码]success: [代码][代码]function[代码] [代码](res) {[代码][代码] [代码] [代码] [代码][代码]loadBar.Loading = [代码][代码]false[代码][代码]; [代码][代码]// 加载完毕[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]loadBar: loadBar[代码][代码] [代码][代码]})[代码] [代码] [代码][代码]let data = res.data; [代码][代码]// { object :{ rows:[] ,records:0}}[代码][代码] [代码][代码]let obj = data.object || {};[代码][代码] [代码][代码]let rows = obj.rows || [];[代码] [代码] [代码][代码]let isData = (pageSize >= rows.length) ? [代码][代码]true[代码] [代码]: [代码][代码]false[代码][代码];[代码][代码] [代码][代码]var[代码] [代码]records = obj.records;[代码] if (!rows.length){ if(page> 1){ isData = false; } } [代码] [代码][代码]if[代码] [代码](!!callback) {[代码][代码] [代码][代码]callback(isData);[代码][代码] [代码][代码]}[代码] [代码] [代码][代码]if[代码] [代码](page > 1) {[代码][代码] [代码][代码]let dataList = self.data.dataList;[代码][代码] [代码][代码]let newRows = dataList.concat(rows);[代码][代码] [代码][代码]loadBar.more = !(records <= newRows.length); [代码][代码]// 判断是否还有数据[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]dataList: newRows,[代码][代码] [代码][代码]loadBar: loadBar [代码][代码] [代码][代码]});[代码] [代码] [代码][代码]} [代码][代码]else[代码] [代码]{[代码] [代码] [代码][代码]loadBar.more = !(records <= rows.length); [代码][代码]// 判断是否还有数据[代码][代码] [代码][代码]self.setData({ [代码][代码] [代码][代码]dataList: rows,[代码][代码] [代码][代码]loadBar: loadBar[代码][代码] [代码][代码]});[代码][代码] [代码][代码]}[代码][代码] [代码][代码]},[代码][代码] [代码][代码]fail: [代码][代码]function[代码] [代码](err) {[代码][代码] [代码][代码]if[代码] [代码](!!callback) {[代码][代码] [代码][代码]callback();[代码][代码] [代码][代码]}[代码][代码] [代码][代码]}[代码][代码] [代码][代码]});[代码] [代码] [代码][代码]},[代码][代码] [代码][代码]/**[代码][代码] [代码][代码]上拉加载 [代码] [代码] [代码][代码]**/[代码][代码] [代码][代码]onReachBottom: [代码][代码]function[代码] [代码]() {[代码] [代码] [代码][代码]var[代码] [代码]self = [代码][代码]this[代码][代码];[代码] [代码] [代码][代码]var[代码] [代码]page = self.data.page;[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]page: ++page[代码][代码] [代码][代码]})[代码] [代码] [代码][代码]let pageSize = self.data.pageSize;[代码][代码] [代码][代码]let dataList = self.data.dataList;[代码][代码] [代码][代码]if[代码] [代码](dataList.length < pageSize) {[代码][代码] [代码][代码]console.log([代码][代码]"数量太小,不需要上拉"[代码][代码])[代码][代码] [代码][代码]return[代码] [代码]false[代码][代码];[代码][代码] [代码][代码]}[代码] [代码] [代码][代码]self.dataLayer([代码][代码]function[代码] [代码](isData) {[代码][代码] [代码][代码]if[代码] [代码](!isData) {[代码][代码] [代码][代码]// 没有数据应减回去[代码][代码] [代码][代码]self.setData({[代码][代码] [代码][代码]page: --page[代码][代码] [代码][代码]})[代码][代码] [代码][代码]}[代码][代码] [代码][代码]});[代码] [代码] [代码][代码]},[代码][代码]});[代码] css 可参考,毕竟业务开发中css还是有所差异的 [代码].g-doc, page {[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]height[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]position[代码][代码]: [代码][代码]relative[代码][代码];[代码][代码]}[代码] [代码].g-doc {[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]height[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]position[代码][代码]: [代码][代码]relative[代码][代码];[代码][代码] [代码][代码]display[代码][代码]: -webkit-box;[代码][代码] [代码][代码]-webkit-box-orient: vertical;[代码][代码] [代码][代码]flex-flow: column;[代码][代码]}[代码] [代码].layer-[代码][代码]top[代码] [代码]{[代码][代码] [代码][代码]height[代码][代码]: [代码][代码]50px[代码][代码];[代码][代码]}[代码] [代码].layer-[代码][代码]bottom[代码] [代码]{[代码][代码] [代码][代码]height[代码][代码]: [代码][代码]50px[代码][代码];[代码][代码]}[代码] [代码].g-bd {[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]background[代码][代码]: [代码][代码]transparent[代码][代码];[代码][代码] [代码][代码]-webkit-box-flex: [代码][代码]1[代码][代码];[代码][代码] [代码][代码]flex: [代码][代码]1[代码][代码];[代码][代码] [代码][代码]margin-bottom[代码][代码]: [代码][代码]50px[代码][代码];[代码][代码]}[代码] [代码].g-ft {[代码][代码] [代码][代码]width[代码][代码]: [代码][代码]100%[代码][代码];[代码][代码] [代码][代码]bottom[代码][代码]: [代码][代码]0[代码][代码];[代码][代码] [代码][代码]position[代码][代码]: [代码][代码]fixed[代码][代码];[代码][代码]}[代码]例图: [图片][图片]
2019-05-14 - 微信3D小游戏下HUD绘制的经验分享
平视显示器(head up display)简称HUD。游戏经常在三维场景上叠加文本或二维图形信息,如弹窗,血量条等,同时需要保证它们在屏幕上的位置和大小不变。 传统的H5游戏可以使用dom,或是在原本的webgl上面盖一个新的2D canvas(画布)做为HUD来实现,同时使用其接口就可以画出HUD所需要的内容。 但微信小游戏只支持一个画布,无法和传统H5游戏的绘制方式一样。因此,要在3D世界中实现HUD就必须在这个唯一的画布上实现。 我们在后台收到了许多反馈:如何用小游戏的框架来实现HUD的绘制。这一期的小故事,我们跟大家分享如何在微信3D小游戏中绘制HUD: 本文的内容包括: 1.微信小游戏只支持一个画布 2.如何使用三维平面模拟HUD? 3.相机变化导致HUD产生位移缩放 4.如何用图形渲染管线解决上述问题? 5.绘制场景时视点变化与投影阶段的问题 6.如何使用顶点着色器解决上述问题? 微信小游戏只支持一个画布 与浏览器不同,微信客户端只有一个画布,并且不能使用html。 普通H5游戏会使用html,或是创建一个新的2D canvas标签,定位在原本的webgl canvas上面,同时使用2D canvas的接口就可以画出HUD的内容。但微信小游戏不支持这样做。所以在三维世界中要实现HUD,需要在一个画布上实现。 所以在三维世界中要实现HUD,则必须在这个唯一的画布上实现。 如何使用三维平面模拟HUD? 对于图像,webgl可以通过纹理贴图来展示图像。开发者可将图片作为的纹理贴图,贴在一个三维矩形平面上,使平面一直正对相机,来模拟HUD。 [图片] 对于文字,微信小游戏三维的canvas是使用webgl作为context的。但是webgl却无法像2D的context能直接画文字。开发者如果直接用webgl画出文字,需要导入文字模型的顶点数据,但由于文字比较复杂,顶点数量多,相当于渲染了一个复杂的3D物体,这种方式无论是从文件大小还是性能上,都会有损体验。 [图片] 那么是否可以使用2D canvas 绘好文字,再作为纹理贴在三维平面上呢? 虽然微信小游戏只能渲染一个canvas,但是开发者可以创建多个的canvas实例。 Step1:开发者可创建一个离屏的2D canvas,再使用2D的接口绘制文字、图片等; Step2:开发者可将这个离屏canvas传给webgl,当成一个texture,贴到一个三维的平面物体上,使其永远都在相机的正前方,通过这样模拟HUD 。 补充 webgl支持直接将canvas作为纹理; void gl.texImage2D(target, level, internalformat, format, type, HTMLCanvasElement? pixels)。 [图片] 相机变化导致HUD产生位移缩放 游戏场景中的相机是会改变的,比如说吃鸡游戏中的第一人称和第三人称视角转化。我们发现了一个问题:当相机的可视范围变化的时候,HUD就会发生形变。 [图片] 那是因为视野看的越广,映射到屏幕上的时候,同一个物体就显得越小。 我们需要保证HUD在任何视角下位置大小都是正确无误的。那么如何才能做到呢? 要解决这个问题就需要明白计算机是如何把三维场景画到二维的屏幕上的。这个画的过程也就是计算机图形渲染管线帮我们完成的。 如何用图形渲染管线解决上述问题? 画一个三维物体到二维平面可以分为三个阶段: ●“准备数据” (应用程序阶段) ●“画点” (几何阶段) ●“画像素” (光栅化阶段) [图片] 一个HUD实际上是一个矩形的平面物体,通过矩形的4个顶点就可以描述出来一个平面的位置、大小。为了让平面的位置,大小看起来没问题,我们需要修改“画点”阶段的逻辑。这个阶段又可以进行如下的细分。 [图片] 与摄影机相关的逻辑,是视点变换还有投影阶段。我们可以通过修改这两者的逻辑来达到我们的目的。 绘制场景时视点变化与投影阶段的问题 1.视点变化阶段的问题 我们需要绘制摄像机看到的世界,而摄像机可以处在任意位置观察这个世界。视点变化本质是就是根据摄像机看的方向来旋转物体,从而让三维空间的物体正确旋转到观察者看到的样子。原本是摆正放的物体,由于观察者的视角问题(歪着看),所以显示出来物体最终也是歪的。 [图片] 通过在应用程序阶段定义相机的视点、观察目标点以及上方向等数据,我们可以得到一个叫做视图矩阵(View Matrix)的矩阵。把这个矩阵与物体的位置做矩阵乘法就可以得到物体变化后的新位置。 因为游戏世界中,摄像机的位置是不停变化的,而我们的物体却需要一直出现在摄像机正前方。所以游戏场景中的视觉矩阵(View Matrix)在每一帧的渲染中,可能都在变化。这里我们只要将HUD原本一直在变化的视觉矩阵(View Matrix)替换为我们需要的,并且保持不变就好了。 2.投影阶段的问题 投影其实是把透视摄像机原本的可视范围,压缩成一个单位立方体。 [图片] 再通过屏幕映射,就会出现如下的效果出来。 [图片] 这一个过程中,会通过摄像机定义的数据(比如长宽比,视场,近截面,远截面),来生成一个叫做投影矩阵(Projection Matrix)的矩阵。将这个矩阵与位置信息进行矩阵乘法,再进行一些归一化操作,就会得到单位立方体内的位置。 和视觉矩阵(View Matrix)一样,对于HUD的物体,我们也不能使用透视摄像机生成的矩阵,否则就会可能导致大小变化。我们替换成正视摄像机的矩阵。这样算出来的位置就是永远都是正常的,不需要担心游戏中更新了相机的数据。 如何使用顶点着色器解决上述问题? 现在我们要用顶点着色器来修改视点变换还有投影的逻辑。 顶点着色器与片元着色器都是 webgl 提供给我们用来操作渲染管线的能力。让我们可以使用glsl 这种编程语言来对 GPU 的能力进行编程。 [图片] 顶点着色器运行在“画点”阶段(几何阶段),也就是对每个三维物体的顶点进行计算。片元着色器运行在“画像素”阶段(光栅化阶段),把顶点围起来的像素(其实是片元)画上颜色。 我们可以通过顶点着色器,修改视点变换与投影的逻辑,最后达到我们的效果。 总结 由于微信小游戏支持一个单独的画布,开发者想要在任何游戏场景下绘制正常的HUD,可以通过顶点着色器的能力,去修改视点变换与投影的所用到的矩阵,最终来解决这个问题。 微信小游戏还有很多与H5游戏、客户端游戏不一样的设计理念与特点,我们会在后续的文章里继续分享微信小游戏背后的小故事。
2018-09-25 - 小游戏的canvas能否做成双缓冲?
就是提供另外一个可以绘制的canvas或者image之类的,主要想解决 在每帧刷新的时候 只绘制这个缓冲区的内容, 缓冲区内容由游戏逻辑自行绘制! 不知道这个怎么实现?求解
2018-11-23 - 【已解决】cocos这小妖精,看不上iOS12,息屏再次打开会导致微信崩溃
泪奔了,用cocos 引擎开发的小游戏,在iOS12上,出现bug。bug:手机息屏(主动锁屏,或手机自动息屏),过了1秒钟在打开小游戏,小游戏卡死,微信会崩溃。 我想的: 实在不行,能不能,在锁屏后,退出小游戏,避免再次打开会导致微信崩溃。锁屏后,如何触发动作呢? 坊间传闻,有cocos的小游戏,已经解决了该问题。 我cocos社区和百度了一圈,没找到成功案例, @小伙伴们,求推荐! @小伙伴们! 解决办法见2楼,感谢Raing
2019-01-22 - 苹果无法播放m3u8格式视频,安卓机下可以
视频流测试的地址是:http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8 在苹果手机中,video组件无法播放视频,在安卓手机上可以
2018-11-21 - ios系统设置wx.setKeepScreenOn无效
ios系统设置 [代码]wx.setKeepScreenOn({[代码][代码] keepScreenOn: true[代码] [代码]})[代码] 无效,依然会息屏,无法保持屏幕常亮,希望处理!
2017-12-06 - 小程序注册相关问题
Q1:小程序如何注册? A:请见链接:http://kf.qq.com/faq/170109iQBJ3Q170109JbQfiu.html Q2:小程序主体上限为多少? A:请见链接:http://kf.qq.com/faq/170109F3MRFj170109eYJ7fi.html Q3:小程序注册主体验证方式 A:请见链接:http://kf.qq.com/faq/170109QvMNRB170109nYnYFr.html Q4:小程序基本信息填写 A:请见链接:http://kf.qq.com/faq/170109nQRFJb170109fi6JJR.html Q5:小程序名称设置规范 A:请见链接:http://kf.qq.com/faq/170109umMvm6170109MZNnYV.html Q6:小程序企业开放哪些服务类目? A:请见链接:http://kf.qq.com/faq/170926eiqeiy170926QJVRje.html Q7:小程序特殊行业相关约定。 A:请见链接:https://developers.weixin.qq.com/miniprogram/product/material.html?t=18080816 Q8:如何申请ICP备案? A:请见链接:http://kf.qq.com/faq/180123AZnmEZ180123zIFR3Q.html Q9:如何申请《增值电信业务经营许可证》或《电信与信息服务业务经营许可证》? A:请见链接:http://kf.qq.com/faq/180202bee2Er180202i2QzIJ.html
2018-09-25 - userAvatarUrl不支持圆形效果?
最近wx.getUserInfo接口即将下线,我打算改成open-data的方式,但发现采用之后,原来的头像圆形效果怎么也出不来,代码如下: <view class="img_radius"><open-data type="userAvatarUrl"></open-data></view> .img_radius{ width: 100rpx; height: 100rpx; border-radius: 100rpx; } 之前用的这种方式: <image src="{{headImg}}" class="img_radius"></image> 头像就是圆形的。 看看怎么弄才能兼容原来的设计呢?
2018-04-23 - 小程序开发工具强制 GIT 提交
[图片]遇到的问题在小程序开发过程中,代码提交突然变成了一件非常头疼的事情。因为小程序的开发、编译、预览到最后的上传发布过程中,任何一步其实都和 Git 没有任何关系。所以之前自己一个人开发的时候,经常性的就忘记了 commit 代码,亦或是 commit 了但是没有对远端进行 push 操作。一个人开发的时候还好,多个人开发的时候再是这种操作习惯可就要把人坑惨了。 另外还有一个问题是,小程序的发布对 Git 没有强相关,所以对代码分支的要求不高。一般说来,日常的 Web 开发中,我们都是在 [代码]dev[代码] 或者 [代码]feature/xxx[代码] 分支中进行开发,[代码]test[代码] 分支进行测试,最后 [代码]master[代码] 分支合并后上线。能够严格的执行这个过程的最重要的原因是因为我们的发布系统只支持从主分支上拉取代码,强制让大家养成了良好的习惯。但是小程序中没有这种强相关,所以会经常导致主分支不是最新的版本,而可能是某个其它分支才是线上最新代码。长久以往下去,可能没有同学能够清楚最新的代码是在哪个分支了,一不小心就把分支给删除了也有可能。 解决方法虽然说微信开发者工具目前已经内嵌了版本管理功能,但是我试了一下似乎并不能解决我的问题。后来我发现小程序是支持自定义预处理命令的,提供了 [代码]beforeCompile[代码],[代码]beforePreview[代码] 和 [代码]beforeUpload[代码] 三个预处理钩子,分别在编译前、预览前和上传前触发。所以我就想利用这个钩子,在上传前判断当前仓库的状态,如果不符合要求就阻止上传。目前我主要是做以下三种操作: 判断当前仓库是否有代码没有 commit,避免上线的版本有未提交的代码 判断当前仓库是否是 master 分支,避免上线的版本非主分支代码 推送当前分支代码到远端,避免其它协作者无法拉取到线上最新的代码 具体的代码如下: [代码]#! /usr/bin/env sh[代码][代码]# 检查分支是否为主分支[代码][代码]br_name=$(git symbolic-ref --short HEAD);[代码][代码]if[代码] [代码][ $br_name != [代码][代码]"master"[代码] [代码]][代码][代码]then[代码][代码] [代码][代码]echo[代码] [代码]"[错误]当前分支名为 $br_name 但是上传包必须是在 master 分支"[代码][代码];[代码][代码] [代码][代码]exit[代码] [代码]42;[代码][代码]fi[代码][代码]# 检查分支上是否有未提交的代码[代码][代码]if[代码] [代码][[ ! -z $(git status --porcelain) ]][代码][代码]then[代码][代码] [代码][代码]echo[代码] [代码]"[错误]你有未提交的代码,上传包前请将代码提交到仓库"[代码][代码];[代码][代码] [代码][代码]exit[代码] [代码]42;[代码][代码]fi[代码][代码]# 最后自动提交到远端仓库[代码][代码]git push;[代码] 其中 [代码]exit 42[代码] 表示是异常退出,微信开发者工具监听到异常退出后会中止上传进程,你也可以是别的非0错误号,更多的错误号可以查看 torvalds/linux 仓库。 最后我们还需要在[代码]微信开发者工具-详情[代码]中勾选[代码]启用自定义处理命令[代码],并在上传前预处理中输入 [代码]./bin/beforeUpload[代码] 地址,该地址即为刚才你的脚本所在位置。如果是修改 [代码]project.config.json[代码] 文本内容添加的,还是需要在微信开发者工具中手动勾选下[代码]启动自定义处理命令[代码],默认开发者工具是不开启这个选项的(来源)。 [图片] [代码]{[代码][代码] [代码][代码]"scripts"[代码][代码]: {[代码][代码] [代码][代码]"beforeCompile"[代码][代码]: [代码][代码]""[代码][代码],[代码][代码] [代码][代码]"beforePreview"[代码][代码]: [代码][代码]""[代码][代码],[代码][代码] [代码][代码]"beforeUpload"[代码][代码]: [代码][代码]"./bin/beforeUpload"[代码][代码] [代码][代码]}[代码][代码]}[代码]后记设置完毕之后,当你不符合条件的时候就会报错,从而达到了我强制与 Git 绑定的需求,避免线上代码在某个同学的本地停留,保证远端代码与线上代码的一致性。当然有了这些钩子,你也可以做更多有趣好玩的事情,欢迎大家分享。 [图片] 若想了解更多内容,可跳转至:https://imnerd.org/miniprogram-force-git-commit.html
2018-10-28 - 小程序分享及用户信息授权等接口能力的调整通知
针对近期部分小程序接口能力使用不合理的情况,微信公众平台将对下列能力进行调整。开发者可在最新版开发者工具内,选择最新基础库版本体验。调整方案具体如下,请开发者尽快完成适配。 1、分享监听接口 10月10日起新提交的版本,用户从小程序、小游戏中分享消息给好友时,开发者将无法获知用户是否分享完成,也无法在分享后立即获得群ID。请参考调整指引 2、getUserInfo接口 10月10日起新提交的版本,用户在小程序、小游戏中需要点击组件后,才可以触发登录授权弹窗、授权自己的昵称头像等数据。请参考调整指引 3、openSetting接口 10月10日起新提交的版本,用户在小程序、小游戏中需要点击行为后,才可以跳转打开设置页,管理授权信息。请参考调整指引
2018-09-12