个人案例
前端XR
小程序元宇宙~
前端XR扫码体验
ELSE IF
国庆头像挂国旗
ELSE IF扫码体验
ELSE前端
ELSE前端扫码体验
- 第一个小游戏做完了,源码已分享,另附完整开发教程
从4月27号,我发布了“微信小游戏实战系列”的第一篇文章,也是我的第一个小游戏正式开始制作的时间,之前它只是一个脑袋中的想法,大概类似于这样:我能不能试着做这样的一系列的游戏呢?它们有着经典的玩法,不会过时,仍然有着很多的受众,如果我把一个经典的小游戏做成一个精品的小游戏,是否是有价值的,甚至能产生商业价值? 当你有了一个待要去验证的想法后,就很难再无视它。这个想法每天都在我的脑海里游荡,时不时的叮咚一下:嗨!你打算什么时候开始做呀?与其长此以往的被脑袋中的这个小闹铃打扰,我知道最好的方式就是把第一个小游戏做出来,然后它就会安静了。所以我就开始谋划第一个小游戏的题材,那些游戏史上的经典:俄罗斯方块,太空侵略者,贪吃蛇,吃豆人….. 最终我选择了“1010”,虽然它不见的会被载入游戏经典史,但是它简单的规则和玩法,确实有被载入的潜质。我的第一款小游戏就是它了,我要将它制作成一款精品。 在确定了要做的游戏后,我开始思考,市面上已经有如此多的“1010”的类型的游戏,我到底要做一款怎样的“1010”呢?以我的能力可以把它做成什么样的呢? 既然是要做一款微信小游戏,当然是先看一下微信小游戏平台上现在已有的“1010”类型的游戏都是什么样子?在试玩了所有的1010类型的游戏后,我有了这样的想法:这里所有的1010都无法让我满意,都不够精致,看来我必须而且一定要自己做一个了。一个极其自恋但是对我来说却有着极大动力的想法。 我要做一款这样的游戏,它小而美,简洁,精致,不会过时,它的名字叫“精致1010”。 于是有了下面这张草图,是我对它初识的印象。 [图片] 而它最终的样子是这样。 [图片] 可以看出,在界面上基本延续了初识时的样子,只是看起来更好看了一些。 虽然不论是从简洁性还是配色上,看上去还不错,但是这只能算是万千小游戏中的一个而已,只有这样并不足以让人能够记住它。于是我又陷入了深深的思考:一款游戏想要被记住,想要深入人心,只有在情感上与玩家产生共鸣和连接才行,这样的一款简单的小游戏如何才能产生情感共鸣呢? 于是我有了这样的方案:将游戏的四个主题与春,夏,秋,冬的四季相联系,然后在每个季节里增加一点儿那个季节里所独有的有可能与某些记忆相联系的东西,春天的樱花飘落,夏天的细雨绵绵,秋天缓缓落下的枫叶以及冬天安静飘洒的雪花。 最终有了这样的效果: 春天的樱花飘落。 [图片] 夏季的绵绵细雨。 [图片] 秋天缓缓落下的枫叶。 [图片] 冬天静静飘洒的雪花。 [图片] 每种季节的特定效果并不会在一开始就出现,而是在游戏中不经意间出现一小会儿。我希望它能传达出这样的感觉:当你行走在春天的路上,不经意间,几片樱花花瓣从眼前飘落,你停下脚步,抬起来头,看见了美丽的樱花树,也看见了整个春天。 为了在游戏中模拟出樱花的飘落的感觉,我设置了非常多的随机数据,用了整整一天的时间,才调整出了想要的感觉:一阵微风吹过,伴随着片片花瓣向斜下方掉落,驻足抬头,你看见了整棵樱花树(这棵樱花树能美成什么样完全基于你的想象)。 游戏中的音效不多,我没有为其增加背景音乐,因为我认为背景音乐会让它显得嘈杂。我希望游戏中的音效能够简单,清澈。起初,找了一些开源的音效素材库,但是并没有找到能够让我满意的音效。后来也试着使用了一些音效制作软件来制作音效,但是仍旧不太满意。最终,从女儿的音乐小玩具中找到了我想要的声音。 [图片] 游戏中的所有的音效都是用这个小东西创造的,原声的录制未加任何的修饰。 旋律也是极其的简单,如果你在游戏中仔细听一下,大概能够听出来: 消除音效用的是:哆瑞咪发梭拉西哆(12345671)游戏结束音效用的是:梭发咪瑞哆(54321)形状拾起时用的是:咪(3)形状放下时用的是: 哆(1)所有的按钮点击用的是:瑞(2) 以上是以作为一个游戏创作者的视角描述的这个游戏的产生和制作的过程和细节。对于一个普通玩家来说,可以算作看个热闹,了解一下游戏是怎么做出来的,都包含了哪些东西。 下面是完成这款游戏后给我的感想和思考。 在游戏做完后,我把它发给了老婆玩,我老婆的感受大概是这样的: 老公,你这个游戏是不是太简单了。 哎呦,还会掉花瓣呢!有点儿意思。 当她玩到了两千多分,登顶排行榜之后...... 老公,你这个游戏挺不错的,配色也挺好看,看着简单,东西还蛮多的。 在游戏上线后,我把它分享给了老妈和丈母娘,想看看她们对于这样一款游戏的感受,没有做过多的解释,对于她们来说似乎也没有什么上手的难度,看着她们在排行榜中的得分,我知道这款游戏完成了,做了这么多年的游戏,这是第一个分享给她们玩的游戏。 每当女儿看到我玩这个游戏时都会跑过来说:爸爸,我玩。然后就用她的小手在屏幕上拖拖拽拽的,她并不能理解游戏规则,只知道只要把下方的图形放到上面去就很高兴,在多次尝试放不上去时就会对我说:爸爸,把我手,一起玩…..然后我就握着她的小手一个一个的将下方的图形拖拽上去。 对于我来说这也是第一个让我每天都会打开的游戏,游戏制作者通常不会玩自己的游戏,这是事实。但是我却经常的打开它,我喜欢游戏里的夏天,打开它有时候只是为了等待那场不知何时会下起的雨。 做了多年的游戏开发,也做了很多款游戏,这是唯一的一款让我觉得异常满足的可以分享给家人玩的游戏,它包含了很多的我对于游戏的想法和思考,并且让我觉得做出了一些不一样的东西。 在这个一切都讲求快的时代,在所有的游戏都在想尽一切办法赚取玩家注意力,保持玩家留存率的环境下,我想通过这款游戏表达一些不一样的东西,正如我在游戏中写给玩家一封信上所说。 我希望它是这样的一款游戏: 简洁而精致,让人看了感觉舒服。它不会去抢夺你的注意力,你可以随时打开玩几下也可以随时的放下。它就像你的一位老朋友,无需多言,也无需时刻保持联络,它就静静的守候在那里,伴你度过每一个春夏秋冬。 当我们玩游戏时,通常都会处于一种“躁”的状态,而我希望它能够传达出一种“静”的感受,它是一位沉默寡言的老友,即使从不说话,它也会一直在那里陪伴着你。 虽然,我个人对它觉得满意,但是,这样的一款游戏是否具有商业价值呢?这是个不得不思考的问题。任何的一件事,只凭借着热爱是很难长久的,对于这种小众的游戏是否有可能实现盈利,持续发展下去呢? 我相信是的,因为我认为这是一件正确的事,长期坚持做下去定会产生价值的事。 说到这里不得不介绍一个人,以及他的一个产品。 此人我叫他“波哥”,因为我写的小游戏开发教程而结实成为朋友,至今尚未谋面。他做了一个个人的博客网站,叫做“刻意周刊”,每周分享互联网上的优质内容。 自从认识后,他的“刻意周刊”几乎就承包了我每个周的阅读内容,各种的人文,社科,行业,趣闻,影视,书籍推荐等等,每期的周刊内容之丰富即使我用一个周的闲余时间也涉猎不完。做这样的一个周刊,每个周得阅读多少的东西才能精选出来呀?他背后一定有一个团队在做这样的事情,我这样想。 于是我就好奇的问他:波哥,你这个“刻意周刊”是一个人做的还是有团队在做啊? 波哥回复:我自己做的,就是把每个周看到的感觉有价值的可以分享的内容整理出来,这种事就得坚持长期价值。 于是乎,我断定此乃牛人也。 你可以看一下这个“刻意周刊”,至今为止出了26期了,看一下每期的内容和质量,大概也就能明白为什么在知道这是一个人做的之后,我会觉得震惊了。 就在今天,基于刻意周刊发现与推荐优质内容的初心,孵化了一个新的产品“Superdaily”,开始正式发挥它的商业价值了。 波哥所做的事证明了这样的一个事实,坚持长期做有价值的事情,是会产生商业价值的。所以,我对自己的小游戏开发之路也有了这样的初心和愿景: - 致力于制作优质的微信小游戏,可以分享给父母,分享给朋友,分享给小朋友的游戏,希望当玩家看到这个游戏是小蚂蚁出品的,就知道这个游戏是用心制作的,靠谱的。 - 继续写出更好的游戏开发教程,帮助更多想要做游戏又不知从何处下手的朋友能够做出自己的游戏,实现自己的想法和创意。 把正确的有价值的事情长期做下去,坚持长期价值。 在制作这个游戏的过程中,我写了一个“微信小游戏开发实战系列”的教程,教你如何从0开始开发出一款这样的游戏。 如果你从未有过游戏开发经验,但是又对游戏开发感兴趣,想实现自己的游戏创意,做出自己的游戏,可以学习一下我的“人人都能做游戏”系列教程,手把手的带你进入游戏开发世界的大门。 差点儿忘了介绍本文的主角:精致1010。一款精致而温暖的游戏送给你,第一个作品,欢迎大家支持鼓励一下,十分感谢。 [图片] 游戏已开源到社区,项目地址:精致1010 欢迎学习,交流,改编分享,请不要直接用于商业用途。 欢迎关注我的公众号:小蚂蚁游戏开发,我会继续致力于分享与小游戏开发有关的教程和内容。如果你遇到任何的问题,我也会尽可能的为你提供帮助。 [图片]
2021-06-19 - 教你 3 分钟搭建 AI 助手(无需编码)
前言 今天给大家带来的是云开发AI智能体,上篇《云开发之云模版CMS体验》文章提到了期待云模版有更多实用模板,这周云模版就更新了AI智能体应用,无需代码一句话搞定一个 AI 助手。 步骤 进入「微信开发者工具」-「云开发」控制台 [图片] 选择「云后台」-「去使用」 [图片] 进入云模板控制台选择「模板中心」 [图片] 进入「AI智能体应用」点右上角「安装」 [图片] 安装成功后切换到「关联资源」菜单「访问」管理后台 [图片] 默认会内置一些AI助手 [图片] 选择「分享」可以直接对话体验 [图片] 如果没有满意的AI助手可以通过「从模版创建」 [图片] 模板中还有 10 多AI助手供你选择 [图片] 选择后可以进入AI助手编辑详情页面 左边区域可以设置人设提示词 右边区域可以直接对话调试效果 [图片] 确认没问题点击「提交」就创建成功了 接下来再来一个自定义一个AI助手,选择「创建智能体」 [图片] 输入AI助手名称点击「确认」 [图片] 进入AI助手详情页,不会写人设提示词可以点击「获取AI建议」 [图片] AI会根据名称来生成一套专业的人设提示词,点击「使用AI建议」即可 [图片] 设定好AI助手人设后,可以在右边区域对话调试 [图片] 除此之外还可以设置AI助手的基础信息: 对外展示信息 头像 名称 简介 背景 开场白 欢迎语 推荐问题 [图片] [图片] 确认无误后点击「提交」就创建好了,可以「分享」给你的好友使用了 [图片] 电脑端效果: [图片] 手机端效果: [图片] 还支持在「对话」菜单中查看所有智能体的对话记录 [图片] 总结 整个体验下来,创建流程非常简单,只需要输入你要创建的AI助手名称即可生成,全程无需代码,赶紧去试试吧~ 发布到小程序/公众号已经在来的路上了,后续开放后我会更新相关体验文章。
2024-05-17 - 微信对话开放平台《实验室》邀请测试
微信对话开放平台为微信AI研发的低门槛、零费用的便捷对话机器人工具,多年来一直为微信生态的开发者与商家提供智能对话能力。 近两年来,随着大语言模型的涌现,人工智能领域迎来了历史性的突破,也引发了一股ChatBot的热潮。随着相关话题的探讨热度不断增加,我们也开始思考,是否可以在微信对话开放平台原有的能力基础上,融入大语言模型技术,从而更好地解决知识库构建成本高、无法回答复杂问题等痛点。为此,我们将进行一个新的尝试,开放“实验室”功能并邀请用户加入测试。 [图片] LLM的优点在于能够处理大量信息,理解复杂语境,并生成自然、流畅的回答。利用LLM的能力,我们可以更好地处理开放式问题、复杂问题和模糊问题。但是,在实际应用场景,LLM也存在一定局限性,为此我们尝试了两方面的调整。 大语言模型文档问答 虽然LLM有着强大的推理理解能力,但其潜在的偏离实际的预测以及知识更新延迟问题仍然值得关注。为了在实际应用中加强"准确性"、"可控性",我们使用RAG(Retrieval Augmented Generation)检索增强生成技术,让大模型可以处理各种复杂的知识密集型任务。 同时,我们针对问答场景对模型进行了微调(Fine-tune),进一步提升了拒识、推理和多轮对话等能力,确保了输出效果的优质。这使得大型语言模型在细分应用场景中具有真正的落地价值。 平台不仅支持Word、TXT、PDF等文件格式的上传,还支持网页、公众号文章等数据格式。 [图片] 文档抽取问答对 由于LLM的知识库回答是从大量的文本数据中提取和总结的,且它可能包含一些错误或不准确的信息。FAQ问答知识库,是一种将信息以问题和答案的形式组织起来的形式。这种结构化知识库通优点是信息准确、可靠,易于管理和更新。 为此平台实现了从上传的文档中自动抽取问答对功能,并允许开发者审核并添加到知识库中。此功能可以有效的提高知识库的创建效率和质量。 [图片] 想要加入测试的用户可以按照如下方式进行申请: 申请方式 1. 发送邮件到:wechatopenai@tencent.com 2. 邮件主题:申请实验室(机器人ID) 3. 邮件内容: - 机器人信息:(包含:机器人ID、机器人名称) - 当前应用情况:(包含:每日消息量、当前召回率) - 应用场景:(如:“微信公众号”、“小程序”) - 应用简介:(如:xxxx 公司xxx 产品的售后客服) - 开发者微信号:xxxxx
2024-01-22 - 留言功能开通了?
21年新创建的公众号,昨天发了一篇图文,发现有了留言功能,之前都是没有的,突然开通了留言功能,是后台有什么规则修改了嘛
2024-02-20 - 5秒教你如何获取公众号主页url
要点: 找到唯一标识:__biz 方法一: step1: [图片] step2: 在新开的页面上,从地址栏中找到“__biz”,如下所示: https://mp.weixin.qq.com/s?__biz=MzA3OTc4MTQ5NQ==&mid=yyyy&&idx=1&sn=111&chksm=222&token=333&lang=zh_CN#rd __biz后面值就是当前公众号的一个唯一标识,此处为MzA3OTc4MTQ5NQ== 也就是__biz后面的=之后、下一个&符号之前的这部分 [图片] [图片] step3: 找到biz的值,把biz的值加到模版地址后面,得到一个链接: https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzA3OTc4MTQ5NQ==#wechat_redirect step4: 把step3中拼好的链接通过微信给自己,然后在微信中点击此链接,就可以了。 说明:这个链接需要在微信中打开 方法二: https://developers.weixin.qq.com/community/develop/article/doc/0008a48410cf207994ef2c6125b413
2024-01-09 - 400元迁移微信公众号留言功能,迁移全过程
背景:2021年5月27日晚8点30分开始策划迁移公众号,迁移的目的为了是为了【留言】功能,因为从2018年开始注册的公众号都没有留言功能。 [图片] 为了不浪费朋友时间,我直接把他的管理员转移给我微信小号了,方便我来回各种扫码。进入主题,开始迁移公众号,先看官方流程图: [图片] 迁移流程总耗时5天(可以缩短到3天) 开始发起迁移: [图片] 管理员(我的微信小号)扫码验证后出现迁移协议,就是下面这个图 [图片] 输入目标账号原始ID(本公众号的原始ID)发送验证后,在目标账号管理员微信端(我的微信大号)允许即可 [图片] 同意后下一步下载迁移公函 [图片] 下载下来我们需要填写迁移双方基本信息,迁移公函需要双方盖章 [图片] 继续准备资料办理公证书:原公众号营业执照、原公众号后台截图、原法人身份证正反面、目标公众号营业执照、目标公众号后台截图、目标法人身份证正反面,公众号后台截图。 [图片] 准备好后开始办理公函公证书,可以在网上办理某宝1-2百左右。线下的话地图搜索:公证处,提前打电话问问能不能做公众号迁移公函公证书,问好了再去,大约3-5百左右。(下面是我的公证书) [图片] 然后我们上传这些资料去提交即可,最后支付300元。(如果资料传错了,有两次免费修改的机会,两次都错了那继续交300) [图片] 然后我们等着就好了,一般情况2、3天(工作日)就搞定了,期间会打电话确认,然后双方公众号管理员同意迁移,约1个工作日迁移成功。 [图片] 至此公众号迁移功能已完成,整理一下我准备的资料。 [图片] 最后做个timeline 2021年5月27日:和朋友沟通拿号 2021年5月28日:把朋友公众号管理员签到我的微信 2021年5月29日:开始准备迁移所有资料 2021年5月30日:TB线上办理公函公证书100,上传后支付300迁移费 2021年5月31日:迁移电话确认,双方管理员同意,迁移成功
2021-06-01 - 手机号授权处罚永久,并扣除运营分0分。申诉2次都没有通过,还有办法吗?
违规信息 [图片] 官方截图 违规1 存在违规收集用户手机号的行为 2023-5-23 [图片] 违规2 存在违规收集用户手机号的行为 2023-6-8 [图片] 目前小程序内获取手机号提示: 由于小程序违规,该功能暂时无法使用 [图片] 申诉 [图片] 申诉了都没有通过,已经永久封禁了吗? 请问各位大佬们还有解决办法吗?? 在线等!急急急!!
2023-10-31 - “小程序直播”接入指引
各位微信开发者: “小程序直播” 功能正在公测中,具体接入指引请参考《小程序直播产品介绍及操作指引》。 一、功能简介 小程序直播是微信官方在2020年2月公测推出的产品能力,帮助商家在自有小程序中实现直播互动与商品销售的闭环。 [图片] 二、商家准入要求 满足以下条件,即可开通小程序直播: ①属于小程序直播开放类目,具体见《微信小程序直播功能准入要求》 ②主体下小程序近半年没有严重违规; ③小程序近90天内,有过支付行为; 三、具体产品功能及操作指引 具体接入指引请参考《小程序直播产品介绍及操作指引》,以下为商家操作步骤: 1. 开通权限 1) 登录“小程序后台”(mp.weixin.qq.com),在左侧导航栏找到“小程序—功能—直播”,点击开通。 小程序直播需要基于小程序,如若开发者还未创建小程序,可按照《小程序接入指南》流程指引创建小程序并完成开发。 2) 符合上述开放范围的即可开通。 2.功能开发 小程序直播需要实现【直播组件】与【后台配置】两个部分,其中组件部分需要在小程序中进行配置开发。 具体开发文档,请参考《小程序直播开发文档》。 2.直播间配置 开发完成后,商家可通过小程序后台设置直播计划、开通、设置抽奖等操作。具体操作指引,请参考《小程序直播产品介绍及操作指引》。
2020-08-26 - 小程序地图个性化样式组件要收费了!
地图个性化样式组件 自2023年6月29日0点起,该能力需要先购买再使用。若未购买,届时将无法使用该能力。具体购买方式见付费管理。 自2023年6月29日0时起,个性化地图配置界面的入口统一为微信公众平台-付费管理,请从此入口进入,腾讯位置服务官网入口不再使用。已经在小程序生效的个性化样式配置,将于2023年6月29日0时变更为默认样式,如有个性化样式配置需求,请于6月29日0时前,前往微信公众平台-付费管理进行相关能力的开通和配置。 [图片] 地图个性化样式组件是腾讯位置服务为开发者提供的地图高级能力,开发者可以在法律允许的范围内,定制背景面、背景线、道路、POI等多种地图元素,灵活地设计心仪的地图样式。 购买该能力后,您可以在MP平台「管理->付费管理->概览->地图个性化样式->去使用」中创建配置您的地图个性化样式,您可以选择我们提供的基础及高级模版,也可以通过在线编辑平台,对多种地图元素的样式进行自定义设置,以满足在不同场景下的个性化需求。 微信公众平台-付费管理 [图片]
2023-07-17 - 公众号运营:如何文章内跳转公众号主页(不是历史文章页面)
近期社区中运营公众号的朋友咨询,如何文章内跳转到公众号主页 [图片] 不是历史文章页面 [图片] 这点是可以通过文章内的图片实现的。 接下来教大家如何实现图片跳转公众号主页: 1、首先获取历史文章链接 打开该公众号任意一篇内容,复制链接,在浏览器打开 [图片] 右击鼠标查看源代码 [图片] 快捷键ctrl+F开启全局搜索“ __biz”然后把该公众号卡版ID复制,记得后面两个“==”号必须都复制上。 [图片] 2、这个功能要通过SVG排版来实现。官方编辑器是不支持的,所以在这里我们使用某排版中的SVG编辑器。 [图片] 打开某排版SVG编辑器后,在组件这里搜索公众号或10214 [图片] 找到公众号——图片(免费的) 组件 [图片] 然后添加图片,粘贴公众号卡片ID [图片] 设置好后,先保存,后同步到微信后台 [图片] 这时候就可以去公众号预览了。 当然要注意的是,这种SVG排版同步到公众号后是不能修改的。所以建议在某排版编辑好所有内容之后,再同步到微信公众号后台。 而且这种排版可以跳转任何公众号主页。 还有一点这种跳转没有任何提示,直接跳到公众号主页,大家快去试试吧。 当然,还有朋友不知道如何跳转历史文章,可以参考:公众号运营:公众号菜单如何跳转历史文章? https://developers.weixin.qq.com/community/develop/article/doc/000e2e5dca09589f9f6fc985456013 我是立十,非官方人员💍公众号💍运营资深忠实粉丝,专注回答社区中关于公众号的问题。
2023-06-21 - 微信:小程序获取手机号要开始收费了!
[图片] 收费说明 自2023年8月26日起,手机号实时验证组件将需要[代码]付费使用[代码]。 [图片] 手机号快速验证组件 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html 新版本组件不再需要提前调用wx.login进行登录。 代码示例 [代码]<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button> Page({ getPhoneNumber (e) { console.log(e.detail.code) } }) [代码] 返回参数说明 code,动态令牌。可通过动态令牌换取用户手机号。使用方法详情phonenumber.getPhoneNumber接口。 请注意: 目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体); 该能力使用时,用户可选择绑定号码,或自主添加号码。平台会基于中国三大运营商提供的短信等底层能力对号码进行验证,但不保证是实时验证; 请开发者根据业务场景需要自行判断并选择是否使用,必要时可考虑增加其他安全验证手段。 开发者需合理使用,若被发现或用户举报开发者不合理地要求用户提供手机号等个人信息,中断了正常的使用流程,影响了用户的使用体验,微信有权依据《微信小程序平台运营管理规范》对该小程序进行处理。常见违规事例和具体解析; 自2023年8月26日起,手机号快速验证组件将需要付费使用。标准单价为:每次组件调用成功,收费0.03元。 手机号快速验证组件(旧版):https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/deprecatedGetPhoneNumber.html 注意 目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。 该能力使用时,用户可选择绑定号码,或自主添加号码。平台会对号码进行验证,但不保证是实时验证; 请开发者根据业务场景需要自行判断并选择是否使用,必要时可考虑增加其他安全验证手段。 手机号实时验证组件 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getRealtimePhoneNumber.html 代码示例 [代码]<button open-type="getRealtimePhoneNumber" bindgetphonenumber="bindgetrealtimephonenumber"></button> Page({ getRealtimePhoneNumber (e) { console.log(e.detail.code) } }) [代码] 该能力与手机号快速验证组件的区别为: 手机号实时验证组件,在每次请求时,平台均会对用户选择的手机号进行实时验证; 手机号快速验证组件,平台会对号码进行验证,但不保证是实时验证。 请注意: 3. 目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体); 4. 该能力使用时,用户可选择绑定号码,或自主添加号码。每次请求时,平台均会基于中国三大运营商提供的短信等底层能力对号码进行实时验证; 5. 请开发者根据业务场景需要自行判断并选择是否使用,必要时可考虑增加其他安全验证手段。 6. 开发者需合理使用,若用户举报或被发现开发者不合理地要求用户提供手机号等个人信息,中断了正常的使用流程,影响了用户的使用体验,微信有权依据《微信小程序平台运营管理规范》对该小程序进行处理。常见违规事例和具体解析; 7. 该能力的bindgetrealtimephonenumber 事件回调中,仅会返回 code,不会返回 encryptedData,开发者仅可通过消费 code的方式换取用户手机号; 自2023年8月26日起,手机号实时验证组件将需要付费使用。标准单价为:每次组件调用成功,收费0.04元。 付费管理 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/paymentManage.html 修改建议 手机号快速验证组件旧版本接口依然可以使用,只是需要收费而已,不想做改动的交钱就行了。如果想用新接口就去改吧,多花一分钱(增强小程序安全性)。
2023-06-30 - 【集合】花了 3 个月,写了 40 篇小程序文章
前言 花了3个月,一共输出 40 篇文章,这也算是一个阶段性的总结。在此做个文章分类集合,希望对大家有所帮助。 小程序前端 《专治按钮效果不明显(扩散动画效果)》 《小程序开发必备,这 5 款超实用开源插件!》 《仿抽奖助手奖品详情页面向上翻页效果》 《推荐 5 款高仿知名应用的开源项目!》 《生成海报很复杂?有它轻松搞定!》 《推荐一个自定义导航栏开源库》 《前端开发,必备的学习网站!》 《情侣券-领取动画分析》 《通过玩游戏来学习CSS》 《CSS不规范导致的布局显示问题》 《微信小程序如何引入npm包?》 《情侣券-选中卡片翻转动画》 《CSS:实现卡片洗牌效果》 《情侣券 v2.0 使用的 4 款开源组件》 小程序云开发 《使用聚合函数实现打卡排行榜》 《使用云开发做内容安全检查》 《云开发-实现分页功能》 《云开发-实现维护用户表》 《云开发-实现模糊搜索》 《云开发实战:实现订阅消息推送》 《如何优雅的调用云函数?》 《云开发实战-如何维护用户表?(优化版)》 《推荐 10 款使用云开发的开源项目》 《云开发:CloudBase CMS 实战使用指南》 小程序产品 《如何利用小程序提高10倍活动效果?》 《实战:让数据说话之自定义埋点分析》 《#小程序云开发挑战赛#-情侣券》 《小程序运营必备的 3 款官方小程序》 《小程序云开发挑战赛:情侣券 v1.1 版本迭代》 《云开发挑战赛复赛:情侣券介绍PPT》 《参加#小程序云开发挑战赛#复赛收获》 《云开发挑战赛决赛:情侣券介绍PPT》 通用知识 《如何重构?》 《如何高效学习?》 《如何看懂时序图?》 《为什么优秀的程序员都写博客?》 《我从 Android 转到 微信小程序 的思考》 最后 后续计划会写更多云开发相关的文章以及小程序基础系列学习文章。
2020-11-24 - 新年模板小程序个人快速体验
开端:在朋友圈看到有个小姐姐说动动手指,轻松制作了自己的拜年小程序。[图片] 2,打开了这位小姐姐说的文章,看到了是微信开发者工具的新年模板https://mp.weixin.qq.com/s/1GPSip5SKkRJRInynj2agQ [图片] 3,尝试自己做一个,创建小程序时,可以选择微信云开发或不使用,都会显示新年模板的。[图片] 4,打开后是现成的新年祝福小程序,可以改一下自己微信头像,改一下里面的微信昵称以及祝福语。[图片] 5,直接上传提审,然后发布。[图片] [图片] [图片] [图片] [图片] 结尾:感觉还可以添加更多设置,比如显示打开的人微信头像,然后他可以用自己的名字和头像转发给亲友。感谢阅读!
2022-01-28 - 前端XR
[图片]
2023-06-28 - 别在@微信官方了,5分钟10行代码教你制作带红旗的微信头像,多种样式随便选(含视频和源码)
昨天发了微信头像挂红旗的讲解文章,应大家要求,今天录制一套视频,免费送给大家。 我们先来看下效果图 [图片] [图片] [图片] 原理讲解 其实原理很简单,我们用canvas把自己的头像画在最下面,然后把对应的相框模版画到我们头像上面。然后使用小程序自带的api把我们画出来的图片,保存成本地图片文件,然后把这个图片作为我们的微信头像就可以了。 [图片] 免费视频链接 https://www.ixigua.com/i6740973288706540040/ B站免费视频链接 https://www.bilibili.com/video/av69074127/ 腾讯视频免费视频链接 https://v.qq.com/x/page/f3001t402da.html
2019-09-27 - ELSE IF
[图片]
2023-06-28 - ELSE前端
ELSE前端个人主页
2022-10-22 - 微信云开发管理工具入门教程
前言 微信云开发管理工具是是什么? 提供了一套云开发的后台管理工具,并且提供低代码开发工具,开发者可基于低代码工具,连接到业务数据库,拖拽组件生成前端UI,从而定制各类管理端应用。 在这里肯定有同学会问它与 云开发内容管理CMS 有什么区别? 可以理解为更加灵活,可随意定制的内容管理,结合了微搭使用起来更简单更灵活。 如果还不知道微搭的同学可以看下我之前写过的低代码平台微搭入门教程 体验 目前微信云开发管理工具还在内测当中,如需申请内测权限,戳这里申请入口 开通主页 当我们开通权限成功后 下载/更新最新版微信开发者工具 进入云开发 IDE 控制台 [图片] 选择「更多」中的「管理工具」 [图片] 打开后会提示是否打开微搭低代码插件提示,选择「允许」 [图片] 模板体验 从这一步开始就已经正式进入管理工具了,首先可以看到的就是模板页面,目前已经内置了常用的模板,需要那个模板点击「查看/安装工具」即可。 这让我感觉这就像手机系统上的App市场,需要什么就安装什么,只要模板足够多那么开发者使用起来能提升不少效率,开发成本可以得到极大的提升。如果这个模板市场可以支持开发者接入发布,类似 App 开发者自由发布 App 市场一样,还可以做付费模板,那么想象空间还是很大的。 [图片] 我先选择一个轮播图管理测试下效果。 [图片] 提示:首次加载会比较慢,需要耐心等待下 安装成功后,可以获得管理后台地址和管理员账号密码 [图片] 复制链接输入账号密码即可进入后台管理 [图片] 管理后台有个简单的 banner 管理后台案例数据 菜单分别为:轮播图管理、轮播图图片管理 [图片] 如果需要自定义轮播图需要现在图片管理上传图片 [图片] 然后再到轮播图管理添加 [图片] 那么小程序如何获取数据呢?我们可以回到云开发 IDE 控制台看到数据库多了一张表 cloudbase-sample-banner 里面有三条数据 [图片] 小程序获取数据代码 [代码]wx.cloud .database() .collection("cloudbase-sample-banner") .where({ status: "online", }) .get({ success: (res) => { this.setData({ banner: res.data, }); }, }); [代码] 编辑模版 那么如果轮播图模版无法满足我们的需求怎么办? 如:轮播图需要点击可以跳转显示公众号文章,这个时候需要加文章路径字段 基于以上需求我们来修改一下,首先回到管理工具首页 [图片] 点击轮播图模版查看详情,选择最下方的「编辑工具」 [图片] 在这里可以对管理页面进行「页面设计」 [图片] 所有页面的数据的显示当然离不开数据,第二个菜单就是「数据源」 [图片] 剩下两个菜单分别是:素材、应用设置,这两个菜单相对比较简单就不做过多介绍。 新增字段需要在「数据源」中找到「添加轮播图」然后点击「编辑」 [图片] 添加一个入参,path 参数就代表文章路径(编辑轮播图信息操作类似) [图片] 然后还要修改代码,在获取参数和添加参数的地方加上 path 这个属性 [图片] 最后点击「方法测试」添加一条数据看下效果 [图片] 可以通过后台管理页面或云开发 IDE 数据库看到数据已经添加成功 [图片] [图片] 添加方法已经改造完成,接下来就是修改查询方法,选择「查询轮播图列表」然后在「出参」进行添加子集,因为查询数据是多条所以是一个数组,我们要查询显示的是数据里面的对象。(查询轮播图信息操作类似,区别是添加入参而不是子集) [图片] 添加是什么字段显示就是什么样的字段 [图片] 数据源部分搞定了! 接下来就是修改后台管理页面「添加」和「查询」,切换到「页面设计」菜单 点击「添加轮播图」可以看到它的布局结构一个表单容器里面装了很多组件 [图片] 我们文章路径需要输入,那么可以从上方拖拽一个单行输入组件到布局里面来 [图片] 然后修改下显示标题和绑定字段 [图片] 当我们编辑完成后可以点击右上角「预览」然后点击「实时预览」 [图片] 这样就可以单独打开 一个窗口进行功能测试,添加修改完成后我们再来修改「列表显示」,选中「数据表格」组件在「列管理」添加 path 路径 [图片] 列表显示效果 [图片] 修改完成需要点击右上角「发布」即可同步线上版本后台。 自定义模版 还有一种情况就是目前的模版无法满足业务需求,比如下面这个「云数据库管理」模版,为了通用只能显示json,查询也没办法模糊查询,那么这个时候就需要自定义。 [图片] 接下来我们自己做个活动列表显示,然后再做个模糊查询,这个需求可以说是最常用的操作了。 接入数据 我们基于「云数据库管理」模版新增一个查询活动列表页面,首先切换到「数据源」点击+号选择「自定义代码」 [图片] 输入名称和标识点击创建 [图片] 添加方法 [图片] 查询代码,其他操作详细可见 cloudbase node sdk 文档 [代码]const cloudbase = require("@cloudbase/node-sdk"); const envId = "<云开发环境ID>"; const collectionName = "<云数据库集合名>"; const app = cloudbase.init({ env: envId, }); const db = app.database(); module.exports = async (event, context) => { let { pageNo, pageSize } = event; if (pageNo < 1) pageNo = 1; // 查询条件先固定为空,即查询集合内的所有数据 const query = db.collection(collectionName).where({}); const recordsRes = await query .skip((pageNo - 1) * pageSize) .limit(pageSize) .get(); const totalRes = await query.count(); return { records: recordsRes.data, total: totalRes.total, }; }; [代码] 入参配置:pageSize、pageNo 出参配置:使用「方法测试」运行测试后再使用出参数映射即可 [图片] 数据显示 切换到「页面设计」点击右上角+号 [图片] 新增空白页面 [图片] 拖拽一个数据表格组件到布局中 [图片] 设置数据表格数据来源 [图片] 列表中数据就显示出来了,但是我们会发现其中时间字段显示重复了,以及表头是字段名,使用者不一定能看懂。 [图片] 我们可以在属性中列管理对不需要的字段进行删除 [图片] 还可以修改属性标题,效果如下: [图片] 建议 1.模版需要更丰富,满足更多开发者场景 2.自带模版业务思考不够全面,过于简单无法直接 3.自定义模板操作过于复杂,需要简化,如:自动生成基础增删查改代码 相关教程 官方云开发管理工具教程 云开发Node.js SDK API 微搭组件列表
2023-06-14 - 2023-06-09
- 微信:把元宇宙装进小程序
[图片] 作为月活13.09亿的国民级应用,微信的每次小升级都很容易形成现象级。2023开年,微信放大招,试图把元宇宙装进小程序。 不久前,微信官方在开放社区贴出了“XR-FRAME”开发指南,这是一套为小程序定制的XR(扩展现实)/3D应用解决方案。简单来说,该方案上线后将从底层赋予小程序扩展现实和3D能力,让未来小程序的人机交互方式由2D向更立体化的3D转变。 之前,XR-FRAME还处于测试阶段,根据官方发布的Demo看,该组件可以更好地呈现3D效果,并提供AR换脸、AR游戏等体验。据透露,微信率先将XR小程序的试水场景瞄准了电商领域,落地AR 试穿试戴、AR 家装等不同类型案例。 如今,框架 XR-FRAME 发布正式版,曾进行了一系列的更新,且一些功能还在开发中。 [代码]xr-frame[代码]在基础库[代码]v2.32.0[代码]开始基本稳定。 [图片] 限制: 最低要求客户端iOS8.0.29、安卓8.0.30及以上,推荐稳定版在iOS8.0.36、安卓8.0.35及以上。 基础库最低2.27.1及以上,推荐2.32.0及以上。 开发工具需要最新版本,建议Nightly版本。 小程序全局同一时刻只能存在一个[代码]xr-frame[代码]组件,否则可能会发生异常。 同一个[代码]xr-frame[代码]组件只能存在一个[代码]xr-scene[代码],并且必须为顶层。 目前不支持和小程序传统标签比如[代码]<view>[代码]混写。 目前不支持[代码]wxml[代码]自动补全,真机调试需要特别注意,见真机调试文档。 同时未来还会追加更多的能力,在未来的规划中,我们还会着重致力于: XR-FRAME内置特色的UI组件,让开发者可以在XR-FRAME组件中写UI,来实现一套酷炫的UI系统。 AR/VR能力持续增强,支持眼睛设备。 交互手段进一步强化,物理碰撞、触发等功能(已完成,待发布)。 工具能力强化,包括标签属性自动补全等。 从战略角度,把元宇宙装进微信小程序,腾讯居安思危。经济学家朱嘉明预测,未来人们社交的基本形态将在元宇宙中进行,倘若这一切真的发生,微信等传统的社交模式将被颠覆。打败微信的可能并非“抖音”社交,而是元宇宙应用。 小程序要3D化 还记得在微信风靡一时的小游戏“跳一跳”吗?玩家通过长按屏幕让小人蓄力跳跃到前方的盒子上得分,小人不慎掉落则游戏结束。这款游戏在2017年12月登陆微信小程序,引来了无数玩家比拼较量。几个月前,消除闯关游戏“羊了个羊”也以微信小程序为载体火爆全网。 自2017年1月微信小程序上线以来,多款现象级应用在其中诞生。依托庞大的微信用户群,小程序为开发者们提供了一片新的创作土壤。6年来,小程序的平台能力和底层框架也在不断升级。2023年刚开年,小程序曝出大动作——正在内测XR框架。 XR即扩展现实,是VR(虚拟现实)、AR(增强现实)、MR(混合现实)的合称,可为受众带来真实与虚拟结合、人机交互的环境。不久前,微信官方在微信开放社区贴出了“XR-FRAME”开发指南,根据描述,这是一套小程序官方提供的XR/3D应用解决方案,基于混合方案实现,性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。 现在这一底层框架还处于测试阶段,小程序官方在开放社区贴出了详细的教程,指导开发者们如何从头构建一个XR小程序。 比起当前小程序采用的Canvas(画布)组件,xr-frame带来了更多能力。据介绍,其提供xml(可扩展标记语言)的方式来描述3D场景,并集成了AR、物理、动画、粒子、后处理等等系统,上手简单。同时,内置完整的PBR(基于物理的渲染)效果、环境光照、阴影,可以快速通过全景图生成环境数据。此外还有渲染性能逼近原生、扩展性强等优势。 [图片] XR小程序开发效果示例 简单理解,xr-frame的上线将从底层赋予小程序扩展现实和3D能力,将让未来小程序的人机交互方式由2D向更立体化的3D转变。 根据官方发布的Demo来看,获得xr-frame支持后,虚拟3D 人、3D物、3D场景都可以在小程序里更好地呈现,此外AR换脸、扫描平面获得AR游戏、扫描特定图片获得AR交互等功能也可实现。这意味着,以后的微信小程序将有更多具有交互性的应用出现。 按照测试节奏,XR小程序功能很可能在中国农历新年后全量上线,业界普遍将其视为下一个微信大版本升级的核心功能。 让元宇宙发生在微信上? 微信内测XR小程序,恰处于元宇宙浪潮激荡之时。这个动作释放了一个信号,微信小程序将一定程度担起腾讯布局元宇宙的使命。 虽然诸如Meta、百度等互联网巨头都开发了元宇宙全景应用,但体验和人气都十分有限。目前与元宇宙相关的应用场景主要体现在人机交互游戏、沉浸式电商购物、虚拟人直播、虚拟会议等方面。没有自建元宇宙平台,腾讯试水元宇宙,选了个轻巧做法,借助微信流量入口,用小程序先接入虚拟现实场景。 据透露,目前微信率先将XR小程序的试水场景瞄准了电商,并与多个不同品类品牌小程序合作,落地 AR 试穿试戴、AR 家装等不同类型案例。 现阶段,XR技术最普遍应用于电商领域。在传统的电商购物体验中,消费者只能依赖商家展示的图片/视频进行购物决策,最终购买后往往会出现买家秀与卖家秀差距过大的情况。而在引入AR技术后,传统电商平台的商品展示模式逐渐被颠覆,尤其在服装试穿、珠宝穿戴、美妆试用等特定场景下,AR能够帮助用户做出更正确的决策。 尽管微信一直不是电商的主战场,但诸如NIKE、Adidas、香奈儿等消费品牌都上线了相关的微信小程序,当XR功能上线后,这些品牌可以更好地展示商品,或许会带动微信电商生态的增长。 另外,可以想象的是,未来微信小程序中也将诞生更多3D建模以及现实交互感更强的小游戏,也许,下一款爆款小游戏将是截然不同的3D形态。 事实上,作为微信生态重要的组成部分,小程序也进入了发展瓶颈。为了实现无需下载、用完即走的效果,微信小程序在性能上做出巨大的牺牲,同样的应用在微信小程序上的表现往往不如APP。这也导致,小程序没有如人们预想一样成为颠覆性的应用,相反,某些功能性较强的应用如果通过小程序使用,显得鸡肋。 XR功能的上线能否为小程序打开增长空间尚未可知。有开发者担忧地表示,xr-frame能否达到预期还需要谨慎乐观。毕竟小程序的设计初衷就是要求快速,这里的“快”指的是加载以及渲染,所以导致微信小程序一直是以webview渲染为主、原生渲染为辅的混合渲染方式,也使得小程序的开发主要是以前端技术为主。然而xr-frame的3D化开发则需要完全不同的技术栈,对于渲染的开销也成倍提升,这就要求开发者要有更为优秀的优化水平。此外,在优质3D建模动辄占用较大内存的情况下,小程序提供的 XR 体验是否会有折扣也要打个问号。 当然,微信作为月活13.09亿的“国民级应用”,流量优势显著,只要有优异的小程序出现,一定不缺用户。这也会吸引大量的品牌方、开发者在上面进行尝试,所以xr-frame的上线将会带动小程序开发生态的繁荣。 从战略角度而言,把元宇宙装进小程序也是腾讯在社交领域的进一步探索,海外的社交巨头Meta已经开始了。 经济学家、横琴数链数字金融研究院学术与技术委员会主席朱嘉明曾认为,Facebook之所以改名为Meta,是因为Facebook本来就是元宇宙,只不过在此前的时代,数字技术发展还有局限,社交体验只能以图文、视频的方式呈现。他预测,未来人们社交的基本形态将在元宇宙中进行,打破时空、地理界限,带来更沉浸式的体验。 倘若这一切真的发生,微信、QQ等传统的社交应用模式将被颠覆,打败微信的可能并非“抖音”这样的视频社交应用,而是元宇宙。 扫码体验 [图片] 你认为XR能否催生现象级小程序? 注:“现象级小程序”是指在短时间内突然爆红而被众所周知和使用
2023-06-13 - XR-FRAME上手须知那些细节
春节假期,终于有时间研究了小程序 XR-FRAME的情况。尽管现在XR-FRAME 还是Beta 版本,但可以说这是小程序进入元宇宙的一个关键节点(希望尽快转正式)。上手入门教程和说明都十分平易近人,基本就是手把手的带入门,这个的确要赞一下。不过呢,可能这文档都比较早,之后都没怎么更新了,我就说说一下我这边入门的关键点吧。 1、真机调试,入门教程文档里忘记提到一个关键点就是需要在APP.JSON建立一个分包。 代码如下: "subpackages": [{ "root": "packageA", "pages": ["pages/cat"] }], 没这分包真机调试怎么都不能起来会报错,但预览可以调用;之前没发现这个费了我不少时间进行测试和找原因。 2、看社区不少同学问调用前置摄像头,其实就加个在xr-scene加给参数camera:Front。 代码如下: 这样就能顺利通过xr-camera进行调用了。 3、xr-frame与小程序view的通信,其实我的理解就是通过原来的view再加载xr-frame的组件应用,所以他们间可以通过父子组件进行通信,这个我没有太深入研究,就用了this.triggerEvent()完事,万幸也成功了。。 最后,一个的确没法搞掂的事情就是,video-texture加载的MP4视频死活都没声音和只能播放一段,我个人觉得因为video-texture是一个简单的视频图像渲染,没有将声音带过来,所以就没有声音了。这个目前我也没深研了,不过这个是AR的一个关键点,望尽快处理吧。最后的最后,以上是本人实战研究的一下小经验,也给后来者一点提醒吧,不用走太多弯路。
2023-01-30 - 关于XR-Frame中clear-color颜色设置的说明
在使用XR-Frame时,可能经常会使用到 clear-color="0.4 0.6 0.7 1" 这样的颜色设置,如下: <xr-camera position="0 1 4" clear-color="0.4 0.6 0.7 1" background="skybox" target="target" camera-orbit-control="" /> 这个颜色代码具体是什么意思呢? 首先,前三个参数代表颜色代码,第四个参数代表透明度(0-1)。 其次,对于前三个参数来说,这不是RGB的颜色方法,因为RGB的颜色方法是表示红、绿和蓝三原色的相对亮度值。例如,(255,0,0) 表示的是红色,它的RGB颜色方法的值是(1,0,0),表示红色是由100%红色,0%绿色和0%蓝色组成。 而(0.1, 0.1, 0.1) 是RGB颜色模型中使用的RGB颜色空间值的归一化版本(从0到1)。它并没有实际的颜色含义,但它可以被用来表示非常暗的灰色。 运算方法: rgb颜色值 除以 255即可! 如:RGB(227,176,242) 227/255 = 0.89 176/255 = 0.69 242/255 = 0.94 (保留两位小数) 归一化处理后即 为(0.89 0.69 0.94) 保持不透明(0.89,0.69,0.94,1)
2023-03-24 - 2022-03-04
- 如何彻底解决小程序滚动穿透问题
背景 俗话说,产品有三宝:弹窗、浮层加引导,足以见弹窗在产品同学心目中的地位。对任意一个刚入门的前端同学来说,实现一个模态框基本都可以达到信手拈来的地步,但是,当模态框里边的内容滚动起来以后,就会出现各种各样的让人摸不着头脑的问题,其中,最出名的想必就是滚动穿透。 什么是滚动穿透? 滚动穿透的定义:指我们滑动顶层的弹窗,但效果上却滑动了底层的内容。 具体解决方案分析如下: 改变顶层:从穿透的思路考虑,如果顶层不会穿透过去,那么问题就解决了,所以我们尝试给蒙层加catchtouchmove,但是发现部分场景无效果,那么就不再赘述了。 改变底层:既然是顶层影响了底层,要是底层不会滚动,那就没这个问题了。 如何改变底层解决该问题呢? 不成熟方案: 底部页面最外层view设置position: fixed;页面不可滚动,但是这个时候会导致页面回到顶部。 滚动时监听滚动距离,弹窗时记录滚动位置,关闭弹窗后使用wx.pageScrollTo回滚到记录的位置。 成熟方案 使用page-meta组件,通过该组件我们可以操作Page的style样式,类似于h5里body设置overflow: hidden; 控制页面不可滚动。文档地址:https://developers.weixin.qq.com/miniprogram/dev/component/page-meta.html 使用wx.setPageStyle设置overflow: hidden, 也可以实现给Page组件设置样式。) page-meta组件: 通过该组件我们可以直接操作[代码]Page[代码]组件 ,我们给它的wxss样式overflow动态设置[代码]hidden[代码]or[代码]visible[代码]or[代码]auto[代码] 就可以控制整个页面是否可以滚动。 [图片] wx.setPageStyle方法: 调用这个api,动态设置它为hidden/auto,用于控制页面是否可滚动,主要用于页面组件内使用,比如封装好的弹窗组件,就不用单独写page-meta组件了。。 [代码]wx.setPageStyle({ style: { overflow: 'hidden' // ‘auto’ } }) [代码] 老规矩,结尾放代码片段: https://developers.weixin.qq.com/s/U6ItgQmP7upQ 拓展 支付宝小程序虽然存在page-meta组件,但是由于内核为69版本,给page设置overflow: hidden 也无法控制底部元素不可滚动,目前已联系支付宝的底层开发同学提供API控制页面disableScroll,目前正在封装Appx,近期开放。 [代码] my.setPageScrollable({ scrollable: true, success: res => { console.log(res); }, fail: err => { console.log(err); }, complete: res => { console.log(res); } }) [代码] 20250618. API已开放,支付宝小程序测试时发现bug,安卓设置禁止滚动后,弹窗内的可滚动区域也会被禁止,IOS正常,且该问题暂时无法解决。 原因: 由于系统实现层面的差异,安卓与 iOS 对于滚动禁止的层级控制存在区别: 安卓端采用 Webview 级滚动限制(全页面锁定),生效时界面及所有弹层均不可滚动; iOS 端采用组件级滚动限制(局部锁定),当弹层激活时会智能区分层级,仅限制底层页面滚动而保持弹层可滚动。
06-18 - 小程序获取手机号,getPhoneNumber回调中获取不到code
[图片] [图片] 不是代码问题!微信开发工具切换基础库版本或者让用户手动更新微信版本即可解决! 1)确认当前基础库版本是否为 2212及以上。 2)目前开发者工具稳定版未兼容此表现 (近期应该会同步)。 3)正常情况下,基础库2.212对应的是客户端版本号为 8.0.16,如果你的版本低于 8.0.16并且是通过开发者工具向客户端推送的 2.21.2 基础库,大几率不会返回 code 参数,请手动更新微信版本
2023-06-07 - “分享监听”能力调整
近期我们收到了很多用户对小程序/小游戏中分享功能的投诉:在某些小程序/小游戏中,分享并非是用户主动自发的行为,而是受到了某类利益的诱惑,或是被迫分享。这样的内容充斥在群里、小程序里,对用户造成了骚扰。 分享功能,旨在帮助用户更流畅地与好友分享内容和服务,应是用户自发的行为。在原来的分享接口中,用户发起分享动作之后,可以通过 [代码]success[代码] 、[代码]fail[代码]、[代码]complete[代码]等回调来判断用户是否完成了最后的分享动作。通过这个能力,开发者可以将产品交互在分享这个能力上做得比较自然和顺畅。现在为鼓励用户自发分享喜爱的内容,减少“强制分享至不同群”等滥用分享能力,破坏用户体验的行为,在我们权衡了分享功能带来的利弊后,分享功能将进行以下调整: 10月10日起新提交发布的版本,不再支持分享回调参数 [代码]success[代码] 、[代码]fail[代码] 、[代码]complete[代码],即用户从小程序/小游戏中分享消息给好友时,开发者将无法获知用户是否分享完成,也无法在分享后立即获得分享成功后的回调参数[代码]shareTicket[代码]。该调整可以在基础库 2.3.0及以上版本体验。 此次调整可能影响到三种分享功能的用法。 第一种:判断用户是否分享成功,进而给予用户奖励。 例如:小程序提示用户“分享到5个群,可以获得一张20元的优惠券”。 这类诱导用户分享的行为是我们平台所不倡导的,后续将没有办法实现。 第二种:分享完成后变更当前的页面状态 例如:赠送礼品场景下,用户点击“赠送”按钮,将礼品分享出去,分享成功后,界面展示“等待领取”。 这类场景,我们建议可以适当调整交互方案。例如在分享后继续保留“赠送”按钮,但在页面上提示用户一个礼品只能被一人领取,重复赠送无效。 第三种:通过用户分享之后的 [代码]shareTicket[代码] 获取群唯一标识 [代码]openGId[代码] ,以显示对应群的相关信息。 例如:通过分享小程序到某个群里,可以查看该群内成员的排行榜。 此次调整后,用户分享完成后无法立刻显示该群的排行榜信息,但仍可在用户从群消息点击进入小程序时显示该群的排行榜信息。 10月10日起新提交发布的版本将会受到此调整的影响。 需要各位开发者注意,10月10日起新提交发布的版本将会受到此策略的影响,请及时调整分享相关能力,考虑兼容上述调整带来的影响。 调整策略在基础库 2.3.0 及以上版本生效,该基础库版本对应微信客户端6.7.2版本。另外,考虑到兼容性等问题,在基础库版本 2.3.0 以下的环境中不受此策略影响,小程序/小游戏可继续获取分享回调事件。
2018-09-13 - 缺陷修改实践——replace函数的运用 | 思考?
介绍 大家好,我是清风。今天给大家分享一个项目中遇到问题解决问题的案例,编程其实就是一个思考的过程,缺少思考就没有灵魂,遇到问题先静下心去思考,想到方法后再去实践。我们要学会灵活变通去解决问题,掌握方法,这样才能举一反三,临危不乱,遇到所有问题都能很好地去解决。 事情是这样的,做的一个答题小程序,要求在后台编辑题目,编辑题目是用的[代码]textarea[代码]文本域,即输入的是文本内容,配置之后小程序里查询显示后台配置的题目列表。 [图片] 当然在测试时后台去配置文本内容,小程序显示是没有问题的。因为配置的题目是纯文本,小程序里也是直接在[代码]text[代码]里显示的,没有问题。 后台配置题目 [图片] 小程序显示题目 [图片] 问题出现 问题往往只有在用的时候才会发现,用户或管理员的各种操作才能显现出各种问题。现在小程序里已经不能正常显示了,有些显示的是html格式富文本格式,有些不显示。显然和需求大相径庭,已经出现问题了。 问题分析 [图片] 如上图,在用的时候因为是从[代码]word[代码]文档里直接复制过去的题目(事先在word里整理好了题目,由于各部门工作对接,先是在word文档进行审核),直接复制会把富文本内容也携带过去,携带过去的当然也有[代码]style[代码]样式,小程序里不显示的原因是富文本的字体颜色是黑色字体,和小程序面背景都是黑色,导致看不到文字。打开控制台调试,问题确实是这么出现的。 [图片] word文档编辑的题目会出现不同的富文本的样式格式,这都会导致小程序的不正常显示。 [图片] 富文本的文字颜色是黑色,这导致的小程序页里题目的不显示。 解决方法 既然后台有可能出现富文本,我们直接把小程序题目的渲染方式换成富文本渲染,这样就算是纯文本也可以显示的。而第二个问题,由于小程序页面背景颜色是黑色,所以题目的字体颜色不能是黑色,我们做一个查找替换,把style样式里的字体样式替换掉就可以了。 优化 样式可能是各种各样的,通过查找style样式里的字体样式考虑的匹配太多了,比如说color属性值可以是rgb形式,也可是rgba形式,也可能是#号颜色值形式,还有可能是英文形式颜色,所以不可取。我们换一种思路,直接把style属性替换掉,即查找到style,换成一个无效的属性名。案例中我们替换成了[代码]c[代码],[代码]c[代码]是一个无效的属性,不会触发节点的查找和计算。 replace函数 我们用到replace函数,[代码]replace()[代码]方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。 参数 regexp/substr,必需。规定子字符串或要替换的模式的 RegExp 对象。 replacement,必需。一个字符串值。规定了替换文本或生成替换文本的函数。 [代码]请注意,regexp/substr 是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp对象[代码],返回值是一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。 实现 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。 [代码] that.setData({ _list: res.data }) let data = that.data._list data.forEach((element, index) => { var stemContent = '_list[' + index + '].stemContent' that.setData({ [stemContent]: element.stemContent.replace(/style/g, 'c') }) element.choiceTopicVos.forEach((item, i) => { var listCheck = '_list[' + index + '].choiceTopicVos[' + i + '].optionDes'; that.setData({ [listCheck]: item.optionDes.replace(/style/g, 'c') }) }) }) [代码] 用到的replace函数,进行了字符串的查找替换,查找到style属性,把它替换到了无效的属性c,没有了样式属性,从而达到了去除内联样式的效果,经过调试,完美解决问题。 [图片] 总结 [图片] 这是一个小问题,我为什么要拿出来说呢?抛去开发的测试流程不说,我认为它能引发一些思考。写代码的过程必须是一个思考的过程,怎么样更好地去实现效果,怎么样更简单有效地解决问题,怎么样优化,要去考虑一个大的方面。善于发现问题,解决问题,并不是说用了什么高级语言就鄙弃了思考,机器语言是相通的,开发中各种各样地应用才是魅力所在。编程是一门是艺术,最重要的是你怎样去巧妙地运用,就像解一道数学题,精绝巧妙的解法会让人眼前一亮,增色太多。同样都做出来了,但是你做的就显得十分优雅! 方法都是思考出来的,能高效解决问题的方法就是好方法,大家如果还有更好的解决方法欢迎评论区留言
2022-11-23 - JavaScript小技巧【建议收藏】
在JavaScript世界里,有些操作会让你无法理解,但是却无比优雅! 有时候读取变量属性时,他可能不是Ojbect。这个这个你就要判断这个变量是否为对象,如果是在如引用 [代码]var obj; if(obj instanceof Object){ console.log(obj.a); }else{ console.log('对象不存在'); } [代码] ES6中有简便写法,可以帮我们简短代码,从而更加明确 [代码]var obj; console.log(obj?.a || '对象不存在'); [代码] 1,2,3,4,5,6…10,11,12 小于10的前面补0 其实我们用slice函数可以巧妙解决这个问题 slice(start,end); start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。 end :可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。 [代码]var list=[1,2,3,4,5,6,7,8,9,10,11,12,13]; list=list.map(ele=>('0' + ele).slice(-2)); console.log(list); [代码] [图片] 打印可视化console.table() [代码]var obj = { name: 'Jack' }; console.table(obj); obj.name= 'Rose'; console.table(obj); [代码] [图片] 获取数组中的最后的元素 数组方法slice()可以接受负整数,如果提供它,它将从数组的末尾开始截取数值,而不是开头。 [代码]let array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; console.log(array.slice(-1)); // Result: [9] console.log(array.slice(-2)); // Result: [8, 9] console.log(array.slice(-3)); // Result: [7, 8, 9] [代码] es6模板字符串 [代码]let name = "Charlse" let place = "India"; let isPrime = bit =>{ return (bit === 'P'? 'Prime' : 'Nom-Prime') } let messageConcat = `Mr.name' is form ${place} .He is a ${isPrime('P')} member`; [代码] H5语音合成 在网页端实现将指定的文字进行语音合成并进行播报。 使用HTML5的Speech Synthesis API就能实现简单的语音合成效果。 [代码]<input id="btn1" type="button" value="点我" onclick="test();" /> <script> function test() { const sos = `阿尤!不错哦`; const synth = window.speechSynthesis; let msg = new SpeechSynthesisUtterance(sos); synth.speak(msg) } </script> [代码] 然后点击按钮,就会触发test方法的执行实现语音合成 这里推荐使用Chrome浏览器,因为HTML5的支持度不同 数字取整 [代码]let floatNum = 100.5; let intNum = ~~floatNum; console.log(intNum); // 100 [代码] [图片] 字符串转数字 [代码]let str="10000"; let num = +str; console.log(num); // 10000 [代码] 交换对象键值 [代码]let obj = { key1: "value1", key2: "value2" }; let revert = {}; Object.entries(obj).forEach(([key, value]) => revert[value] = key); console.log(revert); [代码] [图片] 数组去重 [代码]let arrNum = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]; let arrString = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ]; let arrMixed = [ 1, "1", "2", true, false, false, 1, 2, "2" ]; arrNum = Array.from(new Set(arrNum)); arrString = [...new Set(arrString)]; arrMixed = [...new Set(arrMixed)]; console.log(arrNum); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] console.log(arrString); // ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] console.log(arrMixed); // [1, "1", "2", true, false, 2] [代码] 数组转化为对象 [代码]const arr = [1,2,3] const obj = {...arr} console.log(obj) [代码] 合并对象 [代码]const obj1 = { a: 1 } const obj2 = { b: 2 } const combinObj = { ...obj1, ...obj2 } console.log(combinObj) [代码] 也就是通过展开操作符(spread operator)来实现。 获取数组中的最后一项 [代码]let arr = [0, 1, 2, 3, 4, 5]; const last = arr.slice(-1)[0]; console.log(last); [代码] 一次性函数,适用于初始化的一些操作 [代码]var sca = function() { console.log('msg')//永远只会执行一次 sca = function() { console.log('foo') } } sca() // msg sca() // foo sca() [代码] 提高工作效率,减少代码量,降低键盘磨损程度 我希望你喜欢它并学到了一些新东西 感谢你的阅读,编程快乐!
2022-10-25 - uniapp|微信小程序获取当前城市名称--逆地址解析
问题 uniapp开发的小程序需要获取当前城市名称 解决步骤 看文档 当然是看uniapp文档,我们查到有提供相关的API,即[代码]uni.getLocation(OBJECT)[代码],获取当前的地理位置、速度。 [图片] 我们试试吧 [代码]uni.getLocation({ type: 'wgs84', geocode:true, success: function (res) { console.log('当前位置的经度:' + res.longitude); console.log('当前位置的纬度:' + res.latitude); } }); [代码] 我们发现只能返回经纬度信息,并不会返回城市信息。 [图片] 原来是只有app才支持geocode 哈哈事情没有想象中那么简单~ [图片] 思考ing… 查阅了相关资料,[代码]原来是位置详细信息的一些保密协议,并不能直接获取到[代码]。那么我们就需要通过经纬度,利用腾讯地图JavaScript SDK逆地址解析,即输入坐标返回地理位置信息。 有方法了,开整 逆地址解析 1. 创建应用 打开腾讯地图开放平台,创建应用 [图片] 然后 控制台 ->应用管理 -> 我的应用 ->添加key-> 勾选 [图片] [代码]小程序SDK需要用到webserviceAPI的部分服务,所以使用该功能的KEY需要具备相应的权限[代码] [代码]授权ip即当前连接服务的IP地址(注意:上线后这个一定要换成上线IP地址哦)[代码] [代码]填入微信小程序appid[代码] [图片] 现在有了地图秘钥key 2. uniapp配置 pages.json配置 加入以下配置项,用于申请获得位置权限 [代码]"permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } } [代码] uniapp配置 [图片] [代码]这里填写的描述信息就是微信弹起信息微信授权弹框的描述信息[代码] [图片] 3. 代码部分 下载微信小程序JavaScriptSDK [代码]var QQMapWX = require('@/utils/qqmap-wx-jssdk.min.js'); // 实例化API核心类 var qqmapsdk = new QQMapWX({ key: '' // 必填 }); [代码] [代码]key即申请的腾讯地图秘钥key[代码] [代码]uni.getLocation({ type: 'gcj02', geocode: true, success: function (res) { //逆地址解析 坐标转地址信息 qqmapsdk.reverseGeocoder({ //Object格式 location: { latitude: res.latitude, longitude: res.longitude }, success: function(res) {//成功后的回调 const mapdata=res.result.ad_info; that.city = mapdata.city; },fail: function(error) { console.error(error); }, complete: function(res) { //console.log(res); } }); } }); [代码] 编译 [图片] 我们看返回信息 [图片] 现在是有返回当前位置详细信息了,当前也包括城市名称。 问题解决! 总结 遇到问题并不可怕,可怕的是停滞不前,知难而退。只有发现问题才能解决问题,才会得到成长和锻炼。人生的路总是一波三折,代码也是,风雨之后总会见到彩虹的,加油! 七年代码两茫茫,不思量,自难忘 🌈7年资深前端主管一枚,只分享技术干货,项目实战经验,面试指导 关注博主不迷路~
2022-10-21 - 微信小程序生成海报图片导出相册
前言 小程序内通过静态模板和样式绘制 canvas ,导出图片,可用于生成分享图等场景 一、效果预览 点击生成海报 [图片] 这个是生成的保存到相册的图片 [图片] 二、使用步骤 1.安装引入wxml-to-canvas Step1.运行小程序npm安装命令 [代码]npm install --save wxml-to-canvas [代码] Step2.JSON 组件声明 [代码]{ "usingComponents": { "wxml-to-canvas": "wxml-to-canvas", } } [代码] 文章最后会有wxml-to-canvas的其它详细教程 2.创建js 创建的js放到页面文件夹即可 [图片] 代码如下(demo.js): [代码]var calendar = require('../../../utils/calendar'); var d=new Date(); let Year = d.getFullYear(); let Month = (d.getMonth()+1).toString().padStart(2,'0'); let Day = (d.getDate()).toString().padStart(2,'0'); let time = Month+ '/' + Day; let xq = "星期"+"天一二三四五六".charAt(d.getDay()); const wxml = (hb_describe,hb_bg,hb_wx2code)=>{ return ` <view class="container" > <view class="itembox1"> <text class="time">`+time+`</text> <view class="xqview"> <text class="xq">`+xq+`</text> <text class="xq2">`+calendar.default.solar2lunar(Year,Month,Day).gzYear+'年'+calendar.default.solar2lunar(Year,Month,Day).IMonthCn+calendar.default.solar2lunar(Year,Month,Day).IDayCn+`</text> </view> </view> <view class="itembox2"> <image class="img" mode="aspectFit" src="`+hb_bg+`"></image> </view> <view class="itembox3"> <text class="text">`+hb_describe+`</text> <image class="imgcode" src="`+hb_wx2code+`"></image> </view> </view> ` } let width=wx.getSystemInfoSync().windowWidth*0.8; let widthCenter=width*0.9; let width6=widthCenter*0.6;//描述占60% let width4=widthCenter*0.4; const style = { container: { width: width, height: 450, flexDirection: 'column', backgroundColor: '#FFFFFF', alignItems: 'center' }, itembox1: { width: widthCenter, height: 130 }, itembox2: { width: widthCenter, height: 200 }, itembox3: { width: widthCenter, height: 120, flexDirection: 'row', justifyContent:'space-around', alignItems: 'center', //paddingTop:20, //paddingBottom:20 }, time:{ fontSize:88, color:'#0222AC', textAlign:'center', fontStyle:'italic' }, xqview:{ fontSize:16, color:'#0222AC', marginTop:106 }, xq:{ textAlign:'left' }, xq2:{ textAlign:'right' }, img: { width: widthCenter, minHeight: 190, maxHeight: 200, }, imgcode: { width: 80, height: 80 }, text: { width: width6, height: 60, textAlign: 'center', verticalAlign: 'middle' } } module.exports = { wxml, style } [代码] 3.小程序页面 wxml: [代码]<!-- 海报 --> <view class="hbbox" wx:if="{{maskHidden}}"> <wxml-to-canvas class="widget" height='{{canvasH}}'></wxml-to-canvas> </view> <view class="padding-sm margin-top flex flex-direction renderToCanvas" wx:if="{{hexiao}}"> <button bindtap="renderToCanvas" class="cu-btn">活动打卡</button> </view> <view class='hbmask' hidden="{{maskHidden == false}}"> <button class='hbbaocun' hidden="{{maskHidden == false}}" bindtap='extraImage'>保存相册</button> </view> <!-- 海报end --> [代码] js: 博主这里是打开一个弹窗 在弹窗里展示生成海报,js代码全部放出来,可自行取用。 [代码]const { wxml, style } = require('./demo.js') Page({ data: { //海报 hb_wx2code: "", hb_bg: "", hb_describe: '', maskHidden: false, canvasH: 0, number:0, flag:'' }, //生成海报 makeHB(){ let that = this; that.setData({ maskHidden: true, canvasH:570 }) setTimeout(()=>{ const _wxml = wxml(that.data.hb_describe,that.data.hb_bg,that.data.hb_wx2code) wx.nextTick(()=>{ that.widget = that.selectComponent('.widget') const p1 = that.selectComponent('.widget').renderToCanvas({ wxml:_wxml , style }) p1.then((res) => { wx.hideToast(); that.container = res; }).catch(err=>{ }) }) },500) }, renderToCanvas() { let that = this; if(that.data.hb_wx2code){ wx.showToast({ title: '海报生成中...', icon: 'loading', duration: 1000 }); that.makeHB(); } else{ wx.showToast({ title: '海报生成中...', icon: 'loading', duration: 1000 }); const data={ open_id : wx.getStorageSync('openId'), type: '2', video_id:that.data.id } mycomm.ajaxDataGet("/inviteFriends/ordinary", data, function (res) { that.setData({ hb_wx2code: res.val.qr_code, hb_bg:res.val.background_img, hb_describe:res.val.describe }); that.makeHB(); }, true); } }, extraImage() { const p2 = this.widget.canvasToTempFilePath() p2.then(res => { // this.setData({ // src: res.tempFilePath, // width: this.container.layoutBox.width, // height: this.container.layoutBox.height // }) this.baocun(res.tempFilePath); }) }, //点击保存到相册 baocun: function (imagePath) { var that = this wx.saveImageToPhotosAlbum({ filePath: imagePath, success(res) { wx.showModal({ content: '海报已保存到相册', showCancel: false, confirmText: '确定', confirmColor: '#333', success: function (res) { if (res.confirm) { /* 该隐藏的隐藏 */ that.setData({ maskHidden: false }) } }, fail: function (res) {} }) } }) }, }) [代码] 4.农历日期js 这个是海报上根据当前日期对应的农历日期,不需要可以自行删除掉。 [代码]var calendar = { /** * 农历1900-2100的润大小信息表 * @Array Of Property * @return Hex */ lunarInfo:[0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909 0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919 0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929 0x06566,0x0d4a0,0x0ea50,0x16a95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939 0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949 0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959 0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969 0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979 0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989 0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x05ac0,0x0ab60,0x096d5,0x092e0,//1990-1999 0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009 0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019 0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029 0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039 0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049 /**Add By JJonline@JJonline.Cn**/ 0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059 0x092e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069 0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079 0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089 0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099 0x0d520],//2100 /** * 公历每个月份的天数普通表 * @Array Of Property * @return Number */ solarMonth:[31,28,31,30,31,30,31,31,30,31,30,31], /** * 天干地支之天干速查表 * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"] * @return Cn string */ Gan:["\u7532","\u4e59","\u4e19","\u4e01","\u620a","\u5df1","\u5e9a","\u8f9b","\u58ec","\u7678"], /** * 天干地支之地支速查表 * @Array Of Property * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"] * @return Cn string */ Zhi:["\u5b50","\u4e11","\u5bc5","\u536f","\u8fb0","\u5df3","\u5348","\u672a","\u7533","\u9149","\u620c","\u4ea5"], /** * 天干地支之地支速查表<=>生肖 * @Array Of Property * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"] * @return Cn string */ Animals:["\u9f20","\u725b","\u864e","\u5154","\u9f99","\u86c7","\u9a6c","\u7f8a","\u7334","\u9e21","\u72d7","\u732a"], /** * 阳历节日 */ festival: { '1-1': {title: '元旦节'}, '2-14': {title: '情人节'}, '5-1': {title: '劳动节'}, '5-4': {title: '青年节'}, '6-1': {title: '儿童节'}, '9-10': {title: '教师节'}, '10-1': {title: '国庆节'}, '12-25': {title: '圣诞节'}, '3-8': {title: '妇女节'}, '3-12': {title: '植树节'}, '4-1': {title: '愚人节'}, '5-12': {title: '护士节'}, '7-1': {title: '建党节'}, '8-1': {title: '建军节'}, '12-24': {title: '平安夜'}, }, /** * 农历节日 */ lfestival: { '12-30': {title: '除夕'}, '1-1': {title: '春节'}, '1-15': {title: '元宵节'}, '5-5': {title: '端午节'}, '8-15': {title: '中秋节'}, '9-9': {title: '重阳节'}, }, /** * 返回默认定义的阳历节日 */ getFestival(){ return this.festival }, /** * 返回默认定义的内容里节日 */ getLunarFestival(){ return this.lfestival }, /** * * @param {Object} 按照festival的格式输入数据,设置阳历节日 */ setFestival(param={}){ this.festival = param }, /** * * @param {Object} 按照lfestival的格式输入数据,设置农历节日 */ setLunarFestival(param={}){ this.lfestival = param }, /** * 24节气速查表 * @Array Of Property * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"] * @return Cn string */ solarTerm:["\u5c0f\u5bd2","\u5927\u5bd2","\u7acb\u6625","\u96e8\u6c34","\u60ca\u86f0","\u6625\u5206","\u6e05\u660e","\u8c37\u96e8","\u7acb\u590f","\u5c0f\u6ee1","\u8292\u79cd","\u590f\u81f3","\u5c0f\u6691","\u5927\u6691","\u7acb\u79cb","\u5904\u6691","\u767d\u9732","\u79cb\u5206","\u5bd2\u9732","\u971c\u964d","\u7acb\u51ac","\u5c0f\u96ea","\u5927\u96ea","\u51ac\u81f3"], /** * 1900-2100各年的24节气日期速查表 * @Array Of Property * @return 0x string For splice */ sTermInfo:['9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf97c3598082c95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f','b027097bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f','97bd0b06bdb0722c965ce1cfcc920f','b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f','97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa','9778397bd19801ec9210c965cc920e','97b6b97bd19801ec95f8c965cc920f', '97bd09801d98082c95f8e1cfcc920f','97bd097bd097c36b0b6fc9210c8dc2','9778397bd197c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e','97bd09801d98082c95f8e1cfcc920f','97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec95f8c965cc920e','97bcf97c3598082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e','97bcf97c3598082c95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f','97bd097bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9210c8dc2','9778397bd19801ec9210c9274c920e','97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f','97bd07f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec9210c965cc920e','97bd07f1487f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e','97bcf7f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c9274c920e','97bcf7f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c91aa','97b6b97bd197c36c9210c9274c920e','97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c920e', '97b6b7f0e47f531b0723b0b6fb0722','7f0e37f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b70c9274c91aa','97b6b7f0e47f531b0723b0b6fb0721','7f0e37f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc9210c8dc2','9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0787b0721','7f0e27f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c91aa','97b6b7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9210c8dc2','977837f0e37f149b0723b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722','7f0e37f5307f595b0b0bc920fb0722','7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0721','7f0e37f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc9210c8dc2','977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0723b06bd','7f07e7f0e37f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722','7f0e37f1487f595b0b0bb0b6fb0722','7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0722','7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f531b0b0bb0b6fb0722','7f0e37f0e37f14898082b072297c35','7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f149b0723b0787b0721', '7f0e27f1487f531b0b0bb0b6fb0722','7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14998082b0723b06bd', '7f07e7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722','7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd','7f07e7f0e37f14998083b0787b0721','7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14898082b0723b02d5','7f07e7f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722','7f0e36665b66aa89801e9808297c35','665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0722','7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721', '7f0e36665b66a449801e9808297c35','665f67f0e37f14898082b072297c35','7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721','7f0e26665b66a449801e9808297c35','665f67f0e37f1489801eb072297c35', '7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722'], /** * 数字转中文速查表 * @Array Of Property * @trans ['日','一','二','三','四','五','六','七','八','九','十'] * @return Cn string */ nStr1:["\u65e5","\u4e00","\u4e8c","\u4e09","\u56db","\u4e94","\u516d","\u4e03","\u516b","\u4e5d","\u5341"], /** * 日期转农历称呼速查表 * @Array Of Property * @trans ['初','十','廿','卅'] * @return Cn string */ nStr2:["\u521d","\u5341","\u5eff","\u5345"], /** * 月份转农历称呼速查表 * @Array Of Property * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊'] * @return Cn string */ nStr3:["\u6b63","\u4e8c","\u4e09","\u56db","\u4e94","\u516d","\u4e03","\u516b","\u4e5d","\u5341","\u51ac","\u814a"], /** * 农历年份数字称呼速查表 * @Array Of Property * @trans ['零','一','二','三','四','五','六','七','八','九','十'] * @return Cn string */ nStr4:["\u96f6","\u4e00","\u4e8c","\u4e09","\u56db","\u4e94","\u516d","\u4e03","\u516b","\u4e5d","\u5341"], /** * 返回农历y年一整年的总天数 * @param lunar Year * @return Number * @eg:var count = calendar.lYearDays(1987) ;//count=387 */ lYearDays:function(y) { var i, sum = 348; for(i=0x8000; i>0x8; i>>=1) { sum += (this.lunarInfo[y-1900] & i)? 1: 0; } return(sum+this.leapDays(y)); }, /** * 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 * @param lunar Year * @return Number (0-12) * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 */ leapMonth:function(y) { //闰字编码 \u95f0 return(this.lunarInfo[y-1900] & 0xf); }, /** * 返回农历y年闰月的天数 若该年没有闰月则返回0 * @param lunar Year * @return Number (0、29、30) * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 */ leapDays:function(y) { if(this.leapMonth(y)) { return((this.lunarInfo[y-1900] & 0x10000)? 30: 29); } return(0); }, /** * 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 * @param lunar Year * @return Number (-1、29、30) * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 */ monthDays:function(y,m) { if(m>12 || m<1) {return -1}//月份参数从1至12,参数错误返回-1 return( (this.lunarInfo[y-1900] & (0x10000>>m))? 30: 29 ); }, /** * 返回公历(!)y年m月的天数 * @param solar Year * @return Number (-1、28、29、30、31) * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 */ solarDays:function(y,m) { if(m>12 || m<1) {return -1} //若参数错误 返回-1 var ms = m-1; if(ms==1) { //2月份的闰平规律测算后确认返回28或29 return(((y%4 == 0) && (y%100 != 0) || (y%400 == 0))? 29: 28); }else { return(this.solarMonth[ms]); } }, /** * 农历年份转换为干支纪年 * @param lYear 农历年的年份数 * @return Cn string */ toGanZhiYear:function(lYear) { var ganKey = (lYear - 3) % 10; var zhiKey = (lYear - 3) % 12; if(ganKey == 0) ganKey = 10;//如果余数为0则为最后一个天干 if(zhiKey == 0) zhiKey = 12;//如果余数为0则为最后一个地支 return this.Gan[ganKey-1] + this.Zhi[zhiKey-1]; }, /** * 公历月、日判断所属星座 * @param cMonth [description] * @param cDay [description] * @return Cn string */ toAstro:function(cMonth,cDay) { var s = "\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf"; var arr = [20,19,21,21,21,22,23,23,23,23,22,22]; return s.substr(cMonth*2 - (cDay < arr[cMonth-1] ? 2 : 0),2) + "\u5ea7";//座 }, /** * 传入offset偏移量返回干支 * @param offset 相对甲子的偏移量 * @return Cn string */ toGanZhi:function(offset) { return this.Gan[offset%10] + this.Zhi[offset%12]; }, /** * 传入公历(!)y年获得该年第n个节气的公历日期 * @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 * @return day Number * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 */ getTerm:function(y,n) { if(y<1900 || y>2100) {return -1;} if(n<1 || n>24) {return -1;} var _table = this.sTermInfo[y-1900]; var _info = [ parseInt('0x'+_table.substr(0,5)).toString() , parseInt('0x'+_table.substr(5,5)).toString(), parseInt('0x'+_table.substr(10,5)).toString(), parseInt('0x'+_table.substr(15,5)).toString(), parseInt('0x'+_table.substr(20,5)).toString(), parseInt('0x'+_table.substr(25,5)).toString() ]; var _calday = [ _info[0].substr(0,1), _info[0].substr(1,2), _info[0].substr(3,1), _info[0].substr(4,2), _info[1].substr(0,1), _info[1].substr(1,2), _info[1].substr(3,1), _info[1].substr(4,2), _info[2].substr(0,1), _info[2].substr(1,2), _info[2].substr(3,1), _info[2].substr(4,2), _info[3].substr(0,1), _info[3].substr(1,2), _info[3].substr(3,1), _info[3].substr(4,2), _info[4].substr(0,1), _info[4].substr(1,2), _info[4].substr(3,1), _info[4].substr(4,2), _info[5].substr(0,1), _info[5].substr(1,2), _info[5].substr(3,1), _info[5].substr(4,2), ]; return parseInt(_calday[n-1]); }, /** * 传入年份返回汉语通俗表示法 * @param {lunar} year * @return CN {string} * @eg:let cnYear = calendar.toChinaYear(1960);//cnYear = '一九六零' */ toChinaYear:function(y){ //年 let year = y.toString().split(""); return `${this.nStr4[year[0]]}${this.nStr4[year[1]]}${this.nStr4[year[2]]}${this.nStr4[year[3]]}`; }, /** * 传入农历数字月份返回汉语通俗表示法 * @param lunar month * @return Cn string * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' */ toChinaMonth:function(m) { // 月 => \u6708 if(m>12 || m<1) {return -1} //若参数错误 返回-1 var s = this.nStr3[m-1]; s+= "\u6708";//加上月字 return s; }, /** * 传入农历日期数字返回汉字表示法 * @param lunar day * @return Cn string * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' */ toChinaDay:function(d){ //日 => \u65e5 var s; switch (d) { case 10: s = '\u521d\u5341'; break; case 20: s = '\u4e8c\u5341'; break; break; case 30: s = '\u4e09\u5341'; break; break; default : s = this.nStr2[Math.floor(d/10)]; s += this.nStr1[d%10]; } return(s); }, /** * 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春” * @param y year * @return Cn string * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' */ getAnimal: function(y) { return this.Animals[(y - 4) % 12] }, /** * 传入阳历年月日获得详细的公历、农历object信息 <=>JSON * @param y solar year * @param m solar month * @param d solar day * @return JSON object * @eg:console.log(calendar.solar2lunar(1987,11,01)); */ solar2lunar:function (y,m,d) { //参数区间1900.1.31~2100.12.31 y = parseInt(y) m = parseInt(m) d = parseInt(d) //年份限定、上限 if(y<1900 || y>2100) { return -1;// undefined转换为数字变为NaN } //公历传参最下限 if(y==1900&&m==1&&d<31) { return -1; } //未传参 获得当天 if(!y) { var objDate = new Date(); }else { var objDate = new Date(y,parseInt(m)-1,d) } var i, leap=0, temp=0; //修正ymd参数 var y = objDate.getFullYear(), m = objDate.getMonth()+1, d = objDate.getDate(); var offset = (Date.UTC(objDate.getFullYear(),objDate.getMonth(),objDate.getDate()) - Date.UTC(1900,0,31))/86400000; for(i=1900; i<2101 && offset>0; i++) { temp = this.lYearDays(i); offset -= temp; } if(offset<0) { offset+=temp; i--; } //是否今天 var isTodayObj = new Date(), isToday = false; if(isTodayObj.getFullYear()==y && isTodayObj.getMonth()+1==m && isTodayObj.getDate()==d) { isToday = true; } //星期几 var nWeek = objDate.getDay(), cWeek = this.nStr1[nWeek]; //数字表示周几顺应天朝周一开始的惯例 if(nWeek==0) { nWeek = 7; } //农历年 var year = i; var leap = this.leapMonth(i); //闰哪个月 var isLeap = false; //效验闰月 for(i=1; i<13 && offset>0; i++) { //闰月 if(leap>0 && i==(leap+1) && isLeap==false){ --i; isLeap = true; temp = this.leapDays(year); //计算农历闰月天数 } else{ temp = this.monthDays(year, i);//计算农历普通月天数 } //解除闰月 if(isLeap==true && i==(leap+1)) { isLeap = false; } offset -= temp; } // 闰月导致数组下标重叠取反 if(offset==0 && leap>0 && i==leap+1) { if(isLeap){ isLeap = false; }else{ isLeap = true; --i; } } if(offset<0) { offset += temp; --i; } //农历月 var month = i; //农历日 var day = offset + 1; //天干地支处理 var sm = m-1; var gzY = this.toGanZhiYear(year); // 当月的两个节气 // bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year` var firstNode = this.getTerm(y,(m*2-1));//返回当月「节」为几日开始 var secondNode = this.getTerm(y,(m*2));//返回当月「节」为几日开始 // 依据12节气修正干支月 var gzM = this.toGanZhi((y-1900)*12+m+11); if(d>=firstNode) { gzM = this.toGanZhi((y-1900)*12+m+12); } //传入的日期的节气与否 var isTerm = false; var Term = null; if(firstNode==d) { isTerm = true; Term = this.solarTerm[m*2-2]; } if(secondNode==d) { isTerm = true; Term = this.solarTerm[m*2-1]; } //日柱 当月一日与 1900/1/1 相差天数 var dayCyclical = Date.UTC(y,sm,1,0,0,0,0)/86400000+25567+10; var gzD = this.toGanZhi(dayCyclical+d-1); //该日期所属的星座 var astro = this.toAstro(m,d); var solarDate = y+'-'+m+'-'+d var lunarDate = year+'-'+month+'-'+day var festival = this.festival var lfestival = this.lfestival var festivalDate = m+'-'+d var lunarFestivalDate = month+'-'+day return { date: solarDate, lunarDate: lunarDate, festival: festival[festivalDate] ? festival[festivalDate].title : null, lunarFestival: lfestival[lunarFestivalDate] ? lfestival[lunarFestivalDate].title : null, 'lYear':year, 'lMonth':month, 'lDay':day, 'Animal':this.getAnimal(year), 'IMonthCn':(isLeap?"\u95f0":'')+this.toChinaMonth(month), 'IDayCn':this.toChinaDay(day), 'cYear':y, 'cMonth':m, 'cDay':d, 'gzYear':gzY, 'gzMonth':gzM, 'gzDay':gzD, 'isToday':isToday, 'isLeap':isLeap, 'nWeek':nWeek, 'ncWeek':"\u661f\u671f"+cWeek, 'isTerm':isTerm, 'Term':Term, 'astro':astro }; }, /** * 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON * @param y lunar year * @param m lunar month * @param d lunar day * @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可] * @return JSON object * @eg:console.log(calendar.lunar2solar(1987,9,10)); */ lunar2solar:function(y,m,d,isLeapMonth) { //参数区间1900.1.31~2100.12.1 y = parseInt(y) m = parseInt(m) d = parseInt(d) var isLeapMonth = !!isLeapMonth; var leapOffset = 0; var leapMonth = this.leapMonth(y); var leapDay = this.leapDays(y); if(isLeapMonth&&(leapMonth!=m)) {return -1;}//传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同 if(y==2100&&m==12&&d>1 || y==1900&&m==1&&d<31) {return -1;}//超出了最大极限值 var day = this.monthDays(y,m); var _day = day; //bugFix 2016-9-25 //if month is leap, _day use leapDays method if(isLeapMonth) { _day = this.leapDays(y,m); } if(y < 1900 || y > 2100 || d > _day) {return -1;}//参数合法性效验 //计算农历的时间差 var offset = 0; for(var i=1900;i<y;i++) { offset+=this.lYearDays(i); } var leap = 0,isAdd= false; for(var i=1;i<m;i++) { leap = this.leapMonth(y); if(!isAdd) {//处理闰月 if(leap<=i && leap>0) { offset+=this.leapDays(y);isAdd = true; } } offset+=this.monthDays(y,i); } //转换闰月农历 需补充该年闰月的前一个月的时差 if(isLeapMonth) {offset+=day;} //1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) var stmap = Date.UTC(1900,1,30,0,0,0); var calObj = new Date((offset+d-31)*86400000+stmap); var cY = calObj.getUTCFullYear(); var cM = calObj.getUTCMonth()+1; var cD = calObj.getUTCDate(); return this.solar2lunar(cY,cM,cD); } }; export default calendar [代码] 附其它: wxml-to-canvas的使用 wxml 引入组件 [代码]<video class="video" src="{{src}}"> <wxml-to-canvas class="widget"></wxml-to-canvas> </video> <image src="{{src}}" style="width: {{width}}px; height: {{height}}px"></image> [代码] js 获取实例 [代码]const {wxml, style} = require('./demo.js') Page({ data: { src: '' }, onLoad() { this.widget = this.selectComponent('.widget') }, renderToCanvas() { const p1 = this.widget.renderToCanvas({ wxml, style }) p1.then((res) => { this.container = res this.extraImage() }) }, extraImage() { const p2 = this.widget.canvasToTempFilePath() p2.then(res => { this.setData({ src: res.tempFilePath, width: this.container.layoutBox.width, height: this.container.layoutBox.height }) }) } }) [代码] wxml模板支持 view、text、image 三种标签,通过 class 匹配 style 对象中的样式。 样式对象属性值为对应 wxml 标签的 class 驼峰形式。需为每个元素指定 width 和 height 属性,否则会导致布局错误。 存在多个 className 时,位置靠后的优先级更高,子元素会继承父级元素的可继承属性。 元素均为 flex 布局。left/top 等 仅在 absolute 定位下生效。
2023-06-07