关于uniapp:UniApp微信小程序解决苹果手机上方刘海屏遮挡的方法

大家好,我是你们的好敌人咕噜铁蛋!明天我要和大家分享一种解决苹果手机上方刘海屏遮挡的办法,特地实用于UniApp开发的微信小程序。如果你在开发过程中遇到了这个问题,无妨跟着我一起来看看如何解决吧!苹果手机的刘海屏设计给用户带来了更大的视觉享受,但对于开发者来说,它也带来了一些布局上的挑战,尤其是在微信小程序开发中。因而,咱们须要寻找一种办法来确保应用程序在苹果手机上可能失常显示,不被刘海屏遮挡。上面是解决的步骤: 理解苹果手机的刘海屏尺寸苹果手机的刘海屏通常有肯定的高度,咱们须要理解具体的尺寸以便进行布局调整。目前,iPhone X、iPhone XS、iPhone XR等机型都采纳了相似的刘海屏设计,其高度约为30px左右。应用CSS适配刘海屏在UniApp开发中,咱们能够应用CSS的safe-area-inset-top属性来适配刘海屏。这个属性能够获取到刘海屏的平安区域高度,并将布局进行调整,以确保内容不被刘海屏遮挡。在须要适配刘海屏的组件或页面中,能够增加以下款式代码: .selector { padding-top: constant(safe-area-inset-top); /* 兼容 iOS 12.0-12.1 */ padding-top: env(safe-area-inset-top); /* 兼容 iOS 11.0-11.4 */}通过应用这些款式,咱们能够在刘海屏手机上设置顶部内边距,以防止内容被刘海遮挡。 思考底部平安区域除了顶部的刘海屏之外,苹果手机还有底部的平安区域,通常用于虚构Home按钮。为了确保应用程序的内容不被底部平安区域遮挡,咱们也能够应用相似的CSS款式来适配,具体代码如下: .selector { padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS 12.0-12.1 */ padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS 11.0-11.4 */}通过增加这些款式,咱们能够设置底部的内边距,以防止内容被底部平安区域遮挡。 测试和调整在实现以上步骤后,咱们须要在理论设施上进行测试,确保应用程序在苹果手机上的显示成果合乎预期。如果依然存在布局问题,能够依据具体情况进行调整,尝试不同的款式或布局办法。通过理解苹果手机刘海屏的尺寸,应用CSS的safe-area-inset-top和safe-area-inset-bottom属性,咱们能够很好地解决UniApp微信小程序在苹果手机上方刘海屏遮挡的问题。这种适配办法简单易行,可能确保应用程序的失常显示,晋升用户体验。心愿这篇文章对你有所帮忙。如果你有其余对于UniApp开发或者苹果手机刘海屏适配的问题,欢送在评论区留言,咱们一起交流学习吧!感激大家的浏览,咱们下期再见!

February 28, 2024 · 1 min · jiezi

关于uniapp:客户管理crm系统软件源码CRM小程序源码php版带uniapp

 客户治理crm系统软件源码是一种为企业设计的数字工具,用于无效地组织、监控和保护无关现有和潜在客户的数据。该软件集中了来自各种潜在客户、流量、流动和收买起源的数据,并创立了记录和配置文件。该软件具备残缺客户数据库的存储库,涉众能够应用它来治理长期客户合同和关系。 局部源码:index_css.css body{ background-color: #EEEEEE;}.nav{ width: 100%; background-color: #fff; color:#3EABFF}.nav-div{ width:63%;margin: 20px auto}.body{ width: 80%; display: flex; justify-content: center; align-items: center; margin: 30px auto;}.footer{ width: 63%; margin: 30px auto; text-align: justify;}.footer h4{ margin-bottom: 0; color: black;}.footer p{ font-size: 14px;}blockquote{ margin: 0; border-left: .2rem solid #3EABFF; padding: .2em}.category button{ margin:0px 5px 5px; width: 70px;}.tel{ height:30px; text-align: right;}.tel h2,.tel h5{ display : inline;}.btn-primary-cus { color: #007bff; background-color: transparent; border-color: #007bff; box-shadow: none;}.btn-primary-cus:hover { color: #fff; background-color: #007bff; border-color: #007bff;}.btn-primary-full{ color: #fff; background-color: #007bff; border-color: #007bff;}.btn-primary-full:hover { color: #fff; background-color: #000dff; border-color: #007bff;}.nav-div h4{ font-size: 2.5rem;}.bg-white { background-color: #fff; color: #1f2d3d!important;}.p-3 { padding: 1rem!important;}.text-muted{ color:#5e5e5e;} 客户治理crm系统软件源码(CRM) 是一套集成的、数据驱动的软件解决方案,可帮忙治理、跟踪和存储与公司以后和潜在客户相干的信息。通过将这些信息保留在集中式零碎中,业务团队能够在须要时取得所需的见解。 如果没有集成 CRM 解决方案的反对,您的公司可能会错失增长机会并失去潜在支出,因为它没有优化经营流程或充分利用客户关系和销售线索。 客户治理crm系统软件源码装置过程 以下是客户治理crm系统软件源码装置过程的个别步骤: 1. 下载源码:从文章结尾处下载客户治理crm系统软件源码。 2. 装置本地开发环境:确保你的计算机上曾经装置了PHP、MySQL和Apache等必要的开发环境。 3. 创立数据库:应用MySQL或其余数据库管理工具创立一个新的数据库。 4. 配置数据库连贯:找到源码中的数据库配置文件(通常是config.php或database.php),依据你的数据库设置,批改连贯字符串、用户名和明码等参数。 5. 导入数据库构造:将源码中的数据库构造文件(通常是.sql文件)导入到你创立的数据库中,能够应用phpMyAdmin或MySQL命令行工具来执行导入操作。 6. 配置网站根目录:将源码中的所有文件复制到你的Web服务器的根目录下。 7. 设置文件权限:确保源码中的相干文件和目录(如上传目录、缓存目录)具备适当的写入权限。 8. 配置网站拜访门路:依据你的服务器环境,配置域名、虚拟主机或子目录的拜访门路。 9. 测试装置:在浏览器中拜访你设置的网站地址,如果一切正常,你应该可能看到CRM零碎的登录界面。 10. 初始化零碎设置:首次登录零碎时,你可能须要进行一些根本的配置,如设置管理员账号、公司信息等。 11. 装置实现:实现上述步骤后,你应该曾经胜利装置了客户治理crm系统软件源码,能够开始应用零碎了。 客户治理crm系统软件源码有什么作用? 不久前,公司通过电子表格、电子邮件、地址簿和其余孤立的、通常基于纸质的 CRM 解决方案来跟踪客户相干数据。不足集成和自动化妨碍了团队外部和团队之间的人员疾速查找和共享最新信息,从而升高了他们创立营销流动、寻求新销售线索和服务客户的能力。 到了明天,CRM 零碎主动收集无关现有和潜在客户的大量信息。这些数据包含电子邮件地址、电话号码、公司网站、社交媒体帖子、购买历史记录以及服务和反对票证。接下来,零碎会集成数据并生成综合档案,以便与适当的团队共享。 CRM 零碎还与其余业务工具连贯,包含在线聊天和文档共享应用程序。此外,它们还具备内置的商业智能和人工智能 (AI) 性能,可减速治理工作并提供可行的见解。 换句话说,古代CRM 工具使销售、营销、商务、现场服务和客户服务团队可能立刻理解并拜访对倒退、改善和保留客户关系至关重要的所有。 您能够通过以下形式应用 CRM 性能来使您的公司受害: 通过销售漏斗监控每个机会以取得更好的销售。CRM 解决方案有助于跟踪潜在客户相干数据并提供见解,因而销售和营销团队能够放弃东倒西歪,理解每个潜在客户在销售流程中的地位,并理解每个机会的负责人。 应用销售监控来获取实时绩效数据。将销售数据链接到您的 CRM 解决方案中,以提供即时、精确的销售状况。通过实时查看您的管道,您将理解任何放缓和瓶颈,或者您的团队是否博得了重大交易。 通过洞察生成来布局您的下一步。应用人工智能和内置智能来专一于最重要的事件,以确定最重要的优先事项以及您的团队如何充分利用他们的工夫和精力。例如,销售团队能够确定哪些潜在客户已筹备好移交,哪些须要跟进。 通过自动化优化工作流程。通过工作自动化构建销售报价、收集客户反馈并发送电子邮件流动,这有助于简化营销、销售和客户服务。因而,有助于打消重复性工作,以便您的团队能够专一于高影响力的流动。 跟踪客户互动以取得更大影响。CRM 解决方案包含利用客户行为和外表优化机会的性能,以帮忙您更好地理解各个客户接触点的参与度。 跨多个平台连贯以实现卓越的客户参加。无论是通过实时聊天、电话、电子邮件还是社交互动,CRM 解决方案都能够帮忙您与客户保持联系,帮忙建设信赖和忠诚度,从而吸引客户成为回头客。 麻利成长并取得竞争劣势。基于高度平安的平台构建的可扩大、集成的 CRM 解决方案有助于满足您的业务和市场一直变动的需要。疾速启动新的营销、电子商务和其余动作,并对消费者需要和市场情况做出疾速响应。 为什么施行客户治理crm系统软件源码? 当您定义 CRM 策略并评估客户关系治理解决方案时,请寻找可能提供每个客户关系的残缺视图的解决方案。您还须要一个解决方案来收集每个客户接触点的相干数据、剖析数据并智能地出现见解。 借助 CRM 零碎,您的公司能够帮忙增强沟通并确保客户旅程每个阶段的卓越体验,如下所述: 辨认并吸引适合的客户。预测性洞察和数据驱动的买家行为可帮忙您学习如何辨认、定位和吸引正确的潜在客户,而后将其转化为客户。 改善客户互动。通过对客户的全面理解,销售团队的每个成员都将理解客户的历史记录、购买模式以及任何具体数据,这些数据将帮忙您的团队为每个客户提供最周到的服务。 跟踪整个客户旅程的进度。理解客户在整个销售生命周期中的地位有助于您定位流动和机会以取得最高的参与度。 进步团队生产力。进步可见性和简化流程有助于进步生产力,帮忙您的团队专一于最重要的事件。 客户治理crm系统软件源码如何帮忙您的公司? 各种规模的公司都能够从 CRM 软件中受害。对于寻求倒退的小型企业,CRM 有助于实现业务流程自动化,使员工可能专一于更高价值的流动。对于企业来说,CRM 甚至能够帮忙简化和改善最简单的客户互动。 认真理解 CRM 零碎如何帮忙您的各个业务团队受害。 营销团队 改善客户的旅程。凭借生成多渠道营销流动的能力、通过有针对性的买家体验培养销售就绪的潜在客户以及使您的团队与布局和实时跟踪工具保持一致,您可能提出可能引起客户共鸣的精心策划的营销策略。 当您通过定制的数据分析仪表板深刻理解您的品牌名誉和市场时,您能够优先思考对您的业务最重要的潜在客户,并依据有针对性的自动化流程后果推动的见解和业务决策疾速适应。 销售团队 使卖家可能与客户互动,真正理解他们的需要,并无效博得更多交易。随着业务的增长,通过有针对性的销售策略寻找适合的潜在客户和客户变得更加容易,从而为您的管道下一步制订胜利的行动计划。 通过嵌入式洞察构建更理智的销售策略有助于造就关系、进步生产力、减速销售业绩并利用现代化且适应性强的平台进行翻新。通过应用能够掂量过来和当初当先指标的人工智能性能,您能够从始至终跟踪客户关系,并通过上下文提醒主动执行销售,从而提供个性化体验并随时随地与买家的旅程保持一致。 客户服务团队 为客户提供轻松的全渠道体验。通过应用服务机器人,您的客户服务团队将领有可能提供价值并进步每次交互参与度的工具。通过提供个性化服务,代理商能够应用相干的上下文数据进行追加销售或穿插销售,并依据反馈、考察和社交凝听,依据实时服务趋势优化其资源。 通过提供全渠道反对的疏导式智能服务,客户能够轻松地与客服人员分割并疾速解决问题,从而取得一流的客户体验。 ...

February 28, 2024 · 1 min · jiezi

关于uniapp:最新uniapp打包IOS详细步骤让你的APP在苹果设备上飞起来

嗨,各位敬爱的小伙伴们,我是你们好敌人咕噜铁蛋!在挪动利用开发的路线上,想要让本人的APP在iOS设施上失常运行并顺利上架App Store,就必须把握uni-app在iOS平台上的打包步骤。明天,我将为大家具体介绍最新的uni-app打包iOS的步骤,让你的APP在苹果设施上飞起来!一、筹备工作在开始打包之前,咱们须要先实现一些筹备工作。确保你曾经装置好Xcode,并且在uni-app我的项目中配置了正确的利用信息(如AppID、Bundle Identifier等),以及实现了必要的iOS开发者证书和形容文件的配置。二、生成签名密钥首先,咱们须要在uni-app我的项目中生成签名密钥。关上HBuilderX,在我的项目根目录下找到manifest.json文件,抉择“编译模式”为“生产模式”,而后点击“发行”-“原生App-生成打包资源”来生成签名密钥。三、配置打包参数接下来,咱们须要在HBuilderX中配置打包参数。抉择“发行”-“原生App-本地打包配置”来设置相干的打包参数,包含Xcode门路、开发者证书、形容文件等。四、执行打包命令实现以上步骤后,在HBuilderX中抉择“发行”-“原生App-发行到iOS平台”,期待打包过程实现。期间可能须要输出开发者证书明码等信息,依照提醒操作即可。五、在Xcode中进行调试打包实现后,咱们能够在Xcode中关上生成的.xcworkspace文件,连贯iOS设施进行调试测试。确保利用在真机上失常运行,并查看是否有异样问题须要修复。六、提交App Store审核最初一步是将打包好的利用提交到App Store进行审核。在Xcode中抉择“Product”-“Archive”,而后上传至App Store Connect进行审核流程,期待苹果官网审核通过后,你的APP就能够在App Store上线啦!通过以上具体步骤,置信大家曾经把握了uni-app在iOS平台上的打包流程。心愿这篇文章可能帮忙到正在进行iOS利用开发的小伙伴们,让你的APP在苹果设施上腾飞起来!如果你有任何问题或者想分享教训,欢送在评论区留言,咱们一起学习提高吧!感激大家的浏览,咱们下期再见!

February 25, 2024 · 1 min · jiezi

关于uniapp:unibest-uniapp-vue3-模板-UI-框架选型

背景unibest 作为最好的 uniapp 开发模板,那 UI 框架 的抉择也是要认真斟酌的。 unibest 作为 uniapp + vue3 + ts 的我的项目,天然也要抉择满足 vue3 的 UI库,所以像 vue2 时代的 uview 就不思考在内了。然而在 uview 的根底上衍生进去的反对 vue3 的 uview 系 的 ui框架 还有不少,而且热度很高。 再来说说官网保护的 uni-ui,反对全端,而且有类型提醒,目前曾经内置到 unibest 了,如果用户的确用不到外面的组件也能够删除,缩小包体积。 TIPS: uni-ui 自身是 js 开发的,然而官网提供了齐备的类型提醒( by @uni-helper/uni-ui-types)所以看起来就像是 ts 开发的一样,开发体验很好。所有的组件都有提醒,很不便,很贴心。UI 框架通过搜查了一番,目前加入比照的 UI 框架有: uview-plus (uveiw 系) - 文档地址uv-ui (uveiw 系) - 文档地址Wot Design Uni (wot 系) - 文档地址TuniaoUI (图鸟系) - 文档地址还有 2 个 UI 框架也很优良,然而局部组件开源收费,局部组件免费: ...

February 21, 2024 · 1 min · jiezi

关于uniapp:uniapp项目实践总结二十四安卓平台-APP-打包教程

导语:当你的利用程序开发实现后,在上架安卓利用商店之前,须要进行打包操作,上面简略介绍一下打包办法。目录筹备工作配置我的项目生成证书打包配置筹备工作在打包之前,请保障你的 uniapp 应用程序编译到安卓手机模拟器的 App 是能够失常运行的,APP 打包分为安卓和 ios 两个平台,上面简略介绍一下安卓的打包办法,因为本地打包问题较多,操作比较复杂,这里就省略了,本次次要介绍在线打包的办法。 配置我的项目次要是在manifest.json进行配置;关上文件后增加以下几个内容。 根本信息利用名称、形容、版本名称、版本号; 图标配置上传你的利用图标,倡议1024*1024,而后主动生成所有图标并替换; 启动界面应用原生隐衷政策提示框,这个很重要,勾选后会主动生成配置文件androidPrivacy.json,示例如下: 依据你本人的理论状况填写对应的内容和地址。 { "version": "1.0.0", "prompt": "template", "title": "服务协定和隐衷政策", "message": " 请你务必审慎浏览、充沛了解“服务协定”和“隐衷政策”各条款,包含但不限于:为了更好的向你提供服务,咱们须要收集你的设施标识、操作日志等信息用于剖析、优化利用性能。<br/> 你可浏览<a href=\"\">《服务协定》</a>和<a href=\"\">《隐衷政策》</a>理解详细信息。如果你批准,请点击上面按钮开始承受咱们的服务。", "buttonAccept": "批准并承受", "buttonRefuse": "暂不批准", "hrefLoader": "system|default", "backToExit": "false", "second": { "title": "确认提醒", "message": " 进入利用前,你需先批准<a href=\"\">《服务协定》</a>和<a href=\"\">《隐衷政策》</a>,否则将退出利用。", "buttonAccept": "批准并持续", "buttonRefuse": "退出利用" }, "disagreeMode": { "support": false, "loadNativePlugins": false, "visitorEntry": true, "showAlways": false }, "styles": { "backgroundColor": "#00FF00", "borderRadius": "5px", "title": { "color": "#ff00ff" }, "buttonAccept": { "color": "#ffff00" }, "buttonRefuse": { "color": "#00ffff" }, "buttonVisitor": { "color": "#00ffff" } }}模块配置这块依据你本人的须要进行打勾抉择。比方我用到的是扫码,分享就勾选就好了;如果遇到领取,登录或分享,还须要到对应平台申请利用 ID 和通用链接。 ...

September 26, 2023 · 2 min · jiezi

关于uniapp:uniapp项目实践总结二十三网页和小程序应用打包教程

导语:当你的利用程序开发实现后,在公布到互联网之前,须要进行打包操作,包含网页端、小程序端的打包。目录筹备工作网页打包小程序打包筹备工作在打包之前,请保障你的 uniapp 应用程序编译到网页、小程序是能够失常运行的。 网页打包编写好利用之后,如需打包到 web 平台,能够选中以后我的项目根目录: 在顶部菜单栏找到发行菜单点击后;找到网站-PC Web 或手机 H5(仅实用于 uni-app)子菜单;点击当前增加网站题目和域名;点击发行即可开始打包;打包当前在{{根目录}}\unpackage\dist\build\h5目录下生成,依据你本人的须要上传服务器部署网站。 小程序打包编写好利用之后,如需打包到微信小程序平台,能够选中以后我的项目根目录: 在顶部菜单栏找到发行菜单点击后;找到你要打包的小程序,比方小程序-微信(仅实用于 uni-app)子菜单;点击当前增加小程序题目和小程序 AppId点击发行即可开始打包。打包当前在{{根目录}}\unpackage\dist\build\mp-weixin目录下生成,依据你本人的须要关上微信开发者工具,导入我的项目,点击右上角的上传按钮提交微信审核。 最初以上就是利用打包到网页、小程序的次要内容,有不足之处,请多多斧正。

September 26, 2023 · 1 min · jiezi

关于uniapp:uniapp项目实践总结二十二分包优化和游客模式

导语:这篇次要介绍利用分包和游客模式相干的内容。目录利用分包游客模式利用分包微信对于小程序的打包压缩后的代码体积是有限度的,网页和 APP 也能够实用分包性能,因而须要进行分包增加以及分包优化。 分包增加在pages.json文件中增加分包的信息。例如:有一个名叫user的分包,外面有一个文件是index.vue,那么分包配置就是: { "pages": [ { "path": "pages/index/index", "style": { "navigationBarTitleText": "首页" } } ], "subPackages": [ { "root": "user", "pages": [ { "path": "index", "style": { "navigationBarTitleText": "分包首页" } } ] } ]}配置实现后该文件的拜访地址就是/user/index,其中的user是在根目录下寄存的。 分包优化增加配置分包优化的办法是在manifest.json文件中对应的平台增加以下配置: 例如:mp-weixin平台下增加分包优化。 { "mp-weixin": { "optimization": { "subPackages": true } }}注意事项目前只反对mp-weixin、mp-qq、mp-baidu、mp-toutiao、mp-kuaishou的分包优化;分包目录内搁置的动态资源不会被打包到主包中,也不可在主包中应用;当某个 js 仅被一个分包援用时,该 js 会被打包到该分包内,否则仍打到主包(即被主包援用,或被超过 1 个分包援用);若某个自定义组件仅被一个分包援用时,且未放入到分包内,编译时会输入提示信息;微信小程序目前微信小程序分包大小有以下限度: 整个小程序所有分包大小不超过 20M;单个分包/主包大小不能超过 2M;游客模式在一些平台,比方微信小程序和苹果 ios 利用商店,上架的利用肯定要提供游客模式才能够进行审核通过。 如何实现游客模式呢,上面就来简略实现一下。 服务端配置能够通过动静配置来关上或敞开游客模式。 例如:默认开启游客模式。 { "vistor": true}客户端配置客户端依据服务端的配置来设置是否开启游客模式。 逻辑剖析开启游客模式后,启动利用就应该能够进入到应用程序的主页面,而后能够随便旅行和应用,当遇到须要登录能力拜访的中央,再跳转到登录页面;敞开游客模式后,启动利用后须要先登录账号,而后才能够拜访利用内的页面或者应用利用提供的服务和性能;设置缓存启动利用获取服务端配置后能够设置缓存数据: // 接口获取到的数据let config = { vistor: true,};// 存入本地uni.setStorage("vistor", config.vistor);获取缓存在要拜访的页面触发须要登录能力应用的性能之前,先判断是否开启了游客模式,如开启再提醒并跳转登录。 ...

September 25, 2023 · 1 min · jiezi

关于uniapp:uniapp项目实践总结二十URLScheme-协议知识总结

导语:在日常开发过程中,咱们常常能够碰到很多的调起某个利用,关上唤醒某个 APP,链式启动 App 等场景,背地就波及到了 URLScheme 协定的相干常识,上面就简略介绍一下。目录简介常见 URL Scheme跳转办法实战演练案例展现简介URL Scheme是一个能够让 APP 之间相互跳转的协定,每个 APP 都有本人的 URL Scheme,如果存在雷同的 URL Scheme,会先跳转先装置的 APP,前面装置的会被笼罩掉。 协定格局[scheme]://[host][:port]/[/path]?[query] scheme:协定名称,由开发人员自定义host:域名port:端口path:页面门路query:申请参数例如淘宝:taobao:// 设施判断// 游览器标识const ua = navigator.userAgent.toLowerCase();// 是否微信内const isWeixin = ua.indexOf("micromessenger") !== -1;// 是否android终端const isAndroid = /(Android)/i.test(ua);// 是否ios终端const isIOS = /(iPhone|iPad|iPod|iOS|Mac)/i.test(ua);常见 URL Scheme利用市场market 谷歌利用商店tmast 利用宝mimarket 小米samsungapps 三星huawei 华为oppomarket oppovivomarket vivoitms-apps ios电商taobao 淘宝tmall 天猫jdlogin 京东pinduoduo 拼多多kaola 网易考拉yanxuan 网易严选vipshop 唯品会suning 苏宁mishopv1 小米商城wireless1688 阿里巴巴社交、社区weibo 微博zhihu 知乎xhsdiscover 小红书momochat 陌陌blued bluedmqzone QQ 空间mqq QQtantanapp 探探huputiyu 虎扑com.baidu.tieba 贴吧tianya 天涯社区douban 豆瓣jike 即刻短视频snssdk1128 抖音snssdk1112 火山snssdk32 西瓜视频gifshow 快手视频/直播tenvideo 腾讯视频youku 优酷bilibili B 站imgotv 芒果 TVqiyi-iphone 爱奇艺hanju 韩剧 TVdouyutv 斗鱼yykiwi 虎牙图片解决mtxx.open 美图秀秀faceu faceu 国内ulike 轻颜国内资讯snssdk141 今日头条newsapp 网易新闻qqnews 腾讯新闻iting 喜马拉雅weread 微信读书jianshu 简书igetApp 失去kuaikan 快看漫画财经sinanews 新浪财经amihexin 同花顺炒股音乐orpheus 网易云音乐qqmusic qq 音乐kugouURL 酷狗qmkege 全民 K 歌changba 唱吧工具iosamap 高德地图baidumap 百度地图baiduyun 百度网盘rm434209233MojiWeather 墨迹天气办公wxwork 企业微信dingtalk 钉钉生存imeituan 美团dianping 点评cainiao 菜鸟裹裹wbmain 58 同城mihome 米家美食佳饮xcfapp 下厨房sbuxcn 星巴克中国meituanwaimai 美团外卖静止衰弱fb370547106731052 小米静止meetyou.linggan 美柚babytree 宝宝树keep keep旅行CtripWireless 携程diditaxi 滴滴taobaotravel 飞猪travelguide 马蜂窝游戏tencent1104466820 王者光荣tencent100689805 天天爱打消tencent382 QQ 斗地主跳转办法应用程序相互跳转办法以下是 uniapp 跳转利用的关上通用办法。 ...

September 22, 2023 · 2 min · jiezi

关于uniapp:uniapp项目实践总结十九版本更新和热更新实现方法

导语:当一个 APP 利用开发实现当前,就要上架利用商店,但有时候批改一些小问题或者推出一些流动,又不想频繁地提交利用商店审核,那么就能够应用利用内更新性能来进行利用的版本升级更新或热更新,上面就介绍一下实现的办法。目录筹备工作原理剖析实战演练案例展现筹备工作在/pages/index文件夹上面新建一个version.vue的组件;依照后面文章所说的页面构造,编写好预约的页面;原理剖析上面是利用更新的原理总结。 安装包版本更新通过uni.getSystemInfoSync办法的appVersion属性获取到利用以后安装包版本号;通过申请版本更新接口获取线上的安装包版本号;比拟两个安装包版本号的大小,如果统一不更新,如果不统一,线上大于以后更新版本,线上小于以后不更新;资源包版本更新通过uni.getStorage获取本地资源包版本号,如不存在,则通过uni.setStorage设置默认版本号;通过申请版本更新接口获取线上的资源包版本号;比拟两个资源包版本号的大小,如果统一不更新,如果不统一,线上大于以后更新版本,线上小于以后不更新;实战演练模板应用比拟版本号<view class="version-box"> <view class="version-item"> 版本1: <input class="version-item-ipt" type="text" placeholder="请输出版本1" v-model="versionInfo.v1" /> </view> <view class="version-item"> 版本2: <input class="version-item-ipt" type="text" placeholder="请输出版本2" v-model="versionInfo.v2" /> </view> <view class="version-item"> <button class="version-item-btn" type="primary" size="mini" @click="compareVersion('test')"> 比拟版本 </button> </view> <view class="version-item" v-show="versionInfo.text"> <text>比拟后果:</text> <text class="version-item-txt">{{ versionInfo.text }}</text> </view></view>获取线上版本<!-- #ifdef APP-PLUS --><view class="version-box"> <view class="version-item"> <button class="version-item-btn" type="primary" size="mini" @click="getVersion"> 获取版本 </button> </view> <view class="version-item"> 以后版本: {{ checkInfo.current }} </view> <view class="version-item"> 线上版本: {{ checkInfo.online }} </view> <view class="version-item"> 以后资源包版本: {{ checkInfo.currentSource }} </view> <view class="version-item"> 线上资源包版本: {{ checkInfo.onlineSource }} </view></view><!-- #endif -->检测更新<!-- #ifdef APP-PLUS --><view class="version-box"> <view class="version-item"> <button class="version-item-btn" type="primary" size="mini" @click="checkUpdate"> 检测更新 </button> </view> <view class="version-item" v-show="checkInfo.showProgress"> <progress :percent="checkInfo.currentProgress" show-info :stroke-width="8" active-color="#24afd6" /> </view></view><!-- #endif -->款式编写.version-box { padding: 10rpx; .version-item { display: flex; justify-content: flex-start; align-items: center; margin-bottom: 20rpx; padding: 0 10rpx; .version-item-ipt { margin-left: 20rpx; padding: 10rpx; border: 3rpx solid $e; font-size: 27rpx; } .version-item-btn { margin: 0; } .version-item-txt { color: $mainColor; } .uni-progress { width: 100%; } }}脚本应用定义数据比拟版本信息const versionInfo = reactive({ v1: "", // 版本1 v2: "", // 版本2 text: "", // 检测后果});检测版本信息const checkInfo = reactive({ current: "0.0.0", // 以后版本 online: "0.0.0", // 线上版本 currentSource: 0, // 以后资源包 onlineSource: 0, // 线上资源包 result: "", // 检测后果 data: null, // 在线信息 type: "", // 装置类型 showProgress: false, // 显示进度条 currentProgress: 0, // 以后进度 downloader: null, // 下载定时器});办法调用模仿版本更新数据应用之前介绍的动态服务器搁置版本更新配置文件,格局如下: ...

September 20, 2023 · 4 min · jiezi

关于uniapp:uniapp项目实践总结十八自定义多列瀑布流组件

导语:有时候展现图片等内容,会遇到图片高度不统一的状况,这时候就不能应用等高双列或多列展现了,这时候会用到瀑布流的页面布局,上面就一起探讨一下瀑布流的实现办法。目录筹备工作原理剖析实战演练案例展现筹备工作在pages/index文件夹上面新建一个waterfall.vue的组件;依照后面文章所说的页面构造,编写好预约的瀑布流案例页面;在网上找几张收费的图片素材;原理剖析次要是依据图片的高度主动比拟每列的总高度,依据uni.getImageInfo获取到图片高度,而后哪列低,就给哪列补充图片,直至图片列表循环结束。 实战演练模板应用上面就是循环列和图片。 <view class="waterfall-page"> <view class="waterfall-page-column" v-for="(item, index) in waterfall.columnList" :key="index" ref="column" > <view class="waterfall-page-item" v-for="(pItem, pIndex) in item" :key="pIndex" > <image class="waterfall-page-img" :src="pItem" mode="widthFix"></image> </view> </view></view>款式编写.waterfall-page { display: flex; align-items: flex-start; .waterfall-page-column { box-sizing: border-box; flex: 1; padding: 0 10rpx; width: 0; .waterfall-page-item { margin-bottom: 10rpx; .waterfall-page-img { display: inline-block; width: 100%; } } }}脚本应用定义数据// 瀑布流信息const waterfall = reactive({ // 图片列表 imgList: [ "/static/image/waterfall/pic-01.jpg", "/static/image/waterfall/pic-07.jpg", "/static/image/waterfall/pic-03.jpg", "/static/image/waterfall/pic-07.jpg", "/static/image/waterfall/pic-05.jpg", "/static/image/waterfall/pic-07.jpg", "/static/image/waterfall/pic-01.jpg", "/static/image/waterfall/pic-03.jpg", "/static/image/waterfall/pic-07.jpg", ], columnList: [], // 每列图片 columnHeight: [], // 每列图片高度 columnCount: 2, // 总列数});初始化数据// 初始化数据function initData() { for (var i = 0; i < waterfall.columnCount; i++) { waterfall.columnList.push([]); waterfall.columnHeight.push(0); }}计算方法// 设置瀑布流布局async function setWaterfallLayout() { for (var i = 0; i < waterfall.imgList.length; i++) { let item = waterfall.imgList[i]; try { let imgInfo = await uni.getImageInfo({ src: item, }), h = imgInfo.height; for (let j = 0; j < waterfall.columnCount - 1; j++) { let prevIndex = j, nextIndex = j + 1; if ( waterfall.columnHeight[prevIndex] <= waterfall.columnHeight[nextIndex] ) { waterfall.columnList[prevIndex].push(item); waterfall.columnHeight[prevIndex] += h; } else { waterfall.columnList[nextIndex].push(item); waterfall.columnHeight[nextIndex] += h; } } } catch (error) { console.log(error); } }}案例展现h5 端成果小程序端成果APP 端成果最初以上就是自定义多列瀑布流组件的次要内容,有不足之处,请多多斧正。 ...

September 19, 2023 · 1 min · jiezi

关于uniapp:uniapp项目实践总结十七实现滚动触底加载

导语:在日测的开发过程中,常常会碰到页面须要渲染大量数据的状况,这时候就须要用到滚动加载性能,上面总结一下办法。目录原理剖析实战演练案例展现原理剖析应用@scrolltolower事件来监听滚动到底部,而后加载下一页的数据。 实战演练模板页面<scroll-view :scroll-y="true" class="block-main block-two-level block-pad" @scrolltolower="scrollBottom"> <view class="scroll-ls" v-for="(item, index) in scrollInfo.list" :key="index"> {{ item }} </view> <uni-load-more v-if="scrollInfo.list.length" :status="scrollInfo.loading"></uni-load-more></scroll-view>款式编写.scroll-ls { margin-top: 20rpx; padding: 50rpx 0; text-align: center; background: $f8;}脚本应用定义数据// 滚动列表const scrollInfo = reactive({ originList: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, ], list: [], pageInfo: { page: 1, size: 8, pages: 0, }, loading: "more",});办法调用// 滚动到底部function scrollBottom() { console.log("滚动到底部!"); if (scrollInfo.pageInfo.page < scrollInfo.pageInfo.pages) { scrollInfo.pageInfo.page++; scrollInfo.loading = "loading"; getList(); } else { scrollInfo.loading = "noMore"; }}获取列表// 获取列表function getList() { if (scrollInfo.pageInfo.page <= 1) { show.value = true; } let data = proxy.$apis.utils.splitData(scrollInfo.originList, 8); scrollInfo.pageInfo.pages = data.pages; setTimeout(() => { if (scrollInfo.pageInfo.page <= 1) { scrollInfo.list = data.list[scrollInfo.pageInfo.page - 1]; setTimeout(() => { show.value = false; }, 500); } else { scrollInfo.list = [...scrollInfo.list, ...data.list[scrollInfo.pageInfo.page - 1]]; } scrollInfo.loading = scrollInfo.pageInfo.page < scrollInfo.pageInfo.pages ? "more" : "noMore"; }, 1000);}案例展现h5 端成果小程序端成果APP 端成果最初以上就是实现滚动触底加载的次要内容,有不足之处,请多多斧正。 ...

September 18, 2023 · 1 min · jiezi

关于uniapp:uniapp项目实践总结十四封装存储和路由方法

导语:在日常 APP 开发过程中,常常要用到数据的存储、获取和删除等操作以及页面导航之间的跳转,为此,封装了一个两个简略的办法来对立调用。目录原理剖析办法实现实战演练案例展现原理剖析次要是以下 API。 uni.setStorage:保留数据到本地缓存中;uni.getStorage:获取保留的缓存数据;uni.removeStorage:移除保留的数据缓存;uni.clearStorage:清空保留的缓存数据;uni.navigate{type}:跳转页面;以下办法存于根目录下的scripts文件夹下的utils.js文件中。 办法实现接下来一一阐明如何实现数据缓存操作和路由跳转的封装。 数据缓存这里是应用一个办法,通过传入不同的类型和参数来实现。 参数如下: type: 类型,包含设置,获取,删除,清空;isSync: 是否异步;key: 键名;val: 值;// 存储数据async function storeage(options) { try { let defultOptions = { type: options.type, isSync: options.isSync || false, key: options.key, data: options.val, }; let params = { ...options, ...defultOptions }; console.log("数据缓存参数:", params); let { type, isSync, key, data } = params; let result = null, types = { set: uni[`setStorage${isSync ? "Sync" : ""}`], get: uni[`getStorage${isSync ? "Sync" : ""}`], del: uni[`removeStorage${isSync ? "Sync" : ""}`], clear: uni[`clearStorage${isSync ? "Sync" : ""}`], }; if (type == "set") { if (isSync) { result = await types[type](key, data); } else { result = await types[type]({ key, data, }); } } if (["get", "del"].includes(type)) { let param = isSync ? key : { key }; result = await types[type](param); } if (type == "clear") { result = await types[type](); } return { code: 1, data: result, }; } catch (e) { return { code: 2, data: e, }; }}路由操作这里是把罕用的路由办法装进一个办法外面了,不便调用。 ...

September 9, 2023 · 2 min · jiezi

关于uniapp:uniapp项目实践总结十二封装通用请求上传以及下载方法

导语:在日常开发过程中,前端常常要和后端进行接口联调,获取并且渲染数据到页面中,接下来就总结一下 uniapp 中获取申请、文件下载和上传的一些办法。目录原理剖析办法实现实战演练案例展现原理剖析次要是应用uni.request办法来发送申请,uni.downloadFile办法来下载文件,uni.uploadFile办法来上传文件。 以下办法存于根目录下的scripts文件夹下的http.js文件中。 办法实现接下来一一阐明如何实现数据申请、文件下载以及文件的上传的办法封装。 数据申请这个办法要接管一些参数,和现有默认参数合并,而后传给申请 API,获取数据后应用try...catch来解决胜利和失败。 这里要引入一些文件,包含申请的域名和地址,以及一些通用办法,就先省略了,接口能够到网上找一下公共的,或者本人应用 node 搭建一个繁难的接口服务器。 // 网络申请async function request(options) { let isHttp = options.url.indexOf("http") > -1; let url = isHttp ? options.url : `${urls.baseUrl}${options.url}`; let defultOptions = { url, method: options.method || "get", data: options.data || null, timeout: options.timeout || 30000, dataType: options.dataType || "json", header: options.header || { "Content-Type": "application/json", }, sslVerify: options.sslVerify || false, }; let params = { ...options, ...defultOptions }; console.log("申请参数:", params); try { let result = await uni.request(params); if (result.statusCode === 200) { return result.data; } else { return { code: 102, msg: "get_fail", data: { info: result.errMsg, }, }; } return result; } catch (e) { return { code: 101, msg: "get_fail", data: { info: e, }, }; }}文件下载这个就和申请一样,只不过 API 不一样,看一下内容。 ...

September 7, 2023 · 3 min · jiezi

关于uniapp:uniapp项目实践总结四安装和使用一个插件市场的插件

这篇文章次要介绍如何装置和应用一个插件市场的插件的办法。目录查找插件装置插件应用插件查找插件关上插件市场:https://ext.dcloud.net.cn/ 例如咱们我的项目中要用到富文本渲染的内容,能够查找一下富文本; 在后果页能够选一款适宜本人的插件,我感觉mp-html这个插件挺好的; mp-html 插件地址 装置插件点击右侧装置按钮下载插件并导入 HBuilderX; 下载结束后你会发现你的根目录多出一个文件夹uni_modules,这个专门用于寄存下载的插件。 这个文件夹下的插件能够间接应用,不须要引入全局或者部分组件。 应用插件装置胜利后开始应用插件。 编写一段 js 变量并赋值;data () { return { mdStr: `<h2>Hello</h2><p style="color: #f00;font-size: 20rpx;">我是富文本!</p>`, }}应用富文本插件渲染内容;<mp-html :content="mdStr" />上面是预览图: 最初以上就是如何装置和应用一个插件市场的插件的次要内容,如有不足之处,请多多斧正。

August 31, 2023 · 1 min · jiezi

关于uniapp:uniappmarkdown渲染解析md转html及代码高亮

明天给大家分享一个在uniapp我的项目中用到的markdown语法解析插件uaMarkdown。 如下图:编译至H5+小程序+App端成果。 应用markdown-it和highlight.js封装组件。 // 引入markdown-it和highlight.js插件import MarkdownIt from '@/plugins/markdown-it.min.js'import hljs from '@/plugins/highlight/highlight.min.js'// import '@/plugins/highlight/github-dark.min.css'import '@/plugins/highlight/atom-one-light.css'import parseHtml from '@/plugins/html-parser.js' 初始markdown组件const markdown = MarkdownIt({ html: true, highlight: function(str, lang) { let preCode = "" try { preCode = hljs.highlightAuto(str).value } catch (err) { preCode = markdown.utils.escapeHtml(str); } // 自定义行号 const lines = preCode.split(/\n/).slice(0, -1) let html = lines.map((item, index) => { // 去掉空行 if( item == ''){ return '' } return '<li><span class="line-num" data-line="' + (index + 1) + '"></span>' + item +'</li>' }).join('') html = '<ol style="padding: 0px 30px;">' + html + '</ol>' // 代码复制 copyCode.push(str) let htmlCode = `<div class="markdown-wrap">` // #ifndef MP-WEIXIN htmlCode += `<div style="color: #aaa;text-align: right;font-size: 12px;padding:8px;">` htmlCode += `${lang}<a class="copy-btn" code-data-index="${copyCode.length - 1}" style="margin-left: 8px;">复制代码</a>` htmlCode += `</div>` // #endif htmlCode += `<pre class="hljs" style="padding:0 8px;margin-bottom:5px;overflow: auto;border-radius: 5px;"><code>${html}</code></pre>`; htmlCode += '</div>' return htmlCode }}) ...

July 2, 2023 · 1 min · jiezi

关于uniapp:uniapp自定义跨端标题头相关说明

需要咱们在自定义题目的时候,须要计算的值次要包含状态栏和标题栏的高度,具体如下: 状态栏这个比拟好计算,间接调用办法即可: ztlHeight = uni.getSystemInfoSync().statusBarHeight;标题栏对于小程序而言,思考到左边有个 胶囊 ,所以计算的时候依照如下准则: 胶囊 + 2 * (胶囊顶部到顶的间隔 - 状态栏的高)而对于H5或者APP这种没有胶囊的,间接写死一个适合的值即可。由此,最终代码如下: // #ifndef APP-PLUS || H5btlHeight = (uni.getMenuButtonBoundingClientRect().top - ztlHeight) * 2 + uni.getMenuButtonBoundingClientRect().height;// #endif// #ifdef APP-PLUS || H5btlHeight = uni.upx2px(80);// #endif

July 1, 2023 · 1 min · jiezi

关于uniapp:uniapp开发app使用wangeditor富文本编辑器进行编辑查看

wangeditor是后盾比拟罕用的一个富文本编辑器,官网链接:https://www.wangeditor.com/ 留神:兼容支流的 PC 浏览器,如 Chrome Firefox Safari Edge 等。暂不反对挪动端编辑(反对挪动端查看)。不再反对 IE 浏览器。 我的需要,可能在挪动端编辑、查看,并且可能联动后盾。我在网上找了很多挪动端的富文本编辑器,都不合乎我的需要,最初应用了webview的形式去实现wagneditor4版本。 具体实现代码如下:index.vue文件代码 <template> <view class="initiateContract"> <div class="headerTip" :style="'margin-top:' + height + 'px;'"> <div class="title"> <div class="txt">{{ contractDetails.title }}</div> <div class="status"> <u-tag v-if="contractDetails.flow_status === '1'" :text="contractDetails.flow_status_name" type="info" size="mini" plain></u-tag> <u-tag v-if="contractDetails.flow_status === '2'" :text="contractDetails.flow_status_name" type="warning" size="mini" plain></u-tag> <u-tag v-if="contractDetails.flow_status === '3'" :text="contractDetails.flow_status_name" type="warning" size="mini" plain></u-tag> <u-tag v-if="contractDetails.flow_status === '5'" :text="contractDetails.flow_status_name" type="success" size="mini" plain></u-tag> </div> </div> <div class="info">留神:合同签订区的代码英文,如company_sign、demand_sign、aunt_sign等英文代码请勿删除</div> </div> <view class="html-box"> <web-view :src="'../../../hybrid/html/viewContract/index.html?data=' + obj" @message="getMessage" ref="wv"></web-view> </view> <view class="footer" v-if="isKeyboard === false"> <view class="box"> <view class="item" v-if="contractDetails.flow_status == '1'" @click="saveContract"> <view class="btn"> <u-button type="primary" :key="1" :plain="true" text="保留合同"></u-button> </view> </view> <view class="item"> <view class="btn"> <u-button type="primary" :key="2" text="分享预览"></u-button> </view> </view> <view class="item" v-if="contractDetails.flow_status == '1'" @click="openConfirmSigning"> <view class="btn"> <u-button type="primary" :key="3" text="开始签约"></u-button> </view> </view> <view class="item" v-if="contractDetails.flow_status !== '1'"> <view class="btn"> <u-button :disabled="true" :key="4" type="success" text="签约中"></u-button> </view> </view> </view> </view> </view></template><script> import cluesHttp from '@/api/client/index.js' var wv export default { name: "electronContractEdit", data() { return { dianzi_hetong_id: '', form: { id: '0', hetong_id: '', muban_id: '', }, contractDetails: {}, contractContent: '', currentWebview: null, shareImgInfo: {}, isKeyboard: false, contentHtml: '', } }, onLoad() { const vm = this; uni.$on('to-parent', (data) => { switch( data.type ){ case '1': uni.setClipboardData({ data: this.shareImgInfo.result.tips, success: function () { uni.showToast({ icon: 'none', title: '链接已复制' }) } }); break; case '2': break; } }); // 获取上个页面传来的参数 const self = this const eventChannel = this.getOpenerEventChannel(); eventChannel.on('getInitiateContractParams', function(res) { _this.contractDetails = res _this.dianzi_hetong_id = res.id self.currentWebview = self.$scope.$getAppWebview().children()[0] self.currentWebview.evalJS(`getParams(${JSON.stringify(res)})`) }) }, onReady() { // #ifdef APP-PLUS var currentWebview = this.$scope.$getAppWebview() setTimeout(function() { wv = currentWebview.children()[0] wv.setStyle({ top: uni.getStorageSync('navbarHeight') + 84, bottom: 71, width: uni.getSystemInfoSync['screenWidth'] }) }, 100); // 键盘升起,避免遮挡编辑器内容 uni.onKeyboardHeightChange((res) => { if(this.isKeyboard === true) { this.isKeyboard = false wv.setStyle({ top: uni.getStorageSync('navbarHeight') + 84, bottom: 71, width: uni.getSystemInfoSync['screenWidth'] }) } else { this.isKeyboard = true wv.setStyle({ top: uni.getStorageSync('navbarHeight') + 84, bottom: res.height, width: uni.getSystemInfoSync['screenWidth'] }) } }) // #endif }, methods: { back() { uni.navigateBack() }, saveContract() { const self = this; self.currentWebview.evalJS("uniEvent('saveContract')"); //app向html发送数据 }, openConfirmSigning() { let params = { form: { dianzi_hetong_id: this.dianzi_hetong_id, } } uni.showModal({ title: '开始签约', content: '发动签约后,合同内容不能再次批改,同时会耗费一份合同的使用量,是否开始签约?', complete: (res) => { if(res.confirm === true) { cluesHttp.startElectronContractSigning(params).then(res => { uni.showToast({ icon: 'none', title: '签约胜利' }) }) } } }) }, getMessage(e) { if(e.detail.data[0].msg === 'saveContract') { //保留合同 let params = { form: { title: this.contractDetails.title, id: this.dianzi_hetong_id, content: e.detail.data[0].content } } cluesHttp.saveElectronContractDetail(params).then(res => { uni.showToast({ icon: 'none', title: '保留胜利' }) }) } }, }, beforeDestroy() { uni.$off('to-parent') uni.offKeyboardHeightChange() }, }</script><style lang="scss" scoped> .initiateContract { .header { display: flex; align-items: center; justify-content: space-between; padding: 10px 20px 10px; .left { display: flex; align-items: center; justify-content: flex-start; } .title { text-align: center; } .right { height: 34px; opacity: 0; text-align: right; display: flex; align-items: center; justify-content: flex-end; } .item { // width: 30%; } } .headerTip { background-color: #ffedd1; z-index: 999; padding: 10px; font-size: 12px; .title { color: #f9ae3d; display: flex; justify-content: space-between; align-items: center; padding-bottom: 10px; border-bottom: 1px solid #ececec; } .info { word-break: break-all; } } .footer { position: fixed; bottom: 0px; left: 0px; right: 0px; z-index: 9999; padding: 10px 0 20px; background: #fff; border-top: 1px solid #f3f3f3; .box { display: flex; justify-content: space-around; align-items: center; .item { .btn { margin: 0 auto; } } } } }</style>/hybrid/html/viewContract/index.html文件代码 ...

June 27, 2023 · 4 min · jiezi

关于uniapp:uniapp开发appwebview与app相互通信

一、app向webview发送数据(传参),在index.vue页面 1、通过url传参<view class="html-box"> <web-view :src="'../../../hybrid/html/viewContract/index.html?data=' + obj" @message="getMessage" ref="wv"></web-view></view>2、通过evalJS("uniEvent(`${params}`)")data() { return { currentWebview: null, obj: null } },onLoad() { const self = this; self.currentWebview = self.$scope.$getAppWebview().children()[0] //传递大量数据 self.currentWebview.evalJS(`getParams(${JSON.stringify(res)})`)},methods: { saveContract() {//app通过事件向html发送数据 const self = this; self.currentWebview.evalJS("uniEvent('saveContract')"); },}二、webview接管app发来的数据(传参),在/hybrid/html/viewContract/index.html页面 1、通过url接管参数<script type="text/javascript"> console.log('接管url参数', decodeURIComponent(location.href.split('data=')[1]))</script>2、通过evalJS定义的办法接管参数<script type="text/javascript"> let dianziHetong = null; window.getParams = (data) => { console.log("webview外部:", data) dianziHetong = data console.log(dianziHetong) } window.uniEvent = function(data) { console.log('app发来的数据', data) }</script>三、webview向app发送数据(传参),在/hybrid/html/viewContract/index.html页面 1、通过uni.postMessage()<script src="../js/uni-webview.js"></script><script type="text/javascript"> document.addEventListener('UniAppJSBridgeReady', function() { uni.postMessage({ data: { msg: 'saveContract', content: editor.txt.html() } }); })</script>四、app接管webview发来的数据(传参),在index.vue页面 ...

June 27, 2023 · 1 min · jiezi

关于uniapp:uniapp开发app使用subNVue原生子窗体

首先须要在pages.json中配置 { "path": "pages/client/initiateElectronContract/index", "style": { "navigationBarTextStyle": "white", "navigationBarTitleText": "编辑电子合同", "navigationBarBackgroundColor": "#00bdbd", "backgroundColor": "#00bdbd", "navigationStyle": "custom", "app-plus": { "subNVues": [ { "id": "initiateContractShare", // 惟一标识 "type": "popup", "path": "pages/client/initiateElectronContract/subNVue/share", "style": { "position": "absolute", "bottom": "0", "left": "0", "right": "0", "width": "100%", "height": "200px" } }, { "id": "tips", "type": "popup", "path": "pages/client/initiateElectronContract/subNVue/popup" } ] } } },popup.nvue文件 <template> <view class="page"> <view class="shares"> <view class="title">开始签约</view> <view class="content"> <text class="tip">发动签约后,合同内容不能再次批改,同时会耗费一份合同的使用量,是否开始签约?</text> </view> <view class="operation"> <view class="cancel btn" @click="cancel"> <text class="txt canceltxt">勾销</text> </view> <view class="confirm btn" @click="confirm"> <text class="txt confirmtxt">确定</text> </view> </view> <view class="close" @click="cancel"> <image src="../../../../static/close.png" style="width: 20px;height: 20px;" alt="close" /> </view> </view> </view></template><script> export default { data() { return { }; }, created() { const vm = this; // 接管信息的页面 // uni.$on('from-parent', (data) => { // uni.showToast({ // title: data.type + ', ' + data.content // }) // switch (data.type) { // case '1': // break; // case '2': // break; // case '3': // break; // // .... // } // }); }, beforeDestroy() { // 页面销毁之前 移除监听器 // uni.$off('from-parent'); }, methods: { cancel() { // 获取以后 subNVues 原生子窗体的实例。 const subNVue = uni.getCurrentSubNVue(); // 子窗体暗藏 subNVue.hide(); }, confirm() { // 获取以后 subNVues 原生子窗体的实例。 const subNVue = uni.getCurrentSubNVue(); // 向父窗体传递参数 uni.$emit('to-parent', { type: '3', content: content }); // 子窗体暗藏 // 可自定义 暗藏动画成果,工夫 // subNVue.hide(); }, } }</script><style> /* 分享弹窗 */ .shares { height: 300px; font-size: 20upx!important; padding: 10px; } .title { width: 300px; display: flex; text-align: center; justify-content: center; } .tip { font-size: 16px; padding: 20px 0 10px; } .operation { display: flex; flex-direction: row; justify-content: center; align-items: center; } .btn { display: flex; justify-content: center; align-items: center; color: #606266; padding: 10px 30px; } .txt { display: flex; justify-content: center; align-items: center; font-size: 16px; } .close { position: absolute; top: 10px; right: 10px; }</style>index.vue文件 ...

June 26, 2023 · 3 min · jiezi

关于uniapp:uniapp打包使用高德地图

应用uni.chooseLocation()下方的搜寻始终显示加载中造成这样的起因是因为没有配置key、权限等起因造成的。 一、创立高德地图key这里须要获取SHA1、须要先装置jdk工具,因为咱们须要用到SHA1、SHA256、MD5目前最新版的jdk曾经不反对MD5了,仅反对sha1,sha256两种签名。分享一下能够获取MD5的旧版本jdk 下载链接: https://pan.baidu.com/s/1DIXpmcxHmZVKlnWE6qgIxg 提取码: 7en8 复制这段内容后关上百度网盘手机App,操作更不便哦 二、创立证书1、关上电脑上的cmd命令提示符工具,先进入jdk装置目录 2、应用命令生成证书命令参考:https://ask.dcloud.net.cn/article/35777应用keytool -genkey命令生成证书:keytool -genkey -alias kytest -keyalg RSA -keysize 2048 -validity 36500 -keystore kytest.keystore kytest是证书别名,可批改为本人想设置的字符,倡议应用英文字母和数字kytest.keystore是证书文件名称,可批改为本人想设置的文件名称,也能够指定残缺文件门路36500是证书的有效期,示意100年有效期,单位天,倡议工夫设置长一点,防止证书过期 3、按提醒持续操作、证书已生成 4、查看证书应用命令:keytool -list -v -keystore test.keystore 三、高德地图中填写SHA1 四、docloud开发者后盾配置平台信息 五、uniapp打包配置高德地图key 六、uniapp打包配置权限 七、uniapp打包增加证书 八、打包胜利后就能够应用了

June 26, 2023 · 1 min · jiezi

关于uniapp:uniapp解决uview10-uupload组件使用beforeupload属性限制图片比例问题

前言因我的项目上应用了uniapp,并且应用uview1.0作为ui框架,然而应用过程中发现u-upload组件的before-upload属性有bug,顺便记录下来分享给大家,心愿可能帮忙到大家。 操作u-upload组件的before-upload属性我限度了上传图片大小,然而它还是显示上传胜利了,于是网上搜寻解决方案,并且批改了u-upload组件的源码才彻底解决。 1、批改u-upload组件源码 ...let flag = false// 执行before-upload钩子if(this.beforeUpload && typeof(this.beforeUpload) === 'function') {// 执行回调,同时传入索引和文件列表当作参数// 在微信,支付宝等环境(H5失常),会导致父组件定义的customBack()函数体中的this变成子组件的this// 通过bind()办法,绑定父组件的this,让this.customBack()的this为父组件的上下文// 因为upload组件可能会被嵌套在其余组件内,比方u-form,这时this.$parent其实为u-form的this,// 非页面的this,所以这里须要往上历遍,始终寻找到最顶端的$parent,这里用了this.$u.$parent.call(this)// 明确意思即可,无需纠结this.$u.$parent.call(this)的细节let beforeResponse = this.beforeUpload.bind(this.$u.$parent.call(this))(index, this.lists);// 判断是否返回了promiseif (!!beforeResponse && typeof beforeResponse.then === 'function') { await beforeResponse.then(res => { // promise返回胜利,不进行动作,持续上传 }).catch(err => { flag = true this.lists.splice(index, 1); this.$forceUpdate(); // 进入catch回调的话,持续下一张 return this.uploadFile(index + 1); }) // promise 或 async 返回 false,或进入 catch 回调,持续下一张;否则不进行动作,持续上传} else if(beforeResponse === false) { // 如果返回false,持续下一张图片的上传 return this.uploadFile(index + 1);} else { // 此处为返回"true"的情景,这里不写代码,就跳过此处,继续执行以后的上传逻辑}}// 查看上传地址if (!this.action) { this.showToast('请配置上传地址', true); return;}// 如果在beforeUpload中被回绝,则不往后执行if(flag) return false大家能够参考我的代码进行批改 ...

June 19, 2023 · 1 min · jiezi

关于uniapp:发布了新插件基于editor创作的富文本编辑器

因为我的项目须要@谁来看的性能,所以依据官网editor二次封装了一个富文本编辑器,想着可能你们心愿本人定义编辑器按钮,所以把按钮组件提出来了,你能够自在更换,想着你可能更心愿基于api本人设计编辑器,所以把性能都给你封装到Class Edit类了,你只需new Edit,外面丰盛的api就都是你的了。 上面是插件介绍:插件地址:https://ext.dcloud.net.cn/plugin?name=lsj-edit 创作不易,若能帮到你请不要手软点亮5颗星~应用组件前必读此组件是对editor组件二次封装,减少了相似微信的@谁来看 和 相似微博的插入#话题等性能如心愿插入话题或@后光标不指向最初而指向话题前面,须要在editor组件源码退出一段代码,须要能够加Q群发你为了不便大家更换按钮控件,我将控制器按钮和编辑器画布拆分成了两个组件你齐全能够自定义编辑器,所有性能都封装到了edit类,不便各位调用,查看Edit具体文档因为比拟懒,只测试了H5和App端,其余端懒得测了,如果遇到问题能够群里Q我划重点!!!如果你心愿自定义编辑器,Edit类实例的办法和事件机制你须要理解,具体查看示例我的项目或查看Edit具体文档根本应用lsj-edit组件属性与事件绑定属性是否必填值类型默认值/返回值阐明html否String-初始化时加载的html,例如加载草稿placeholder否String开始输出编辑器提示信息maxCount否Number0最大输出字数,含空格和符号,超出最大限度时Edit返回overstep:truereadOnly否Booleanfalse编辑器是否只读styles否Object-编辑器自定义款式showImgSize否Booleantrue点击图片时显示图片大小控件showImgToolbar否Booleantrue点击图片时显示工具栏控件showImgResize否Booleantrue点击图片时显示批改尺寸控件@onReady否Function[Class] Edit编辑器初始化实现触发回调,返回edit实例对象附带的按钮edit-btns组件属性与事件绑定属性是否必填值类型默认值/返回值阐明edit是[Class] Edit-将edit对象传入和应用color否String#999999Tab栏字体默认色彩selectedColor否String#00aaffTab栏字体选中色彩fontColor否ArrayArray字体罕用色彩数组bgColor否ArrayArray字体罕用背景色数组tabs否Array#、@Tab栏是否须要显示#和@emojiList否Arraytrueemoji列表@click否FunctionObject {name,index}点击Tab栏时回调@submit否FunctionClass Edit点击Tab栏右侧提交按钮时回调VUE<lsj-edit ref="lsjEdit" placeholder="输出注释":maxCount="200"@onReady="editReady"> <template v-slot:btns="data"> <edit-btns :edit="data.edit" @click="onTabClick" @submit="save"></edit-btns> </template></lsj-edit>JSimport editBtns from '@/uni_modules/lsj-edit/components/lsj-edit/edit-btns/edit-btns.vue';export default { components:{ // 富文本基本操作按键,可自行抉择是否应用示例的按键 editBtns }, data() { return { edit: null } }, methods: { // 编辑器初始化结束,返回edit对象 editReady(edit) { // 将富文本对象寄存到以后页面,便于后续间接操作 this.edit = edit; }, // 演示----按钮组件点击事件 onTabClick({name,index}) { switch (index){ // 插入#话题# case 0: this.addLink(); break; // @某人 case 1: this.addLink2(); break; default: break; } }, // 演示公布 async save() { // 获取插入的图片列表 let imgs = await this.edit.getImages() // 判断是否容许提交 if (!this.edit.textCount && !imgs.length) { uni.showToast({ title: '请录入内容' }); } // 将所有未上传的本地图片上传到服务器并替换到编辑器 this.edit.replaceImage(async(img)=>{ // 已上传的无需再上传 // 这里没有放到edit外部去过滤,因为我感觉需不需要上传得你本人决定 // 比方插入的base64图片是否须要上传 // img.indexOf('http') = 0阐明这个图片曾经是网络地址,无需替换就间接跳过 if(img.indexOf('http') === 0) {return img;} // 上传并替换图片 /* let {data} = await uni.uploadFile({ url: 'https://www.example.com/upload', //仅为示例,非实在的接口地址 filePath: img, //本地图片 name: 'file', formData: { 'user': 'test' } }); return data; */ // 因为演示的时候没有服务器,所以间接换个网络图不便后续演示, // 理论我的项目应应用上方正文内容 return 'https://t7.baidu.com/it/u=3406125714,2513313326&fm=193&f=GIF' }).then(res=>{ console.log('替换实现,最终内容为',JSON.stringify(res)); // 示例我的项目可查看解析富文本演示 uni.navigateTo({ url: '/pages/article/article?data='+escape(res.html) }); }); }, // 插入话题示例 addLink() { this.edit.addLink({ prefix: '#', suffix: '#', name: '有问题欢送退出LSJ插件交换群', data: { name: 'QQ交换群', qqGroupChatID: '667530868', } }) }, // @某人示例 addLink2() { this.edit.addLink({ prefix: '@', name: '马冬梅', data: { userId: 10, } }) } }}Edit类实例的办法和事件机制Edit实例办法tool调用editorContext对象的事件,如撤销undo,复原redo,清空内容clear,失焦blur等调用形式:edit.tool('blur')参数阐明nameeditorContext对象的事件名称,如撤销undo,复原redo,清空内容clear等valueeditorContext事件参数,如初始化html内容edit.tool('setContents',{html}),设置文本edit.tool('insertText',{text})format批改款式,反对的值可查看editorContext format调用形式:edit.format('color','#999999')参数阐明name属性value值getContents获取编辑器内容,返回Promise.resolve调用形式:await edit.getContents()upKeyboard使光标进入编辑器并唤起键盘调用形式:edit.upKeyboard()emoji插入emoji表情调用形式:edit.emoji('')参数阐明emojiTextemoji字体addLink插入带参数的链接,如插入#话题或@谁调用形式:edit.addLink(Object)参数必填阐明prefix否在插入的内容后面增加一串字符,例如@谁suffix否在插入的内容前面增加一串字符,例如 #话题#的 #号name是插入的字符串data否链接附带的参数,用于解析后点击该链接返回getLink获取编辑器内增加的所有链接调用形式:edit.getLink()addImage通过相册/相机抉择图片并增加到编辑器中,此时图片是本地门路,在公布前应将图片上传,具体可查看示例我的项目index.vue提交事件示例;调用形式:edit.addImage(tempFilePaths)参数类型必填阐明tempFilePathsArray否不传参数时调起相册/相机抉择,传入图片数组时直接插入getImages获取编辑器内增加的所有图片调用形式:edit.getImages()replaceImage替换图片,编辑器内每个图片都会触发传入的fn,依据须要可自行替换成新的图片地址,用于将本地图片上传到服务器必须传入Function,且必须return一个图片地址调用形式:edit.replaceImage(fn)参数类型必填阐明fnFunction是return的图片地址将替换之前的图片// 提交前将所有未上传的本地图片上传到服务器并替换到编辑器edit.replaceImage(async(img)=>{ // 已上传的无需再上传 // 这里没有放到edit外部去过滤,因为我感觉需不需要替换得你本人决定 // 比方插入的base64图片是否须要上传 // img.indexOf('http') = 0阐明这个图片曾经是网络地址,就跳过 if(img.indexOf('http') === 0) {return img;} // 上传并替换图片 let {data} = await uni.uploadFile({ url: 'https://www.example.com/upload', //仅为示例,非实在的接口地址 filePath: img, //本地图片 name: 'file', formData: { 'user': 'test' } }); return data; }).then(res=>{ console.log('所有图片替换实现,返回最新的detail',JSON.stringify(res));}); 事件机制Edit为您设计了观察者模式,您能够在须要的中央注册和发送事件$fire(eventName,any)发送事件示例: ...

April 21, 2023 · 2 min · jiezi

关于uniapp:环信-uniapp-Demo升级改造计划Vue2迁移到Vue3一

前言因为环信uni-app Demo 为晚期通过工具从微信小程序转换为的 uni-app 我的项目,通过理论的应用以及复用反馈,目前曾经不适用于以后的开发应用,因而开启了整体降级革新打算,目前一期打算将 vue2 代码进行手动转换为 vue3+vite,并剔除原我的项目中曾经无用的我的项目代码,上面记录一下降级操作,如果降级过程,对大家有所帮忙,深感荣幸~后期筹备【重要】浏览 uni-app 官网文档 Vue2 降级 Vue3 指南文档地址调研迁徙到 Vue3 中原有的 Demo 中哪些三方库或者办法将不可用(_次要 uview UI 库不反对 Vue3_)。下载并运行环信官网 uni-app 我的项目(原我的项目master分支)。Demo下载地址在 HubilderX 中创立容器我的项目(_所谓容器我的项目即为创立一个空白的 Vue3 模板,用以逐渐将 Vue2 的我的项目代码逐渐挪到此我的项目中。_)在空白我的项目中引入 uni-ui 组件,次要为了应用其组件替换原我的项目 uviewUI 组件确认降级流程以及形式(_本次降级采纳渐进式语法批改模式_),次要形式为迁徙一个组件则将批改一个组件的语法为 vue3,如该组件依赖多个组件则先切断相组件的连贯(_正文大法_),后续逐渐放开并配套批改。外围迁徙步骤第一步、导入环信 uni-app SDK原有 Vue2 版本 uni-app-demo 我的项目为本地引入 SDK 包,对于有些习惯 npm 装置导入的同学不太敌对,目前 uniSDK 曾经反对 npm 装置并导入,因而将原有本地引入 js 文件改为通过 npm 装置 SDK 并 import 导入 SDK。//第一步 关上终端执行 npm install easemob-websdk//第二步 复制原demo中的utils文件夹至空白我的项目中//第三步 找到utils文件夹中的WebIM.js 文件中的导入SDK形式改写为impot 导入 easemob-websdk/uniApp包,具体代码如下。/* 原我的项目引入SDK代码 */import websdk from '../newSDK/uniapp-sdk-4.1.2';/* 改写后的代码 */import websdk from 'easemob-websdk/uniApp/Easemob-chat';第二步、CommonJS 导入导出改写为 ESM这种改写起因两点: ...

April 18, 2023 · 7 min · jiezi

关于uniapp:uniapp实现文件选择上传支持App小程序H5

lsj-upload插件地址:https://ext.dcloud.net.cn/plugin?id=5459不分明应用形式可点击右侧导入示例我的项目运行残缺示例此次更新2.0与1.0应用形式略有差别,已应用1.0的同学自行斟酌是否更新到2.0版本!!!应用插件有任何问题欢送退出QQ探讨群: 群1:701468256(已满)群2:469580165(已满)群3:667530868若能帮到你请高抬贵手点亮5颗星~重要提醒组件是窗口级滚动,不要在scroll-view内应用!!组件是窗口级滚动,不要在scroll-view内应用!!组件是窗口级滚动,不要在scroll-view内应用!!控件的height高度应与slot自定义内容高度保持一致nvue窗口只能应用固定模式position=absoluteshow() 当DOM重排后在this.$nextTick内调用show(),控件定位会更加精确hide() APP端webview层级比view高,如不心愿触发点击时,应调用hide暗藏控件,反之调用show若iOS端跨域服务端同学切实配置不好,可把hybrid下html目录放到服务器去,同源则不存在跨域问题。小程序端因hybrid不能应用本地HTML,所以插件提供的是从微信音讯列表拉取文件并抉择,请知悉。file对象不是object对象,也不能转json字符串,如果你打印file那就是{},能够打印file.name和file.size。返回的path是个blob类型,仅供用于文件回显,插件已内置好上传函数,调用上传会主动提交待上传文件,若非要本人拿path去搞上传那你本人解决。应用阐明属性是否必填值类型默认值阐明width否String100%容器宽度height是String80rpx容器高度debug否Booleanfalse打印调试日志option是Object-文件上传接口相干参数instantly否Booleanfalsetrue=主动上传count否Number10附件抉择下限(个)size否Number10附件大小下限(M)wxFileType否Stringall微信小程序文件选择器格局限度(all=从所有文件抉择,video=只能抉择视频文件,image=只能抉择图片文件,file=能够抉择除了图片和视频之外的其它的文件)accept否String-文件选择器input file格局限度(局部机型不兼容,倡议应用formats)formats否String-限度容许上传的格局,空串=不限度,默认为空,多个格局以逗号隔开,例如png,jpg,pdfchildId否StringlsjUpload控件的id(仅APP无效,利用内每个控件命名一个惟一Id,不同窗口也不要同名Id)position否Stringstatic控件的定位模式(static=控件随页面滚动;absolute=控件在页面中相对定位,不随窗口内容滚动)top,left,right,bottom否[Number,String]0设置控件相对地位,position=absolute时无效@change否FunctionMap抉择文件触发,返回所有已抉择文件Map汇合@progress否FunctionObject上传过程中产生状态变动的文件对象,需通过set更新至Map汇合@uploadEnd否FunctionObject上传完结回调,返回参数与progress统一option阐明参数是否必填阐明url是上传接口地址name否上传接口文件key,默认为fileheader否上传接口申请头formData否上传接口额定参数ref调用作用办法名传入参数阐明显示控件show-控件显示状态下可触发点击暗藏控件hide-控件暗藏状态下不触发点击动静设置文件列表setFiles[Array,Map] files传入格局请与组件抉择返回格局保持一致,且name为必须属性,可查看下方演示动静更新参数setData[String] name,[any] valuename反对a.b 和 a[b],可查看下方演示移除抉择的文件clear[String] name不传参数清空所有文件,传入文件name时删除该name的文件手动上传upload[String] name不传参数默认顺次上传所有type=waiting的文件,传入文件name时不关怀type是否为waiting,独自上传指定name的文件progress返回对象字段阐明字段阐明file文件对象name文件名称size文件大小type文件上传状态:waiting(期待上传)、loading(上传中)、success(胜利) 、fail(失败)responseText上传胜利后服务端返回数据(仅type为success时存在)以下演示为vue窗口应用形式,nvue应用区别是必须传入控件相对地位如top,bottom,left,right,且position只能为absolute,如不分明可点击右侧导入示例我的项目有具体演示代码。vue:<lsj-upload ref="lsjUpload" childId="upload1" :width="width" :height="height" :option="option" :size="size" :formats="formats" :debug="debug" :instantly="instantly" @uploadEnd="onuploadEnd" @progress="onprogress" @change="onChange"> <view class="btn" :style="{width: width,height: height}">抉择附件</view></lsj-upload><view class="padding"> <view>已抉择文件列表:</view> <!-- #ifndef MP-WEIXIN --> <view v-for="(item,index) in files.values()" :key="index"> <image style="width: 100rpx;height: 100rpx;" :src="item.path" mode="widthFix"></image> <text>提醒:【path次要用于图片视频类文件回显,他用自行处理】:{{item.path}}</text> <text>{{item.name}}</text> <text style="margin-left: 10rpx;">大小:{{item.size}}</text> <text style="margin-left: 10rpx;">状态:{{item.type}}</text> <text style="margin-left: 10rpx;">进度:{{item.progress}}</text> <text style="margin-left: 10rpx;" v-if="item.responseText">服务端返回演示:{{item.responseText}}</text> <text @click="resetUpload(item.name)" v-if="item.type=='fail'" style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #007AFF;">从新上传</text> <text @click="clear(item.name)" style="margin-left: 10rpx;padding: 0 10rpx;border: 1rpx solid #007AFF;">删除</text> </view> <!-- #endif --> <!-- #ifdef MP-WEIXIN --> <view v-for="(item,index) in wxFiles" :key="index"> <text>{{item.name}}</text> <text style="margin-left: 10rpx;">大小:{{item.size}}</text> <text style="margin-left: 10rpx;">状态:{{item.type}}</text> <text style="margin-left: 10rpx;">进度:{{item.progress}}</text> <view> <button @click="resetUpload(item.name)">从新上传</button> <button @click="clear(item.name)">删除</button> </view> </view> <!-- #endif --> </view>函数阐明export default { data() { return { // 上传接口参数 option: { // 上传服务器地址,须要替换为你的接口地址 url: 'http://hl.j56.com/dropbox/document/upload', // 该地址非实在门路,需替换为你我的项目本人的接口地址 // 上传附件的key name: 'file', // 依据你接口需要自定义申请头,默认不要写content-type,让浏览器自适配 header: { // 示例参数可删除 'Authorization': 'bearer eyJhbGciOiJSUzI1NiIsI', 'uid': '99', 'client': 'app', 'accountid': 'DP', }, // 依据你接口需要自定义body参数 formData: { // 'orderId': 1000 } }, // 抉择文件后是否立刻主动上传,true=抉择后立刻上传 instantly: true, // 必传宽高且宽高应与slot宽高保持一致 width: '180rpx', height: '180rpx', // 限度容许上传的格局,空串=不限度,默认为空 formats: '', // 文件上传大小限度 size: 30, // 文件数量限度 count: 2, // 文件回显列表 files: new Map(), // 微信小程序Map对象for循环不显示,所以转成一般数组,不要问为什么,我也不晓得 wxFiles: [], // 是否打印日志 debug: true, // 演示用 tabIndex: 0, list:[], } }, onReady() { setTimeout(()=>{ console.log('----演示动静更新参数-----'); this.$refs['lsjUpload'+this.tabIndex].setData('formData.orderId','动静设置的参数'); console.log('以下正文内容为-动静更新参数更多演示,放开后可查看演示成果'); // 批改option对象的name属性 // this.$refs.lsjUpload.setData('name','myFile'); // 批改option对象的formData内的属性 // this.$refs.lsjUpload.setData('formData.appid','1111'); // 替换option对象的formData // this.$refs.lsjUpload.setData('formData',{appid:'222'}); // option对象的formData新增属性 // this.$refs.lsjUpload.setData('formData.newkey','新插入到formData的属性'); // ---------演示初始化值,用于已提交后再次编辑时需带入已上传文件------- // 形式1=传入数组 // let files1 = [{name: '1.png'},{name: '2.png',}]; // 形式2=传入Map对象 // let files2 = new Map(); // files2.set('1.png',{name: '1.png'}) // 此处调用setFiles设置初始files // this.$refs.lsjUpload.setFiles(files1); // 初始化tab this.onTab(0); },2000) }, methods: { // 某文件上传完结回调(成功失败都回调) onuploadEnd(item) { console.log(`${item.name}已上传完结,上传状态=${item.type}`); // 更新以后窗口状态变动的文件 this.files.set(item.name,item); // ---可删除--演示上传实现后取服务端数据 if (item['responseText']) { console.log('演示服务器返回的字符串JSON转Object对象'); this.files.get(item.name).responseText = JSON.parse(item.responseText); } // 微信小程序Map对象for循环不显示,所以转成一般数组, // 如果你用不惯Map对象,也能够像这样转一般数组,组件应用Map次要是防止重复文件去重操作 // #ifdef MP-WEIXIN this.wxFiles = [...this.files.values()]; // #endif // 强制更新视图 this.$forceUpdate(); // ---可删除--演示判断是否所有文件均已上传胜利 let isAll = [...this.files.values()].find(item=>item.type!=='success'); if (!isAll) { console.log('已全副上传完毕'); } else { console.log(isAll.name+'待上传'); } }, // 上传进度回调 onprogress(item) { // 更新以后状态变动的文件 this.files.set(item.name,item); console.log('打印对象',JSON.stringify(this.files.get(item.name))); // 微信小程序Map对象for循环不显示,所以转成一般数组,不要问为什么,我也不晓得 // #ifdef MP-WEIXIN this.wxFiles = [...this.files.values()]; // #endif // 强制更新视图 this.$forceUpdate(); }, // 文件抉择回调 onChange(files) { console.log('以后抉择的文件列表:',JSON.stringify([...files.values()])); // 更新抉择的文件 this.files = files; // 强制更新视图 this.$forceUpdate(); // 微信小程序Map对象for循环不显示,所以转成一般数组,不要问为什么,我也不晓得 // #ifdef MP-WEIXIN this.wxFiles = [...this.files.values()]; // #endif // ---可删除--演示从新定位覆盖层控件 this.$nextTick(()=>{ console.log('演示从新定位'); this.$refs.lsjUpload0.show(); this.$refs.lsjUpload1.show(); this.$refs.lsjUpload2.show(); }); }, // 手动上传 upload() { // name=指定文件名,不指定则上传所有type等于waiting和fail的文件 this.$refs['lsjUpload'+this.tabIndex].upload(); }, // 指定上传某个文件 resetUpload(name) { this.$refs['lsjUpload'+this.tabIndex].upload(name); }, // 移除某个文件 clear(name) { // name=指定文件名,不传name默认移除所有文件 this.$refs['lsjUpload'+this.tabIndex].clear(name); }, /** * ---可删除--演示在组件上方增加新内容DOM变动 * DOM重排演示,重排后组件外部updated默认会触发show办法,若非凡状况未能触发updated也能够手动调用一次show() * 什么是DOM重排?自行百度去 */ add() { this.list.push('DOM重排测试'); }, /** * ---可删除--演示Tab切换时覆盖层是否能被点击 * APP端因为是webview,层级比view高,此时若不心愿点击触发抉择文件,须要手动调用hide() * 手动调用hide后,须要调用show()能力复原覆盖层的点击 */ onTab(tabIndex) { this.$refs.lsjUpload0.hide(); this.$refs.lsjUpload1.hide(); this.tabIndex = tabIndex; this.$nextTick(()=>{ this.$refs['lsjUpload'+this.tabIndex].show(); }) }, /** * 关上nvue窗口查看非追随窗口滚动成果 */ open() { uni.navigateTo({ url: '/pages/nvue-demo/nvue-demo' }); } }}舒适提醒文件上传如阐明表白还不够分明,不分明怎么应用可导入残缺示例我的项目运行体验和查看APP端请优先联调Android,上传胜利后再运行iOS端,如iOS返回status=0则须要后端开启容许跨域;header的Content-Type类型须要与服务端要求统一,否则收不到附件(服务端若没有明文规定则可不写,应用默认匹配)服务端不分明怎么配置跨域可加群征询,具体百度~欢送退出QQ探讨群:701468256(已满)欢送退出QQ探讨群:469580165(已满)欢送退出QQ探讨群:667530868若能帮到你还请点亮5颗小星星以作激励哈~若能帮到你还请点亮5颗小星星以作激励哈~若能帮到你还请点亮5颗小星星以作激励哈~

March 23, 2023 · 2 min · jiezi

关于uniapp:uniapp-在微信小程序中图片宽度显示问题

在uniapp中,如果你的富文本图片显示宽度不失常,你能够通过设置图片的宽高属性来解决这个问题。例如,你能够在富文本中增加以下代码来设置图片的宽度为100%: <img src="your_image_url" style="width: 100%" /> 另外,如果你想设置图片的高度,你能够增加以下代码: <img src="your_image_url" style="height: 100px" /> 当然,能够实现一个 filter 来主动对图片宽度进行解决。 export default { // ... filters: { formatRichHtml(html) { if (!html) { return html; } //管制小程序中图片大小 let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) { console.log(match.search(/style=/gi)); if (match.search(/style=/gi) === -1) { match = match.replace(/\<img/gi, '<img style=""'); } return match; }); newContent = newContent.replace(/style="/gi, '$& max-width:100% !important; '); newContent = newContent.replace(/<br[^>]*\/>/gi, ''); return newContent; } } // ...}在调用时只须要如下调用 export default { // ... filters: { formatRichHtml(html) { if (!html) { return html; } //管制小程序中图片大小 let newContent = html.replace(/<img[^>]*>/gi, function (match, capture) { console.log(match.search(/style=/gi)); if (match.search(/style=/gi) === -1) { match = match.replace(/\<img/gi, '<img style=""'); } return match; }); newContent = newContent.replace(/style="/gi, '$& max-width:100% !important; '); newContent = newContent.replace(/<br[^>]*\/>/gi, ''); return newContent; } } // ...}在调用时只须要如下调用即可 ...

December 27, 2022 · 1 min · jiezi

关于uniapp:uniapp-开发输入键盘几种-confirmtype-状态

在 uniapp 中,能够应用 confirm-type 属性来管制 input 组件的确定键的款式。如果要将确定键显示为搜寻按钮,能够将 confirm-type 设置为 search,代码示例如下: <input type="text" confirm-type="search" placeholder="请输出关键字" />须要留神的是,在不同平台上,这个属性的体现可能不同。例如,在安卓平台上,会将确定键显示为搜寻按钮,而在 iOS 平台上,可能会显示为实现按钮。如果您心愿在不同平台上看到雷同的成果,能够通过自定义款式来实现。 在 uniapp 中,confirm-type 属性能够设置为以下几种值: send:将确定键显示为发送按钮。search:将确定键显示为搜寻按钮。next:将确定键显示为下一步按钮。go:将确定键显示为返回按钮。done:将确定键显示为实现按钮。不同平台对这些值的反对状况可能不同。例如,在安卓平台上,将 confirm-type 设置为 send 可能会没有任何成果,而在 iOS 平台上,会将确定键显示为发送按钮。

December 15, 2022 · 1 min · jiezi

关于uniapp:uniapp-微信小程序开启发送好友和朋友圈

引言最近在开发微信小程序的过程中,须要在页面开启分享性能——分享给好友或者是朋友圈的性能。 找了一圈的uniapp文档,决定在这里记录一下,分享给有缘人应用。成果 在微信小程序中,这个默认是敞开状态的如下: 开启的正确形式 onShareAppMessage(res) { if (res.from === 'button') { console.log(res.target) } return { title: '分享进来的题目', path: `你以后的页面路由`, } }, onShareTimeline(res) { return { title: '分享进来的题目', path: `你以后的页面路由`, desc: '形容', } }应用形式很简略,只须要和生命周期钩子函数同级应用就行: 当然,如果您须要体验该性能,能够微信关上小程序搜寻 【太极开发者平台即可】

October 27, 2022 · 1 min · jiezi

关于uniapp:可视化uniapp整合thinkphp6-EasyWeChat实现微信小程序支付

可视化uniapp整合thinkphp6 EasyWeChat实现微信小程序、公众事件领取,调用tp6接口返回微信相干下单参数。 开源地址:https://gitee.com/diygw/diygw... //小程序领取相干办法var Pay = { async pay(param){ let page = getApp().globalData.currentPage let session = page.$session; if(!session.getToken() || !session.getUser().openid){ //如果参数自带openid跳过验证 if(!param.openid){ page.showToast('请先登录') return; } } if(!param.total){ page.showToast('请配置价格参数total') return; } let data = await page.$http.post(param.url||'/api/wepay/order',{ total:param.total, body:param.body, openid:param.openid||session.getUser().openid, },{},'json') if(data.code!=200){ page.showToast(data.msg) return; } if(this[param.paytype]){ this[param.paytype](Object.assign(data,param)) }else{ page.showToast('请应用微信关上') return; } }, //微信领取 weixin(params = {}) { uni.requestPayment({ provider: 'wxpay', timeStamp: params.data.timeStamp,// 领取签名工夫戳,留神微信jssdk中的所有应用timestamp字段均为小写。但最新版的领取后盾生成签名应用的timeStamp字段名需大写其中的S字符 nonceStr: params.data.nonceStr,// 领取签名随机串,不长于 32 位 package: params.data.package,// 对立领取接口返回的prepay_id参数值,提交格局如:prepay_id=\*\*\*) signType: params.data.signType,// 签名形式,默认为'SHA1',应用新版领取需传入'MD5' paySign: params.data.paySign,// 领取签名 success: res => { if(typeof params.success=='function'){ params.success(res) }else{ console.log('配置领取回调胜利办法') } }, fail: res => { if(typeof params.fail=='function'){ params.fail(res) }else{ console.log('配置领取回调失败办法') } } }) }}export default Pay<?phpnamespace app\api\controller;use app\BaseController;use app\common\model\DiyOrderModel;use app\common\model\DiyUserModel;use EasyWeChat\Factory;use think\App;use think\facade\Log;/* * 领取 */class WepayController extends BaseController{ //判断是否全副不须要登录 public $notNeedLoginAll = false; public $isModel = false; //判断不须要登录的办法 public $notNeedLogin = ['notify']; public $wepayApp; /** * 构造方法 * @access public * @param App $app 利用对象 */ public function __construct(App $app) { parent::__construct($app); $paymentConfig = config('wechat.payment'); $this->wepayApp = Factory::payment($paymentConfig); } /** * 用户下单 * @return \think\response\Json * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException * @throws \GuzzleHttp\Exception\GuzzleException * @throws \think\exception\DbException */ public function order(){ $userModel = DiyUserModel::where(['id'=>$this->request->userId])->find(); if(!$userModel){ return $this->error('请先登录'.$this->request->userId); } $user = $userModel->toArray(); if(empty($user['openid'])){ return $this->error('请先登录'); } // 生成订单信息 $data = $this->request->param(); $data['orderNo'] = getOrderNo(); $data['status'] = 0; $data['payStatus'] = 0; $data['openid'] = $user['openid']; $data['userId'] = $this->request->userId; $model = new DiyOrderModel(); $data = $model->add($data); $notify_url = url('api/wepay/notify') ->suffix('html') ->domain($this->request->domain())->build(); //调起微信领取 $payData = [ 'body' => $data['body'], 'out_trade_no' =>$data['orderNo'] , 'total_fee' =>(float)($data['total']*100), 'notify_url' => $notify_url, // 领取后果告诉网址,如果不设置则会应用配置里的默认地址 'trade_type' => 'JSAPI', // 请对应换成你的领取形式对应的值类型 'openid' => $data['openid'], ]; $result = $this->wepayApp->order->unify($payData); if ($result['return_code'] === 'SUCCESS') { $jssdk = $this->wepayApp->jssdk; $config = $jssdk->bridgeConfig($result['prepay_id'],false); // 返回数组 return $this->successData($config); }else{ return $this->errorData($result); } } /** * 领取回调 * @return mixed */ public function notify(){ $response = $this->wepayApp->handlePaidNotify(function ($message,$error){ $order = DiyOrderModel::where(['order_no'=>$message['out_trade_no']])->find(); if (!$order || $order['status'] == '1') return true; if ($message['return_code'] === 'SUCCESS') { if ($message['result_code'] === 'SUCCESS') { $order['status'] = '1'; } elseif ($message['result_code'] === 'FAIL') { $order['status'] = '2'; } } else { return $error('通信失败,请稍后再告诉我'); } if ($order->save()){ return true; } return false; }); $send = $response->send(); return $send; }}<?phpnamespace app\api\controller;use app\BaseController;use app\common\model\DiyUserModel;use EasyWeChat\Factory;use Overtrue\Socialite\AuthorizeFailedException;use thans\jwt\facade\JWTAuth;use think\App;/* * 微信小程序 */class WexcxController extends BaseController{ //判断是否全副不须要登录 public $notNeedLoginAll = true; public $isModel = false; //判断不须要登录的办法 public $notNeedLogin = []; public $wexcxApp = null; /** * 构造方法 * @access public * @param App $app 利用对象 */ public function __construct(App $app) { parent::__construct($app); $minConfig = config('wechat.mini_program'); $this->wexcxApp = Factory::miniProgram($minConfig); } /** * 获取用户登录信息 * @return \think\response\Json * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function login(){ $userInfo = json_decode($this->request->post('userInfo'),true); $code = $this->request->post('code'); $auth = $this->wexcxApp->auth; $opendata = $auth->session($code); if(isset($opendata['openid'])){ $openid = $opendata['openid']; $type = 'weixcx'; $model = new DiyUserModel(); //查找获取微信小程序用户 $user = $model->where('openid',$openid)->where('type',$type)->find(); $data['openid'] = $openid; $data['type'] = $type; $data['nickname'] = $userInfo['nickName']; $data['avatar'] = $userInfo['avatarUrl']; $data['country'] = $userInfo['country']; $data['province'] = $userInfo['province']; $data['gender'] = $userInfo['gender']; if($user){ $userId = $user->toArray()['id']; $data['id'] = $userId; $user->edit($data); }else{ $model = new DiyUserModel(); $model->add($data); $userId = $data['id']; } $token = "bearer".JWTAuth::builder(['uid' => $userId]); $opendata['token'] = $token; $data = array_merge($data,$opendata); return $this->successData($data); }else{ return $this->errorData($opendata,'登录失败'); } } /** * 服务端签名,获取操作权限 */ public function getSignPackage(){ $url = $this->request->param('url'); try { return $this->successData($this->wexcxApp->jssdk->buildConfig([ 'checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard' ],false,false,false,['wx-open-launch-weapp'],'https://php.diygw.com/pay/index.html')); }catch (Throwable | Exception $e){ return $this->error("获取用户失败,请重试"); } }}

October 10, 2022 · 3 min · jiezi

关于uniapp:uniapp中使用canvas实现二维码分享海报

案例1实现背景: 海报的尺寸依据图片大小来的,宽度百分百,高度同比例缩放,图上笼罩二维码如果没有设置海报图片,应用别的图片,在底部增加一个底部的固定图片,和二维码,和图片的左上角笼罩log图难点:因为是应用canvas渲染的图片,然而图片的尺寸不是固定,也就是canvas的尺寸不是固定(解决:在内部先获取图片的尺寸,传进这个组件中)h5是渲染失常的,微信小程序图片渲染不进去(解决:微信不反对canvas间接渲染网络图片,所以须要先缓存到本地)<template> <view class="poster-box" ref="posterBox" @click="hidePoster"> <canvas :style="{ width: posterOptions.poster.canvasWidth + 'px', height: posterOptions.poster.canvasHeight + 'px', }" canvas-id="myCanvas" ></canvas> <!-- #ifdef MP --> <image :src="base64" class="poster-image" :draggable="false" show-menu-by-longpress="true" ></image> <!-- #endif --> <!-- #ifdef H5 --> <image class="poster-image" :src="base64" :draggable="false"></image> <!-- #endif --> </view></template><script>import Qr from '@/utils/wxqrcode'export default { name: 'poster_canvas', data() { return { base64: '', // 海报绘制成图片以便保留 } }, props: { //图片地址 posterOptions: { type: Object, require: true, }, }, mounted() { this.$nextTick(() => { this.imgToCanvas() }) }, methods: { async imgToCanvas() { let that = this let canvasHeight = this.posterOptions.isHavePosterImg ? this.posterOptions.poster.canvasHeight : this.posterOptions.poster.canvasHeight - this.posterOptions.buttonOption.h // 渲染大图 let ctx = uni.createCanvasContext('myCanvas', that) console.log(11111,this.posterOptions) ctx.drawImage( this.posterOptions.poster.url, 0, 0, this.posterOptions.poster.canvasWidth, canvasHeight ) if (!this.posterOptions.isHavePosterImg) { //渲染底部的图片 ctx.drawImage( this.posterOptions.buttonOption.bottomUrl, this.posterOptions.buttonOption.x, this.posterOptions.buttonOption.y, this.posterOptions.buttonOption.w, this.posterOptions.buttonOption.h ) } // 渲染二维码 if (this.posterOptions.QrOption.isWeChatMiniApp) { ctx.drawImage( this.posterOptions.QrOption.QrUrl, this.posterOptions.QrOption.x, this.posterOptions.QrOption.y, this.posterOptions.QrOption.w, this.posterOptions.QrOption.h ) } else { //一般二维码 let qrCodeImg = Qr.createQrCodeImg(this.posterOptions.QrOption.QrUrl, { size: parseInt(300), }) ctx.drawImage( qrCodeImg, this.posterOptions.QrOption.x, this.posterOptions.QrOption.y, this.posterOptions.QrOption.w, this.posterOptions.QrOption.h ) } if (!this.posterOptions.isHavePosterImg) { // 渲染log 和文字 ctx.drawImage( this.posterOptions.logOption.logUrl, this.posterOptions.logOption.x, this.posterOptions.logOption.y, this.posterOptions.logOption.w, this.posterOptions.logOption.h ) ctx.fillStyle = this.posterOptions.textOption.color ctx.setFontSize(22) ctx.font = 'bold arial' ctx.fillText( this.posterOptions.textOption.text, this.posterOptions.textOption.x, this.posterOptions.textOption.y ) } ctx.save() //保留 ctx.draw() //绘制 // 不加提早的话,base64有时候会赋予undefined // 把以后画布指定区域的内容导出生成指定大小的图片,并返回文件门路 setTimeout(() => { uni.canvasToTempFilePath( { canvasId: "myCanvas", fileType: "jpg", width:that.posterOptions.poster.canvasWidth, height:that.posterOptions.poster.canvasHeight, destWidth:that.posterOptions.poster.canvasWidth, destHeight:that.posterOptions.poster.canvasHeight, success: function (res) { that.base64 = res.tempFilePath; }, fail: function (error) { console.log(error, "谬误"); }, },that ); }, 500); }, hidePoster() { // #ifdef H5 this.$parent.$parent.hidePoster() // #endif // #ifndef H5 this.$parent.hidePoster() // #endif }, },}</script><style lang="scss" scoped>.poster-box { position: fixed; top: 0; z-index: 999; background-color: rgba(0, 0, 0, 0.8); width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;}.poster-image { position: absolute; top: 0; left: 0; z-index: 1000; width: 100%; height: 100%; opacity: 0;}</style>应用 ...

September 4, 2022 · 6 min · jiezi

关于uniapp:Uniapp-小程序开发完美适配刘海屏的Appbar方案

在Uniapp开发小程序的过程中,常常会遇到官网提供的appbar计划无奈满足开发需要的问题,在应用自定义appbar开发过程中,难以避免的会遇到适配刘海屏的问题,接下来我将会带给大家最完满的刘海屏适配计划,间接上代码。 在app.vue中退出获取机型头部高度的办法,并把获取的数据存入vuex <script> export default { data() { return { globalData: { //全局数据管理 navBarHeight: 0, // 导航栏高度 menuBottom: 0, // 胶囊距底部间距(顶部间距也是这个) menuHeight: 0, // 胶囊高度 }, } }, methods: { calcNavBarInfo () { // 获取零碎信息 const systemInfo = wx.getSystemInfoSync(); // 胶囊按钮地位信息 const menuButtonInfo = wx.getMenuButtonBoundingClientRect(); // 导航栏高度 = 状态栏到胶囊的间距(胶囊上坐标地位-状态栏高度) * 2 + 胶囊高度 + 状态栏高度 this.globalData.navBarHeight = (menuButtonInfo.top - systemInfo.statusBarHeight) * 2 + menuButtonInfo.height + systemInfo.statusBarHeight; // 状态栏和菜单按钮(标题栏)之间的间距 // 等同于菜单按钮(标题栏)到注释之间的间距(胶囊上坐标地位-状态栏高度) this.globalData.menuBottom = menuButtonInfo.top - systemInfo.statusBarHeight; // 菜单按钮栏(标题栏)的高度 this.globalData.menuHeight = menuButtonInfo.height; this.$store.commit('update_globalStyle', this.globalData); } }, onLaunch: function() { console.log('App Launch'); this.calcNavBarInfo(); }, onShow: function() { console.log('App Show') }, onHide: function() { console.log('App Hide') } }</script><style> /*每个页面公共css */ view { box-sizing: border-box; } ::-webkit-scrollbar { display: none; } .flex-right { display: flex; justify-content: flex-end; align-items: center; } .flex-center { display: flex; justify-content: center; align-items: center; }</style>创立自定义的appbar组件: ...

September 3, 2022 · 2 min · jiezi

关于uniapp:uniapp实现IM即时通讯仿微信聊天功能

本文介绍如何基于 UNIAPP 应用 即时通讯SDK ZIM SDK 疾速实现根本的音讯收发性能。 1 uniapp im 即时通讯性能 计划介绍即时通讯SDK ZIM SDK 提供了如下接入计划: 在此计划中,您须要通过您本人的业务零碎实现以下业务逻辑: 搭建客户端的用户治理逻辑,并下发用户 ID 用于客户端登录。鉴权 Token,倡议由您的业务后盾自行实现,保障鉴权数据安全。uni-app SDK 是一个基于原生 iOS/Android 平台 ZIM SDK 的 uni-app Wrapper。开发者如需应用 uni-app 开发 Web 或小程序平台的利用,请下载对应的 SDK 集成应用:下载 Web SDK 和 下载小程序 SDK。 2 集成 IM 即时通讯SDK 的前提条件在应用 IM即时通讯 SDK ZIM SDK 前,请确保: 已在 ZEGO 控制台 创立我的项目,获取到了接入 IM即时通讯 ZIM SDK 服务所需的 AppID 和 ServerSecret。ZIM 服务权限不是默认开启的,应用前,请先在 ZEGO 控制台 自助开明 ZIM 即时通讯 服务(详情请参考 项目管理 - 即时通讯),若无奈开明 ZIM即时通讯 服务,请分割 ZEGO 技术支持开明。已获取登录 即时通讯 SDK 所需的 Token,详情请参考 应用 Token 鉴权。3 集成 uniapp IM 即时通讯 SDK3.1 (可选)新建我的项目此步骤以如何创立新我的项目为例,如果是集成到已有我的项目,可疏忽此步。 ...

August 29, 2022 · 3 min · jiezi

关于uniapp:手把手教你uniapp接入聊天IM即时通讯功能源码分享

本文介绍如何基于uniapp应用 IM即时通讯SDK ZIM SDK 疾速实现同腾讯微信音讯收发聊天交友性能。实现uniapp跨平台框架开发多端利用,节俭开发成本。 1 IM即时通讯SDK接入计划介绍ZIM SDK IM即时通讯SDK提供了如下接入计划: 在此计划中,您须要通过您本人的IM即时通讯业务零碎实现以下业务逻辑: 搭建客户端的用户治理逻辑,并下发用户 ID 用于客户端登录。鉴权 Token,倡议由您的业务后盾自行实现,保障鉴权数据安全。2 接入IM即时通讯SDK的前提条件在应用 IM即时通讯SDK ZIM SDK 前,请确保: 开发环境: React Native 0.60.0 或以上版本。iOS 9.0 或以上版本的 iOS 设施或模拟器(举荐应用真机)。Android 4.0.3 或以上版本的 Android 设施或模拟器(举荐应用真机),如果为真机,请开启“容许调试”选项。iOS / Android 设施曾经连贯到 Internet。配置 VS Code 开发环境,可在利用商店中搜寻 “React Native Tools” 扩大并下载。已在 ZEGO 控制台 创立我的项目,获取到了接入 ZIM SDK 服务所需的 AppID 和 ServerSecret。ZIM 即时通讯SDK 服务权限不是默认开启的,应用前,请先在 ZEGO 控制台 自助开明 ZIM 服务(详情请参考 项目管理 - 即时通讯),若无奈开明 ZIM 即时通讯SDK 服务,请分割 ZEGO 技术支持开明。已获取登录 IM即时通讯SDK 所需的 Token,详情请参考 应用 Token 鉴权。3 集成 IM即时通讯SDK3.1 (可选)新建我的项目此步骤以如何创立新我的项目为例,如果是集成到已有我的项目,可疏忽此步。 ...

August 8, 2022 · 3 min · jiezi

关于uniapp:uniapp集成极光推送

本文旨在记录应用极光推送中遇到的坑 注册极光账号并获取AppKey去极光官网注册账号,并创立利用,填写包名,获取AppKey。 引入极光推送插件极光推送依赖 极光JCore官网SDK,所以首先须要引入 极光JCore官网SDK。而后引入 极光JPush官网SDK。而后在我的项目的manifest.json中,找到App原生插件配置抉择咱们援用的云端插件填写获取到的AppKey 援用曾经实现,上面开始编码。 调用极光推送在common中新建jpush.js 公共APIAndroid独有APIiOS独有API// 引入极光推送插件var jpushModule = uni.requireNativePlugin("JG-JPush");export default () => { // 开启debug模式 jpushModule.setLoggerEnable(true); // 初始化SDK jpushModule.initJPushService(); // 连贯状态回调 jpushModule.addConnectEventListener(result => { let connectEnable = result.connectEnable // true已连贯, false未连贯 console.log("jpush连贯", connectEnable) }) // 设置别名 jpushModule.setAlias({ "alias": "别名", "sequence": 1 }) // 告诉事件回调 jpushModule.addNotificationListener(result => { // 通过 notificationEventType字段辨别是收到告诉还是点击告诉 const { notificationEventType, messageID, title, content } = result if(notificationEventType == 'notificationOpened') { // 点击告诉操作 } else if(notificationEventType == 'notificationArrived') { // 收到告诉 } }) // 获取应用程序的 RegistrationID。 只有当应用程序胜利注册到 JPush 的服务器时才返回对应的值,否则返回空字符串 jpushModule.getRegistrationID(result => { if (result.registerID) { uni.setStorageSync("register_id", result.registerID) } }) // 自定义音讯,不会显示在告诉栏里 jpushModule.addCustomMessageListener(result => { console.log("自定义音讯", result) })}在App.vue中引入jpush.js ...

July 22, 2022 · 1 min · jiezi

关于uniapp:uniapp封装unishowMsg提示框

在min.js中// 封装弹框办法 uni.$showMsg = function (title = '加载胜利', duration = 1500){ uni.showToast({ title, duration, icon:'none' })({ }) }调用提醒办法 onShow() { // uni.$showMsg() // 封装弹框办法 uni.$showMsg()},

July 7, 2022 · 1 min · jiezi

关于uniapp:uniapp点击上传图片后清除原来的图片数据

执行步骤:点击“上传图片”按钮弹出弹窗,抉择图片点击“确定”图片上传胜利后弹窗敞开,再点击上传图片会发现弹窗会保留有上次选中图片的数据。开发要求:图片上传胜利后默认革除上一次选中上传的图片数据。解决办法: <view class="pop-up1" @click="rule1=true">弹窗1</view> <view class="sure_btn" @click="formData.type = 2;showOne()"> <p>上传图片</p> </view></view><!-- 弹窗 --><view class="boxBm test_pop" v-if="isLower"> <view class="box2 share-state"> <image class="img_close" @click="closePop" src="../../../static/img/koreaActive/close.png" mode=""></image> <view class="addImg"> <image class="" @click="addImg(),imgItem=true" src="../../../static/img/japanActive/upload.png" mode=""></image> </view> <textarea class="active_text" maxlength="1000" @input="getText" v-model="formData.remarks" placeholder="您尊贵的意见和倡议......" /> <button type="default" @click='uploadImage()'>確定</button> <view class="Img_box" v-if="imgItem" v-for="(item,index) in imgList" :key="index"> <image class="Img_item" :src="item" mode=""></image> </view> </view></view><script> import api from '@/apis/api.js' import URL from '@/common/config.js' export default { data() { return { token:'', showShare: false, isLower: false, imgList:[], List:'', rule1:false, formData: { pic: "", remarks:"", type:0 }, } }, async onLoad(e) { if (e.lang) { this.$i18n.locale = e.lang this.lang = e.lang } else { this.lang = 'en' } console.log("eee",e) await this.$onLaunched; //获取浏览器缓存的token this.token = localStorage.getItem('token') }, methods: { //弹出弹窗 showOne(){ this.showShare=true; this.isLower = true; // console.log('this.showShare',this.showShare) }, //革除上一次选中的图片数据 closePop() { this.formData = { pic: "", remarks:"", type:0 } this.imgList = [] this.List = [] this.isLower=false }, //点击抉择图片 addImg() { uni.chooseImage({ count: 3, //默认9 sizeType: ['original', 'compressed'], //能够指定是原图还是压缩图,默认二者都有 sourceType: ['album'], //从相册抉择 loop: true, success: res => { // console.log(res); if (res.tempFilePaths.length != 0) { this.imgList.push(res.tempFilePaths[0]); } var tempFiles = res.tempFiles[0]; uni.uploadFile({ url: URL.httpurl + '/api/common/upload', file: tempFiles, method: 'POST', name: 'file', header:{ token: this.token, }, success: uploadFileRes => { var data_ =JSON.parse(uploadFileRes.data) console.log('data_',data_) this.formData.pic = data_.data.url; this.formData.pic = data_.data.url; // console.log('上传图片', JSON.parse(uploadFileRes.data)); }, fail(err) { console.log(err); } }); } }); }, //点击“确定”上传图片 uploadImage(){ this.$apis.saveImg(this.formData) .then(res => { console.log(res) uni.showToast({//提醒 title: res.msg, // lang:this.lang, }) //执行革除数据办法 this.closePop() }) } }</script> ...

June 20, 2022 · 2 min · jiezi

关于uniapp:uniapp-和-HTML5-区别

uniapp 和 HTML5 区别:1、uniapp 是一个应用 Vue.js 开发所有前端利用的框架,而 HTML5 是构建 Web 内容的一种语言形容形式;2、uniapp 不反对 dom 操作,而 H5 端有 dom 对象;3、uniapp 不反对过滤器等等。 本教程操作环境:windows7 零碎、uni-app2.5.1 版本、thinkpad t480 电脑。 举荐(收费):uni-app 开发教程 uniapp 是一个应用 Vue.js 开发所有前端利用的框架,开发者编写一套代码,可公布到 iOS、Android、Web(响应式)、以及各种小程序(微信 / 支付宝 / 百度 / 头条 / QQ / 钉钉 / 淘宝)、快利用等多个平台。 HTML5 是构建 Web 内容的一种语言形容形式。HTML5 是互联网的下一代规范,是构建以及出现互联网内容的一种语言形式.被认为是互联网的核心技术之一。HTML 产生于 1990 年,1997 年 HTML4 成为互联网规范,并广泛应用于互联网利用的开发。 uniapp 反对跨挪动端开发,如果只做 H5 端,用 uniapp 其实和用 vue 开发没什么区别,vue 能用的插件,uniapp 也能用。 uniapp 的性能问题次要集中在 app 端,做 H5 和 VUE 的开发体验是统一的。 ...

May 26, 2022 · 1 min · jiezi

关于uniapp:微信小程序和-uniapp-的区别是什么

区别:1、触摸事件名称上,微信小程序是 bindtap,uniapp 是 “@click”;2、if 判断上,微信小程序应用 “wx:if="{{isShow}}” 语句,uniapp 应用 “v-if="isShow"” 语句。 本教程操作环境:windows10 零碎、uni-app2.5.1 版本,Dell G3 电脑。 举荐:《uni-app 开发教程》 微信小程序和 uniapp 的区别 触摸事件名称:①微信小程序:bindtap②uni-app:@click 函数传参形式:①微信小程序:<view bindtap="click" data-id="id"></view>②uni-app:<view @click="click(id)"></view> 函数接管参数:①微信小程序:function(e){this.setData(currentId:e.currentTarget.dataset.id)}②uni-app:function(id){this.currentId = id} for 循环:①微信小程序:<view wx:for="{{currentList}}" wx:for-index="s_index" wx:for-item="s_item"></view>②uni-app:<view v-for="(s_item,s_index) in currentList"></view> if 判断:①微信小程序:<view wx:if="{{isShow}}"></view>②uni-app:<view v-if="isShow"></view> src 动静接管图片:①微信小程序:<image src="{{item.img}}"></image>②uni-app:<image :src="$util.img(item.img)"></image> 页面传参:①微信小程序:<navigator url="/pages/live?id={{item.room_id}}"></navigator>②uni-app:<navigator :url="'/pages/live?id=' + item.room_id"></navigator> 源码附件曾经打包好上传到百度云了,大家自行下载即可~ 链接: https://pan.baidu.com/s/14G-b...提取码: yu27百度云链接不稳固,随时可能会生效,大家放松保留哈。 如果百度云链接生效了的话,请留言通知我,我看到后会及时更新~ 开源地址码云地址:http://github.crmeb.net/u/defu Github 地址:http://github.crmeb.net/u/defu

May 25, 2022 · 1 min · jiezi

关于uniapp:腾讯云直播插件MLVB如何借助这些优势成为主播直播推拉流的神助攻

跨平台代码公布因为智密-腾讯云直播 MLVB 插件是基于 HbuilderX 开发,并采纳了 uni-app 框架。因而能够实现一套代码公布多个平台的跨平台开发个性。目前 uni-app 框架不仅反对了  iOS、Android 两大支流手机操作系统的APP公布,还反对 H5、小程序和 Web 版公布。 再联合 MLVB 的 SDK 自身就可能兼容这些平台进行数据接入,因而真正让主播和观众能够不受限制的推送/观看直播,构建多种直播场景。 高速推流腾讯云为规范 RTMP 提供 UDP 减速能力,当您应用挪动直播 SDK 的 RTMP 推流性能时,配合云直播,能够开启 UDP 减速能力,开启 UDP 减速后的推流品质会比规范 RTMP 推流有更好的网络稳定抵抗力,同时能够取得更好的推流速度,将传统直播中3秒 - 5秒延时升高至1秒以内,同时兼顾秒开、卡顿率等外围指标从而改善以后直播流的观看体验,升高全局卡顿率。 互动连麦性能所有主播在进行直播时,为了留住老观众,并吸引更多的新流量,与粉丝进行互动是必不可少的。不论是通过留言还是语音连麦,乃至于粉丝进行视频互动,当初都曾经是一个直播APP必备的性能。而基于uniapp框架开发的智密-腾讯云直播 SDK 因为其反对模块化开发的劣势,连麦的性能甚至不须要从新开发,仅作为功能模块能够非常简便地退出到现有的直播APP中。 同时因为摈弃了传统TCP协定而转向应用UDP协定进行RTMP传输,因而不论是语音连麦还是视频互动的提早都非常低。进一步晋升了粉丝与主播之间互动吸粉能力。 开源源码模块化开发如前一节提到的,应用 Uni-app 框架进行直播 App 的开发除了反对跨平台公布安装包,另外一大个性就是模块化开发。 置信很多开发者都遇到过给 APP 开发新性能的需要。在模块化开发之前,每次退出新性能都必须在原先的代码中减少和删减。如果从 Github 中其余开发者分享的代码移植到本人的软件我的项目中,还会遇到各种变量、隶属和 Bug 等问题。 然而 Uniapp 的模块化开发齐全能够让 APP 新增性能效率大大晋升。例如想要给本人的直播 APP 退出购物车和红包的性能,就能够参考往期的文章: 在这里,仅仅3段代码就能够实现购物车的性能:uniapp短视频APP持续革新降级:退出购物车与红包性能 10 分钟上手直播 APP DemoUni-app 的开发者应该都晓得,想要将 DCloud 的插件市场中的试用 Demo 移植到本人中央是一件比拟轻松的事件,甚至10分钟就能够实现从“申请试用+打包自定义基座“到 ”HBuilderX 导入我的项目“的配置。具体配置教程能够参考前文:如何在Uni-app中疾速创立属于本人的第一个仿抖音短视频App ...

April 12, 2022 · 1 min · jiezi

关于uniapp:用uniapp写一个内外循环的全选与反选不会的赶紧围观

依据我的项目需要;写的一个内外循环的全选与反选;遇到问题:因为是分页,抉择全选,当上拉加载时;新加载的数据并没有被选中等问题,都被解决;如果有其余些问题;欢送提出。 留神:这只我我的项目中的页面;有些全局援用的例如提醒或是一些组件;应用的时候能够删除;并不影响次要性能;获取数据时;因为后盾传的是认为数组;但理论须要的二维数据;上面获取数据的接口曾经过解决;依据你们返回的数据格式可自行更改;咱们我的项目中有一键换色;牵扯到色彩变量的可删除;写成固定色彩以下是具体代码: Html:<template> <view> <view class="record" :style="colorStyle" v-if="visitList.length"> <view class="nav acea-row row-between-wrapper"> <view class="left">以后共 <text class="num">{{count}}</text> 件商品</view> <view class="font-num" v-if="!isShowChecked" @click="switchTap">治理</view> <view v-else @click="switchTap">勾销</view> </view> <view class="list"> <checkbox-group @change="checkboxChange"> <view class="item" v-for="(item,index) in visitList" :key="index"> <view class="title"> <checkbox v-if="isShowChecked" :value="item.time" :checked="item.checked" /> <text>{{item.time}}</text> </view> <checkbox-group @change="(e)=>{picCheckbox(e,index)}"> <view class="picList acea-row row-middle"> <view class="picTxt" v-for="(j,jindex) in item.picList" :key="jindex" @click.stop="goDetails(j)"> <view class="pictrue"> <image :src="j.image"></image> <checkbox v-if="isShowChecked" :value="(j.id).toString()" :checked="j.checked" class="checkbox" /> </view> <view class="money">¥<text class="num">{{j.product_price}}</text></view> </view> </view> </checkbox-group> </view> </checkbox-group> <view class='loadingicon acea-row row-center-wrapper'> <text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}} </view> </view> <view class="footer acea-row row-between-wrapper" v-if="isShowChecked"> <checkbox-group @change="checkboxAllChange"> <checkbox value="all" :checked="isAllSelect" /> <text class='checkAll'>全选</text> </checkbox-group> <view class="acea-row row-middle"> <view class="bnt acea-row row-center-wrapper" @click="collect">珍藏</view> <view class="bnt on acea-row row-center-wrapper" @click="del">删除</view> </view> </view> </view> <view class='noCommodity' v-else-if="!visitList.length && page == 1"> <view class='pictrue'> <image src='../../../static/images/noCollection.png'></image> </view> <recommend :hostProduct="hostProduct"></recommend> </view> <home v-if="navigation"></home> </view></template>Js:<script> import { getVisitList, getProductHot, deleteVisitList, collectAdd } from '@/api/store.js'; import { mapGetters } from "vuex"; import { toLogin } from '@/libs/login.js'; import recommend from '@/components/recommend'; // #ifdef MP import authorize from '@/components/Authorize'; // #endif import home from '@/components/home'; import colors from '@/mixins/color.js' export default { components: { recommend, // #ifdef MP authorize, // #endif home }, mixins: [colors], data() { return { isShowChecked: 0, count: 0, times: [], isAllSelect: false, hostProduct: [], loadTitle: '加载更多', loading: false, loadend: false, visitList: [], limit: 21, page: 1, isAuto: false, //没有受权的不会主动受权 isShowAuth: false, //是否暗藏受权 hotScroll: false, hotPage: 1, hotLimit: 10, isItemAll: [] }; }, computed: mapGetters(['isLogin']), onLoad() { if (this.isLogin) { this.loadend = false; this.page = 1; this.visitList = []; this.get_user_visit_list(); this.get_host_product(); } else { toLogin(); } }, onShow() { this.times = []; this.loadend = false; this.page = 1; this.visitList = []; this.get_user_visit_list(); }, methods: { goDetails(item){ if(this.isShowChecked) return false; uni.navigateTo({ url: '/pages/goods_details/index?id=' + item.product_id }) }, switchTap(){ this.isShowChecked = !this.isShowChecked; }, collect(){ let ids = []; this.visitList.forEach(item=>{ item.picList.forEach(j=>{ if(j.checked){ ids.push(j.id) } }) }) if(!ids.length){ return this.$util.Tips({ title: '请抉择珍藏商品' }); } collectAdd(ids).then(res=>{ return this.$util.Tips({ title: res.msg }); }) }, del(){ let ids = []; this.visitList.forEach(item=>{ item.picList.forEach(j=>{ if(j.checked){ ids.push(j.id) } }) }) if(!ids.length){ return this.$util.Tips({ title: '请抉择删除商品' }); } deleteVisitList(ids).then(res=>{ this.times = []; this.loadend = false; this.page = 1; this.$set(this, 'visitList', []); this.get_user_visit_list(); return this.$util.Tips({ title: res.msg }); }) }, picCheckbox(event, index) { let that = this, picTime = event.detail.value; that.visitList[index].picList.forEach(j => { if (picTime.indexOf(j.id + '') !== -1) { j.checked = true; } else { j.checked = false; } }) if(that.visitList[index].picList.length == picTime.length){ that.visitList[index].checked = true; }else{ that.visitList[index].checked = false; } let visitObj = []; that.visitList.forEach(item=>{ if(item.checked){ visitObj.push(item.time) }else{ if(visitObj.indexOf(item.time) !== -1){ visitObj.remove(item.time); } } }) if(visitObj.length == that.visitList.length){ that.isAllSelect = true; }else{ that.isAllSelect = false; } }, checkboxChange(event) { let that = this, timeList = event.detail.value; that.isItemAll = timeList; that.visitList.forEach((item, index) => { if (timeList.indexOf(item.time) !== -1) { item.checked = true; } else { item.checked = false; } item.picList.forEach(j => { if (item.checked) { j.checked = true; } else { j.checked = false; } }) }) if (timeList.length === that.visitList.length) { that.isAllSelect = true; } else { that.isAllSelect = false; } }, forGoods(val) { let that = this; if (!that.visitList.length) return that.visitList.forEach((item) => { if (val) { item.checked = true; } else { item.checked = false; } item.picList.forEach(j => { if (val) { j.checked = true; } else { j.checked = false; } }) }) }, checkboxAllChange(event) { let value = event.detail.value; if (value.length) { this.isAllSelect = true; this.forGoods(1) } else { this.isAllSelect = false; this.forGoods(0) } }, // 受权敞开 authColse: function(e) { this.isShowAuth = e }, /** * 获取珍藏产品 */ get_user_visit_list: function() { let that = this; if (this.loading) return; if (this.loadend) return; that.loading = true; that.loadTitle = ""; getVisitList({ page: that.page, limit: that.limit }).then(res => { this.count = res.data.count; for (let i = 0; i < res.data.time.length; i++) { if (this.times.indexOf(res.data.time[i]) == -1) { this.times.push(res.data.time[i]) this.visitList.push({ time: res.data.time[i], picList: [] }) } } for (let x = 0; x < this.times.length; x++) { this.visitList[x].checked = this.isAllSelect ? true : false; for (let j = 0; j < res.data.list.length; j++) { if (this.times[x] === res.data.list[j].time_key) { if (this.isAllSelect) { res.data.list[j].checked = true; } else { res.data.list[j].checked = false; } this.visitList[x].picList.push(res.data.list[j]) } } } let loadend = res.data.list.length < that.limit; that.loadend = loadend; that.loadTitle = loadend ? '没有更多内容啦~' : '加载更多'; that.page = that.page + 1; that.loading = false; }).catch(err => { that.loading = false; that.loadTitle = "加载更多"; }); }, /** * 获取我的举荐 */ get_host_product: function() { let that = this; if (that.hotScroll) return getProductHot( that.hotPage, that.hotLimit, ).then(res => { that.hotPage++ that.hotScroll = res.data.length < that.hotLimit that.hostProduct = that.hostProduct.concat(res.data) }); } }, onReachBottom() { if (this.visitList.length) { this.get_user_visit_list(); } else { this.get_host_product(); } } }</script>Css:<style lang="scss"> page { background-color: #fff; } .record .pictrue /deep/checkbox .uni-checkbox-input { background-color: rgba(0, 0, 0, 0.16); } .record .pictrue /deep/checkbox .wx-checkbox-input { background-color: rgba(0, 0, 0, 0.16); } .record { .footer { box-sizing: border-box; padding: 0 30rpx; width: 100%; height: 96rpx; box-shadow: 0px -4px 20px 0px rgba(0, 0, 0, 0.06); background-color: #fff; position: fixed; bottom: 0; z-index: 30; padding-bottom: constant(safe-area-inset-bottom); ///兼容 IOS<11.2/ padding-bottom: env(safe-area-inset-bottom); ///兼容 IOS>11.2/ .bnt { width: 160rpx; height: 60rpx; border-radius: 30rpx; border: 1rpx solid #ccc; color: #666666; &.on { border: 1rpx solid var(--view-theme); margin-left: 16rpx; color: var(--view-theme); } } } .nav { border-bottom: 1rpx solid #eee; color: #999999; font-size: 28rpx; height: 74rpx; padding: 0 30rpx; .left { color: #333; .num { color: var(--view-theme); margin: 0 10rpx; } } } .list { padding-top: 32rpx; padding-bottom: 96rpx; .item { .title { padding: 0 30rpx; margin-bottom: 34rpx; font-size: 34rpx; font-weight: 600; } .picList { padding: 0 30rpx 0 12rpx; .picTxt { margin-left: 18rpx; margin-bottom: 48rpx; .pictrue { width: 218rpx; height: 218rpx; border-radius: 10rpx; position: relative; image { width: 100%; height: 100%; border-radius: 10rpx; } .checkbox { position: absolute; right: 10rpx; top: 14rpx; } } .money { font-size: 24rpx; color: var(--view-theme); font-weight: 600; margin-top: 15rpx; .num { font-size: 32rpx; margin-left: 6rpx; } } } } } } }</style>最初如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点star:http://github.crmeb.net/u/defu不胜感激 ! ...

April 12, 2022 · 5 min · jiezi

关于uniapp:UNIAPP条件编译ifdef-ifndef-endif

语法释义#ifdef仅实用于某环境下#ifndef仅实用于非某环境下#endif完结1.标识含意标识含意VUE3HBuilderX 3.2.0+APP-PLUSAppAPP-PLUS-NVUE或APP-NVUEApp nvueH5H5MP微信小程序/支付宝小程序/百度小程序/头条小程序/QQ小程序MP-WEIXIN微信小程序MP-ALIPAY支付宝小程序MP-TOUTIAO字节跳动小程序MP-LARK飞书小程序MP-BAIDU、MP-QQ 、MP-KUAISHOU、MP-360 QUICKAPP-WEBVIEW快利用通用2.示例<!-- #ifndef APP-NVUE --><view><text>{{msg}}</text></view><!-- #endif --><!-- #ifdef APP-NVUE --><text><text>{{msg}}</text></text><!-- #endif -->

April 7, 2022 · 1 min · jiezi

关于uniapp:unipush消息推送及遇到的问题

1 . 在app.vue页面onLaunch中增加 onLaunch: function() { var platform = uni.getSystemInfoSync().platform; // #ifdef APP-PLUS plus.screen.lockOrientation("portrait-primary"); //推送 var pinf = plus.push.getClientInfo(); var cid = pinf.clientid; //客户端标识 console.log('cid:' + cid); const _self = this; const _handlePush = function(payload) { var pages = getCurrentPages(); console.log('----------', payload) //页面栈为0,标记app是被push唤醒,在欢送页执行跳转逻辑 if (payload.alive === false) { console.log('设置storage') uni.setStorage({ key:'appLaunchedByPush', data:payload }) } else { //app在线,收到push能够间接跳转 uni.navigateTo({ url: '/pages/index' }); } }; plus.push.addEventListener('click', function(message) { console.log('push click =======', message) if (platform == 'ios') { //离线是payload为object , 在线时本地创立的为string(本地创立告诉只能传string,否则无奈传递payload) if (typeof message.payload == 'string') { console.log('string') var payload = JSON.parse(message.payload); } else { console.log('obj') var payload = message.payload; } _handlePush(payload); return } //这里能够写跳转业务代码 _handlePush(message.payload); }); plus.push.addEventListener('receive', function(message) { console.log('push receive ======', message); if (message.type == "receive"){ // 这里判断触发的起源,否则始终推送。 if (platform == 'ios') { console.log('ios receive', message); if (typeof message.payload == 'string') { plus.push.createMessage( message.content, message.payload, { cover: false, title: message.title, }); } else { plus.push.createMessage( message.content, JSON.stringify(message.payload), { cover: false, title: message.title, }); } } else { console.log('android receive======', message); //执行跳转判断或增加本地告诉 plus.push.createMessage( message.content, JSON.stringify(message.payload), { cover: false, title: message.title }); } } }); }2 . 解决离线音讯跳转在app默认跳转页面增加我这里是登录页面 ...

April 2, 2022 · 2 min · jiezi

关于uniapp:unisimplerouter使用vuerouter管理uniapp路由

笔记中的内容仅实用于HBulider构建的uniapp我的项目,通过其余形式构建的uniapp我的项目请参考uni-simple-router官网 uni-simple-router (hhyang.cn)uniapp用到了vue的很多api,但在路由治理的性能上相较于vue-router还是比拟欠缺的,比方全局导航守卫。 咱们能够通uniapp的插件uni-simple-router来实现相似于vue-router的性能,但多端兼容时,一些用法还须要留神,咱们会讲到。 一、装置如果你的我的项目没有应用package,请先初始化: $ npm init -y装置依赖: $ npm install uni-simple-router uni-read-pagesuni-read-pages的作用是:读取uniapp的pages.json,作为router的配置,把pages.json中的路由配置转换成vue-router配置的模式。二、配置与初始化1、根目录新建 vue.config.js 文件,写入以下内容: //vue.config.jsconst TransformPages = require('uni-read-pages')const {webpack} = new TransformPages()module.exports = { configureWebpack: { plugins: [ new webpack.DefinePlugin({ ROUTES: webpack.DefinePlugin.runtimeValue(() => { const tfPages = new TransformPages({ includes: ['path', 'name', 'aliasPath'] }); return JSON.stringify(tfPages.routes) }, true ) }) ] }}⚠️ 其中要重点关注第 10 行: // ... includes: ['path', 'name', 'aliasPath']// ...includes 中蕴含的是router会读取pages路由中的字段名,后续如果有用到meta等路由信息,能够在 includes 里减少 'meta',在pages路由中写对应的数据,router中就能够获取失去(前面再补充案例) 2、根目录新建并写入router.js,写入以下内容: ...

February 14, 2022 · 2 min · jiezi

关于uniapp:uniuAdmin基于uniappuViewUI跨端后台管理模板uniapp后台实例

一、前言网上很多后盾管理系统都是pc网页端,手机端的后盾零碎绝对比拟少。而跨端的挪动端后盾治理模板少之又少。于是本人就应用uniapp+uview-ui+uni-ui捣鼓了一个跨设施后盾管理系统uniapp-uadmin我的项目。 uni-uAdmin我的项目是一款基于uniapp+vue.js+uView-ui+uni-ui+mock.js等技术开发的跨端后盾管理系统模板我的项目。 二、技术框架编辑器:HbuilderX3.3.5应用技术:vue+uniapp+uViewUI+mockjs弹窗组件:ua-popup(基于uni-app跨端弹框组件)表格组件:ua-table(基于uni-app封装的多功能表格)自定义组件:uaDock全新的dock格调tabbar组件图表组件:u-charts图表库模仿数据:mock.js 全新的毛玻璃视觉UI质感,应用了图表、自定义表格、表单、瀑布流及图文编辑器等业务模块,动静权限治理,谬误页解决,可编译至H5+小程序+APP端 三、我的项目构造目录 四、公共模板页面整体分为顶部自定义导航条+内容区域+底部dock菜单三大部分。 <!-- 公共页面模板 --><template> <view class="ua__pageview flexbox flex-col" :style="{'--SKIN': $store.state.skin, 'background': bgcolor, 'color': color}"> <slot name="header" /> <!-- //主容器 --> <view class="ua__scrollview flex1"> <slot /> </view> <!-- //底部 --> <slot name="footer" /> <!-- //dock菜单 --> <ua-dock v-if="dock && dock != 'false'" @click="handleDockClick" /> <!-- //函数式弹框 -->![ <ua-popup ref="uapopup" />](/img/bVcXG8X) <!-- //换肤弹框模板 --> <ua-popup v-model="isVisibleSkin" position="right"> <Skin /> </ua-popup> </view></template> ...

January 29, 2022 · 3 min · jiezi

关于uniapp:uniapp-webview如何与H5相互通信

uniapp webview如何与H5互相通信 h5封装的代码能够从这里获取git:https://github.com/MyButifull... 进入主题一、uniapp如何接管H5发送的音讯uniapp端:应用@message来监听H5的音讯 H5端:index.htmel 导入 uni.webview.js 最新版地址:https://js.cdn.aliyun.dcloud....这里有一个坑安卓端运行时会加载不了这个JS,所以要加这个js代码拿下来本地再引入 运行时监听uniappjs加载实现,加载实现后可应用 window.uni.postMessage 发送音讯至uniapp底座。 发送内容要写在data里 document.addEventListener('UniAppJSBridgeReady', function(e) { uni.getEnv(function(res) { console.log('以后环境:' + JSON.stringify(res)); }); // 向uniapp底座发送音讯 uni.postMessage({ data: 'H5发送的音讯' }); });二、uniapp发送音讯给H5

January 28, 2022 · 1 min · jiezi

关于uniapp:20220120uniapp和Android-Studio无线真机调试

uniapp和Android Studio无线真机调试查找adb所在目录 uniapp的adb门路是 HBuilderX\plugins\launcher\tools\adbsAndroid Studio的adb门路是 Android\Sdk\platform-tools Android Studio的sdk目录能够通过as的setting查看如果你电脑上同时有HbuilderX和AS的话,能够用其中一个为了方便使用咱们把adb目录设置为环境变量,如何设置这里就不做阐明了,自行百度adb有俩种模式,tcpip和usb,默认是usb,所以咱们真机调试的时候都是须要连贯数据线的,usb模式下无奈应用无线调试,然而tcpip模式下能够无线,也能够有线咱们设置tcpip模式,第一次设置tcpip是须要应用数据线的,插上数据线当前,咱们执行命令 adb tcpip 5555 ,5555是安卓默认的近程调试端口,你也能够更换,呈现如图所示提醒就是胜利这个时候就能够拔掉数据线了,执行 adb connect 192.168.0.129 ,ip是你手机的ip而后在HbuilderX和AS中看到本人的手机了当前调试的时候只须要 adb connect 手机ip即可,你也能够写一个脚本,更加不便的无线连接手机,我这提供一个繁难的脚本 @ECHO offSET /P ip="IP:[default] 192.168.0.129]"IF "%ip%"=="" ( SET ip="192.168.0.129")adb connect %ip%具体成果自行测试即可强迫症如果想换回usb模式的话,能够执行 adb usb 即可

January 20, 2022 · 1 min · jiezi

关于uniapp:uniapp-使用easycom-失效-填坑

看看pages.json文件是否配置了呀

January 6, 2022 · 1 min · jiezi

关于uniapp:20211231uniapp之安卓原生插件开发教程

uniapp之安卓原生插件开发教程筹备hbuilderX,下载app离线SDK,下载Andorid Studio,安卓官网或中文社区证书(能够本人筹备,也能够应用android Studio生成)插件性能简介加法性能,咱们把插件名称起名为leruge-add,办法是add,参数是a和b过程HbuilderX创立一个我的项目在pages/index/index.vue中轻易写一个按钮,而后调用咱们的原生插件leruge-add,代码如下 <template> <view> <button @click="add">加法</button> </view></template><script> export default { methods: { add() { // 引入原生插件 leruge-add let lerugeAdd = uni.requireNativePlugin("leruge-add") // 调用 lerugeAdd.add({ a: 1, b: 2 }, res => { uni.showToast({ title: JSON.stringify(res), icon: 'none' }) }) } } }</script><style></style>申请Appkey,在开发者核心,点击方才创立的appAndroid包名和IOS Bundled都填写成com.android.UniPluginSHA1签名自行百度如何获取吧,这里就不错具体解说了,教程点击保留,生成appkey解压咱们下载好的APP离线SDK,下载地址关上Android Studio,open抉择UniPlugin-Hello-AS我集体习惯project模式,所以切换一下把咱们方才申请的appkey填写到app/src/main/AndroidManifest.xml中,因为开发的是安卓,所以appkey必定也是安卓的把咱们的证书放到app目录下,我的证书名字叫leruge.keystore配置证书,在app/build.gradle的signingConfigs选项中右键UniPlugin-Hello-AS,创立Module填写插件信息配置leruge_add/build.gradle,复制例子uniplugin_module/build.gradle在leruge_add/src/main/java/com/example/leruge/add创立类AddModule实现加法,代码如下 package com.example.leruge.add;import com.alibaba.fastjson.JSONObject;import io.dcloud.feature.uniapp.annotation.UniJSMethod;import io.dcloud.feature.uniapp.bridge.UniJSCallback;import io.dcloud.feature.uniapp.common.UniModule;public class AddModule extends UniModule { @UniJSMethod public void add(JSONObject json, UniJSCallback callback) { int a = json.getIntValue("a"); int b = json.getIntValue("b"); JSONObject res = new JSONObject(); res.put("code", 1); res.put("result", a + b); callback.invoke(res); }}注册插件,在app/src/main/assets/dcloud_uniplugins.json文件中增加,如下到HbuilderX生成本地打包资源把生成的本地打包资源复制到app/src/main/assets/apps目录下配置appid,在app/src/main/assets/data/dcloud_control.xml中配置增加插件project援用,在app/build.gradle中增加组件测试,手机或者虚构设施连贯当前,点击运行进行测试测试胜利当前就生成uniapp插件,点击Android Studio右侧的Gradle,顺次抉择leruge_add/Tasks/other/assembleRelease,双击生成aar包,生成的包在leruge_add/build/outputs/aar目录下创立跟插件雷同名字的文件夹leruge_add,在leruge_add下创立android文件夹和package.json文件aar包放到android文件夹下,package.json最小配置即可,也能够依照理论状况配置 ...

December 31, 2021 · 1 min · jiezi

关于uniapp:uniapp-使用sass-踩坑记

背景:有力吐槽,搞了我好多好多天,始终说版本问题,各种试@vue/cli 创立的支付宝小程序我的项目,无奈应用sass ,应用lang=‘scss’ 报错,尝试过好几个版本都不好使上面是我应用的版本,大家避避坑,如果你们能够 那当我没说 "node-sass": "^4.14.1", "sass-loader": "^7.3.1","node-sass": "^4.14.1", "sass-loader": "^7.1.0", ...还有几个遗记了 (每次都是给整个node_module删除重新安装的)上面进入正题 : 我本人的 node版本: v12.16.0首先给本人的包卸载掉npm uninstall node-sass sass-loader- 装置sass ,留神这里是sass 不是node-sassnpm install sass npm install sass-loader@8.0.2不输出命令,就间接在packagejson文件增加这两个,本人执行npm install也能够 操作完这些,发现我还报错,很怄气,刚好电脑很卡 我就重启一下,emm 这货竟然好了,泪目。。。

December 30, 2021 · 1 min · jiezi

关于uniapp:uniapp-配置eslint-prettier

背景: 应用的是vue/cli创立的支付宝小程序我的项目话不多说上菜 装置eslint ,因为我的项目中应用的是cli搭建的,所以间接应用 vue add @vue/eslint vue add @vue/eslint而后依据本人爱好抉择格调,这里我抉择的是prettier配置.eslintrc.js 在我的项目根目录新建文件.eslintrc.js,依据本人需要配置规定module.exports = { root: true, env: { node: true, }, globals: { uni: "readonly", my:"readonly" }, extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"], parserOptions: { parser: "babel-eslint", }, rules: { "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", "no-sequences": 0, "import/named": 0, "no-useless-concat": 0, "no-unreachable": 0, "no-case-declarations": 0, "no-continue": 0, "no-redeclare": 0, "block-scoped-var": 0, "operator-assignment": 0, "no-multi-assign": 0, "comma-dangle": 0, "prefer-const": 0, "semi": 0, "eol-last": 0, "linebreak-style": 0, "no-unused-vars": 0, "no-useless-computed-key": 0, "default-case": 0, "prefer-destructuring": 0, "arrow-parens": 0, 'no-var': 2, // 要求应用 let 或 const 而不是 var "comma-spacing": 0, "no-mixed-operators": 0, "radix": 0, "prefer-promise-reject-errors": 0, "arrow-body-style": 0, "prefer-rest-params": 0, "no-restricted-syntax": 0, "vars-on-top": 0, "import/no-named-as-default": 0, "import/extensions": 0, "import/no-named-as-default-member": 0, "guard-for-in": 0, "no-unused-expressions": 0, "import/prefer-default-export": 0, "no-shadow": 0, "no-nested-ternary": 0, "no-empty": 0, "eqeqeq": 0, "camelcase": 0, "prefer-template": 0, "dot-notation": 0, "prefer-arrow-callback": 0, "no-plusplus": 0, "no-else-return": 0, "one-var-declaration-per-line": 0, "consistent-return": 0, "no-param-reassign": 0, "max-len": 0, "no-lonely-if": 0, "array-callback-return": 0, "prefer-object-spread": 0, "import/order": 0, "import/newline-after-import": 0, "func-names": 0, "no-console": 0, "no-underscore-dangle": 0, "no-useless-escape": 0 },};配置eslint不必查看的文件 .eslintignore根目录 新建文件.eslintignore ,依据理论需要配置/utils/subpackage/utils/node_modules/postcss.config.js/babel.config.js最初配置.prettierrc.js 根目录新建.prettierrc.js文件,依据理论需要配置//配置 prettier 。prettierrc.jsmodule.exports = { // 单行最大长度 printWidth: 100, // 设置编辑器每一个程度缩进的空格数 tabWidth: 2, // 在句尾增加分号 semi: true, // 应用单引号 singleQuote: true, jsxSingleQuote: true, // 在任何可能的多行中输出尾逗号。 trailingComma: 'all', // 在对象字面量申明所应用的的花括号后({)和前(})输入空格 bracketSpacing: true, // 在多行JSX元素最初一行的开端增加 > 而使 > 独自一行(不适用于自闭和元素) jsxBracketSameLinte: false, // 为单行箭头函数的参数增加圆括号。 alwaysParens: 'always', // 行完结 endOfLine:"auto", vueIndentScriptAndStyle: true, //是否缩进Vue 文件中的代码<script>和<style>标签 htmlWhitespaceSensitivity:'ignore',//HTML 空白敏感度};最初一步在package.json文件中批改一下lint的命令,批改为 ...

December 30, 2021 · 2 min · jiezi

关于uniapp:uniapp-swiper

swiper 切换知识点:获取页面/组件高度// 重点let info = uni.createSelectorQuery().select(".swiper-item");info.boundingClientRect(function(data) { //data - 各种参数 _this.sceneH = data.height // 获取元素宽度 console.log(data.height,'bbbbbbbbbbb')}).exec()swiper轮播 监听高度 // swiper切换此函数被监听swiperChange(e) { let _this = this this.selectStatus = e.detail.current; if (e.detail.current == 0) { // 重点 let info = uni.createSelectorQuery().select(".swiper-item"); info.boundingClientRect(function(data) { //data - 各种参数 _this.sceneH = data.height // 获取元素宽度 console.log(data.height,'bbbbbbbbbbb') }).exec() } if (e.detail.current == 1) { let info = uni.createSelectorQuery().select(".swiper-item2"); console.log(info) info.boundingClientRect(function(data) { //data - 各种参数 console.log(data) _this.sceneH = data.height // 获取元素宽度 console.log(data.height,'aaaaaaaaaaaaaaaaaaaaaa') }).exec() } }, 页面 全副写法<template> <view class="collectWrapper"> <view class="tabbar"> <view :class="selectStatus == 0 ? 'selectStatus' : '' " @tap="changeTabs(0)">tabs1</view> <view :class="selectStatus == 1 ? 'selectStatus' : '' " @tap="changeTabs(1)">tabs2</view> <view :class="selectStatus == 2 ? 'selectStatus' : '' " @tap="changeTabs(2)">tabs2</view> </view> <view class="uni-padding-wrap"> <view class="page-section swiper"> <view class="page-section-spacing"> <swiper class="swiper" :duration="duration" @change="swiperChange" :current="currentVal"> <swiper-item><view class="swiper-item">内容区域一</view></swiper-item> <swiper-item><view class="swiper-item">内容区域二</view></swiper-item> <swiper-item><view class="swiper-item">内容区域三</view></swiper-item> </swiper> </view> </view> </view> </view></template><script>export default { data() { return { background: ['color1', 'color2', 'color3'], duration: 500, // 管制swiper的显示 currentVal: 0, // 顶部tabs显示状态 selectStatus: 0, } }, methods: { // 点击顶部tabs触发该函数 changeTabs(i) { this.currentVal = i; this.selectStatus = i; }, // swiper切换此函数被监听 swiperChange(e) { this.selectStatus = e.detail.current; }, }}</script><style lang="scss">page { width: 100%; height: 100%;}.selectStatus { color: rgba(19, 149, 244, 1); border-bottom: 4rpx solid rgba(19, 149, 244, 1);}.collectWrapper { // 确保swiper 内容填满设施,若需自适应只需勾销掉100%即可 width: 100%; height: 100%; .tabbar { width: 100%; height: 70rpx; } .uni-padding-wrap { height: 100%; .page-section-spacing { height: 100%; } .swiper { height: 100%; } }}</style>

December 15, 2021 · 2 min · jiezi

关于uniapp:uniapp-瀑布流

<template> <view class="Index"> <!-- 瀑布流布局列表 --> <view class="pubuBox"> <view class="pubuItem"> <view class="item-masonry" v-for="(item, index) in comList" :key="index"> <image :src="item.img" mode="widthFix"></image> <view class="listtitle"> <!-- 这是没有高度的父盒子(下半局部) --> <view class="listtitle1">{{ item.name }}</view> <view class="listtitle2"> <text class="listtitle2son">¥</text> {{ item.commdityPrice }} </view> <view class="listtitle3"> 来自莫成尘的旗舰店 </view> </view> </view> </view> </view> </view></template><script> export default { data() { return { comList: [{ img: "http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg", name: '商品的名称,能够很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长', commdityPrice: 100 }, { img: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg', name: '商品名称会在超出两行时候主动折叠', commdityPrice: 100 }, { img: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg', name: '只有一行题目时高度为39', commdityPrice: 100 }, { img: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg', name: '具体款式您能够自定义', commdityPrice: 100 }, { img: 'http://pic1.sc.chinaz.com/Files/pic/pic9/202002/zzpic23346_s.jpg', name: 'vue的H5页面也是如此应用', commdityPrice: 100 } ], //商品列表 }; }, onShow() {}, onLoad() {}, methods: {}, };</script><style scoped="scoped" lang="scss"> //瀑布流 page { background-color: #eee; height: 100%; } .pubuBox { padding: 22rpx; } .pubuItem { column-count: 2; column-gap: 20rpx; } .item-masonry { box-sizing: border-box; border-radius: 15rpx; overflow: hidden; background-color: #fff; break-inside: avoid; /*防止在元素外部插入分页符*/ box-sizing: border-box; margin-bottom: 20rpx; box-shadow: 0px 0px 28rpx 1rpx rgba(78, 101, 153, 0.14); } .item-masonry image { width: 100%; } .listtitle { padding-left: 22rpx; font-size: 24rpx; padding-bottom: 22rpx; .listtitle1 { line-height: 39rpx; text-overflow: -o-ellipsis-lastline; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; min-height: 39rpx; max-height: 78rpx; } .listtitle2 { color: #ff0000; font-size: 32rpx; line-height: 32rpx; font-weight: bold; padding-top: 22rpx; .listtitle2son { font-size: 32rpx; } } .listtitle3 { font-size: 28rpx; color: #909399; line-height: 32rpx; padding-top: 22rpx; } } .Index { width: 100%; height: 100%; }</style>

November 22, 2021 · 2 min · jiezi

关于uniapp:uniapp-学习笔记

注意事项背景图片不反对本地图片 反对网络门路/base64格局字体同上 也不反对本地字体rpa计算形式设计稿 1px / 设计稿基准宽度 = 框架款式 1rpx / 750rpx若设计稿宽度为 750px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 外面的宽度应该设为:750 * 100 / 750,后果为:100rpx。若设计稿宽度为 640px,元素 A 在设计稿上的宽度为 100px,那么元素 A 在 uni-app 外面的宽度应该设为:750 * 100 / 640,后果为:117rpx。若设计稿宽度为 375px,元素 B 在设计稿上的宽度为 200px,那么元素 B 在 uni-app 外面的宽度应该设为:750 * 200 / 375,后果为:400rpx。 疾速判断运行环境uEnvDev、uEnvProd 能够疾速生成对应 development、production 的运行环境断定代码。// uEnvDevif (process.env.NODE_ENV === 'development') { // TODO}// uEnvProdif (process.env.NODE_ENV === 'production') { // TODO}

November 9, 2021 · 1 min · jiezi

关于uniapp:uniapp-实现pagesjson的模块加载

对于一个日渐宏大的下uni-app我的项目,pages.json文件会变得有大有难以保护,所有就思考怎么样将pages.json文件才分易保护的小文件。起初在浏览他的源码时发现了这个 const pagesJsonJsFileName = 'pages.js'function processPagesJson (pagesJson, loader = { addDependency: function () {}}) { const pagesJsonJsPath = path.resolve(process.env.UNI_INPUT_DIR, pagesJsonJsFileName) if (fs.existsSync(pagesJsonJsPath)) { delete require.cache[pagesJsonJsPath] const pagesJsonJsFn = require(pagesJsonJsPath) if (typeof pagesJsonJsFn === 'function') { pagesJson = pagesJsonJsFn(pagesJson, loader) if (!pagesJson) { console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireReturnJsonObject')}`) } } else { console.error(`${pagesJsonJsFileName} ${uniI18n.__('cliShared.requireExportFunction')}`) } } // 将 subpackages 转换成 subPackages if (pagesJson.subpackages && !pagesJson.subPackages) { pagesJson.subPackages = pagesJson.subpackages delete pagesJson.subpackages } let uniNVueEntryPagePath if (pagesJson.pages && pagesJson.pages.length) { // 如果首页是 nvue if (isNVuePage(pagesJson.pages[0])) { uniNVueEntryPagePath = pagesJson.pages[0].path } } // pages filterPages(pagesJson.pages) // subPackages if (Array.isArray(pagesJson.subPackages) && pagesJson.subPackages.length) { pagesJson.subPackages.forEach(subPackage => { filterPages(subPackage.pages, subPackage.root) }) } if (uniNVuePages.length) { // 间接挂在 pagesJson 上 pagesJson.nvue = { pages: uniNVuePages.reverse() } if (uniNVueEntryPagePath) { pagesJson.nvue.entryPagePath = uniNVueEntryPagePath } } return pagesJson}于是就有上面这个工具仓库地址uni-module-pages ...

October 11, 2021 · 1 min · jiezi

关于uniapp:unittLive基于uniappuViewUI短视频聊天直播实例

一、我的项目概述uniapp-ttlive 一款基于uni-app+uview-ui+vue.js+uapopup等技术混合开发的多端仿造抖音短视频/直播/聊天我的项目。反对全屏沉迷式、高低滑动切换视频等性能。 二、预览成果如下图:在h5、小程序、APP端编译成果 三、编码技术编码器/技术:HbuilderX3.1.21+Uniapp+Nvue+Vuex+UapopupUI组件库:uView-ui / uni-ui矢量图标库:iconfont字体图标弹窗组件:UApopup 基于uni-app封装跨端弹窗组件自定义导航条+底部菜单栏编译反对:H5+小程序+APP端 四、性能个性✅ 反对全屏沉迷式通明模式✅ 顺滑的高低滑动体验✅ 迷你工夫进度条✅ 自定义组件反对Nvue页面 五、目录构造/编译 我的项目中应用的组件库是uview-ui,多平台疾速开发UI框架。 main.js配置import Vue from 'vue'import App from './App'import uView from 'uview-ui'Vue.use(uView)import API from '@/common/request'Vue.prototype.$api = API// 引入状态治理import Store from './store'Vue.prototype.$store = StoreVue.config.productionTip = falseApp.mpType = 'app'// #ifdef APP-PLUSplus.navigator.closeSplashscreen()// #endifconst app = new Vue({ ...App})app.$mount()思考到Nvue页面不反对prototype原型全局挂载,改为应用globalData来管制。 /** * 主入口配置 * @author xiaoyan */<script> export default { globalData: { // 全局设置状态栏和导航栏高度 statusBarH: 0, customBarH: 0, }, onLaunch: function() { uni.getSystemInfo({ success: (e) => { // 获取手机状态栏高度 let statusBar = e.statusBarHeight let customBar // #ifndef MP customBar = statusBar + (e.platform == 'android' ? 50 : 45) // #endif // #ifdef MP-WEIXIN // 获取胶囊按钮的布局地位信息 let menu = wx.getMenuButtonBoundingClientRect() // 导航栏高度 = 胶囊下间隔 + 胶囊上间隔 - 状态栏高度 customBar = menu.bottom + menu.top - statusBar // #endif // #ifdef MP-ALIPAY customBar = statusBar + e.titleBarHeight // #endif // 兼容nvue写法(H5/小程序/APP/APP-Nvue) this.globalData.statusBarH = statusBar this.globalData.customBarH = customBar } }) }, onShow: function() { console.log('App Show') }, onHide: function() { console.log('App Hide') } }</script>uniapp自定义navbar+tabbar组件大家看到的顶部导航条及底部菜单栏,是全新开发的反对nvue组件。 ...

September 20, 2021 · 4 min · jiezi

关于uniapp:crmeb-小程序包大小超过2M的解决方法

crmeb 小程序包大小超过2M的解决办法微信限度了小程序的代码包不能超过2MB,这次要是出于对小程序启动速度的思考。然而,2MB 的大小也限度了小程序性能的扩大,如果大小超出了2MB该如何解决呢? 优化代码,删除掉不必的代码图片压缩或者上传服务器个别图片所占用的空间比拟大,尽量不要放在小程序本地文件夹中,如果图片不多的话能够对图片进行压缩,图片压缩平台:https://tinyjpg.com/另外, 通过cli命令创立的uni app我的项目,可将图片或字体图标放入assets文件夹下,通过require引入, 也可缩小主包大。分包加载:什么是分包加载: 小程序个别都是由某几个性能组成,通常这几个性能之间是独立的,但会依赖一些公共的逻辑,且这些性能个别会对应某几个独立的页面。那么小程序代码的打包,能够依照性能的划分,拆分成几个分包,当须要用到某个性能时,才加载这个性能对应的分包。 对于用户来说,小程序加载流程变成了: 1.首次启动时,先下载小程序主包,显示主包内的页面; 2.当进入某个分包的页面,再下载这个对应分包,下载结束后,显示分包的页面。 采纳分包加载,对开发者而言,能使小程序有更大的代码体积,承载更多的性能与服务;而对用户而言,能够更快地关上小程序,同时在不影响启动速度前提下应用更多功能。 分包的划分: 在配置前,依照性能对各个分包的内容进行划分,将同一个性能下的页面和逻辑放在童改一个目录下,把一些跨性能的公共逻辑放在主包下。 在分包划分时需注意: 1.包与包之间性能尽可能独立,防止分包与分包之间援用上的耦合。因为分包的加载是由用户操作触发的,并不能确保某分包加载时,另外一个分包就肯定存在,这个时候可能会导致 JS 逻辑异样的状况,例如报「"xxx.js" is not defined」这样的谬误; 2.一些公共的自定义组件,要放在主包内。 分包的配置: 在uni app中通过cli初始化的小程序目录构造如下: ├── src ├── main.js ├── App.vue ├── pages.json ├── manifest.json ├── orderPackages │ └── pages │ ├── goodsDetail │ └── myorder ├── pages │ ├── index │ └── user └── utils 需在pages.json中配置subPackages字段,在subPackage外面申明我的项目的分包构造: crmeb 小程序包大小超过2M的解决办法目前小程序分包大小的限度: 整个小程序所有分包大小不超过 4M 单个分包/主包大小不能超过 2M 以上只列举了uni app框架分包加载的步骤, 原生小程序分包办法依据官网文档即可疾速实现,小程序框架虽多, 大都大同小异,如果后续有应用其余框架进行开发,会进行补充。 如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点star:http://github.crmeb.net/u/defu 不胜感激 ! ...

August 9, 2021 · 1 min · jiezi

关于uniapp:uniapp踩坑记录uview的collapse组件面板打开时获取数据不显示内容以及显示慢的问题

环境HBuilder X 3.1.18uview-ui 1.8.4 问题形容应用uview-ui的collapse组件,当某个面板关上时,获取数据并更新内容 <template> <view> <u-collapse> <u-collapse-item title="title" v-for="(item, index) in list" @change="handleOpenChange(item, index)" > {{item.content}} </u-collapse-item> </u-collapse> </view></template><script> export default { data() { return { list: [{ content: '' }, { content: '' }] }; }, methods: { handleOpenChange(item, index) { this.list[index].content = '我是内容'; } } }</script>以上代码,当组件面板关上时,内容并不显示,调试发现DOM中已有内容,但高度为0 解决查看文档尝试调用init办法,内容胜利显示,但有重大的性能问题,当item较多时,十分卡顿,查看源码发现init办法会循环解决所有的子元素查看u-collapse-item.vue源码组件外部有queryRect办法用于更新内容高度故批改代码如下首先给u-collapse-item增加ref属性 <u-collapse-item title="title" v-for="(item, index) in list" ref="collapseItem" @change="handleOpenChange(item, index)">再批改事件处理办法,调用以后item的queryRect办法,问题解决 handleOpenChange(item, index) { this.list[index].content = '我是内容'; // 实测如果用$nextTick,在android端依然有概率获取不到高度,故改用setTimeout setTimeout(() => { this.$refs.collapseItem[index].queryRect(); }, 100);}

July 7, 2021 · 1 min · jiezi

关于uniapp:关于uniapp基于uView框架开发的一些js文件配置

装置npm依赖npm install uview-ui 开发环境请将 http.interceptor.js 文件中的 baseUrl: appconfig.serverUrl, 加上条件编译,如下// #ifndef H5 baseUrl: appconfig.serverUrl,// #endif开发环境跨域配置vue.config.js 正式环境能够将 http.interceptor.js 文件中的 baseUrl: appconfig.serverUrl 条件编译去掉 变成如下模式baseUrl: appconfig.serverUrl,后续更换域名同样批改 vue.config.js 和 config.js 中的域名main.jsimport Vue from 'vue'import App from './App'import store from './store'import * as utils from '@/common/utils.js'import uView from "uview-ui";Vue.use(uView);import cuCustom from 'colorui/components/cu-custom.vue'Vue.component('cu-custom',cuCustom)Vue.config.productionTip = falseVue.prototype.$store = storeVue.prototype.$utils = utilsApp.mpType = 'app'const app = new Vue({ ...App})// http拦截器,此为须要退出的内容,如果不是写在common目录,请自行批改引入门路import httpInterceptor from '@/common/http.interceptor.js'// 这里须要写在最初,是为了等Vue创建对象实现,引入"app"对象(也即页面的"this"实例)Vue.use(httpInterceptor, app)// http接口API集中管理引入局部import httpApi from '@/common/http.api.js'Vue.use(httpApi, app)app.$mount()config.js//配置文件放这里吧export default { apiurl:'', serverUrl:"",//服务器接口api地址,本地跨域配置临时用空 imageUrl:"",//服务图片加载地址 imgupload:"",//图片上传地址 appid:""//公众号appid }http.api.jsimport appconfig from './config.js'// 如果没有通过拦截器配置域名的话,能够在这里写上残缺的URL(加上域名局部)let loginUrl="" //登录// 此处第二个参数vm,就是咱们在页面应用的this,你能够通过vm获取vuex等操作,更多内容详见uView对拦截器的介绍局部:// https://uviewui.com/js/http.html#%E4%BD%95%E8%B0%93%E8%AF%B7%E6%B1%82%E6%8B%A6%E6%88%AA%EF%BC%9Fconst install = (Vue, vm) => { // 应用传入的params参数 let login = (params = {}) => vm.$u.post(loginUrl, { username:params.username, password:params.password }); // 将各个定义的接口名称,对立放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下 vm.$u.api = {login};}export default { install}http.interceptor.js//引入配置文件import appconfig from './config.js'// 这里的vm,就是咱们在vue文件外面的this,所以咱们能在这里获取vuex的变量,比方寄存在外面的token变量const install = (Vue, vm) => { // 此为自定义配置参数,具体参数见上方阐明 Vue.prototype.$u.http.setConfig({ baseUrl: appconfig.serverUrl, loadingText: '致力加载中~', loadingTime: 800, // 在此工夫内,申请还没回来的话,就显示加载中动画,单位ms originalData: false, // 是否在拦截器中返回服务端的原始数据 false时服务器状态码不为200,会modal弹框提醒 loadingMask: true, // 展现loading的时候,是否给一个通明的蒙层,避免触摸穿透 showLoading: true, // 是否显示申请中的loading // 设置为json,返回后会对数据进行一次JSON.parse() dataType: 'json', // 配置申请头信息 header: { 'content-type': 'application/json', } }); // 申请拦挡,配置Token等参数 Vue.prototype.$u.http.interceptor.request = (config) => { // 援用token console.log("申请拦挡:",config); // 形式一,寄存在vuex的token,假如应用了uView封装的vuex形式 // 见:https://uviewui.com/components/globalVariable.html // config.header.token = vm.token; // 形式二,如果没有应用uView封装的vuex办法,那么须要应用$store.state获取 // config.header.token = vm.$store.state.token; // 形式三,如果token放在了globalData,通过getApp().globalData获取 // config.header.token = getApp().globalData.username; // 形式四,如果token放在了Storage本地存储中,拦挡是每次申请都执行的 // 所以哪怕您从新登录批改了Storage,下一次的申请将会是最新值 const token = uni.getStorageSync('token'); config.header.token = token; // 能够对某个url进行特地解决,此url参数为this.$u.get(url)中的url值 // if(config.url == '/user/login') config.header.noToken = true; // 最初须要将config进行return return config; // 如果return一个false值,则会勾销本次申请 // if(config.url == '/user/rest') return false; // 勾销某次申请 } // 响应拦挡,判断状态码是否通过 Vue.prototype.$u.http.interceptor.response = (res) => { // console.log("响应拦挡:", res); //临时就间接诶返回吧 return res; // if(res.code == 200) { // // res为服务端返回值,可能有code,result等字段 // // 这里对res.result进行返回,将会在this.$u.post(url).then(res => {})的then回调中的res的到 // // 如果配置了originalData为true,请注意这里的返回值 // return res.result; // } else if(res.code == 201) { // // 假如201为token生效,这里跳转登录 // vm.$u.toast('验证失败,请从新登录'); // setTimeout(() => { // // 此为uView的办法,详见路由相干文档 // vm.$u.route('/pages/user/login') // }, 1500) // return false; // } else { // // 如果返回false,则会调用Promise的reject回调, // // 并将进入this.$u.post(url).then().catch(res=>{})的catch回调中,res为服务端的返回值 // return false; // } }}export default { install}

June 29, 2021 · 2 min · jiezi

关于uniapp:uniapp封装公共请求typescript版

第一步:新建文件夹services 第二步:新建文件request.ts //服务器接口地址 const baseURL:string='http://xxxxxx' //本地调试接口地址// const baseURL:string='http://xxxxxx'// 封装公共申请办法function request(url:string, method: "GET" | "POST" | undefined,data: object | any){ return new Promise(function(resolve, reject){ let header:any if(uni.getStorageSync('token') !== undefined && uni.getStorageSync('token') !== ""){ header = { 'content-type': 'application/json', 'X-Auth-Token': uni.getStorageSync('token') }; }else { header = { 'content-type': 'application/json', }; } uni.request({ url: baseURL + url, method: method, data: data, header: header, success(res:any) { console.log(res) uni.hideLoading() if (res.data.code === "200" || res.data.ok) { resolve(res.data); } else { //其余异样 uni.showToast({ title:res.data.msg, icon:'none' }) reject(res.data); } }, fail(err) { uni.hideLoading() //申请失败 uni.showToast({ title:'无奈连贯到服务器', icon:'none' }) reject(err) } }) }) }export {request,baseURL}第三步:新建同级文件api.ts ...

June 2, 2021 · 1 min · jiezi

关于uniapp:uniapp返回上一级页面前先判断是否需要弹出提示弹出提示后用户点击确定返回上一级页面点击取消就阻止返回

一、h5、app用同一个办法,小程序要用另外的(因为小程序用onBackPress监听不了)。二、h5、app(此办法写在methods里): onBackPress(options) { //h5、app拦挡返回 if (this.show) {//this.show为true才弹出提醒 uni.showModal({ title: '提醒', content: '答案未保留,确定退出吗', success: function(res) { if (res.confirm) { uni.reLaunch({ url: "/pages/index/index"//返回上一级页面 }) } else if (res.cancel) {} } }); return true } },三、小程序(computed跟methods同级,此办法写在methods下面): computed:{ hasReplyC(){//小程序拦挡返回 // #ifdef MP-WEIXIN if(!this.show){ wx.disableAlertBeforeUnload()//this.show为false则不须要弹出 }else{ wx.enableAlertBeforeUnload({//提醒 message: "答案未保留,确定退出吗", success: function(res) { }, fail: function(errMsg) { }, }) } // #endif } },

May 14, 2021 · 1 min · jiezi

关于uniapp:uniApp-tabbar-可自定义也可原生

最近在学习uniApp,对于tabbar的学习,记录一下。 uniApp原生的 tabbar 设置 在 pages.json 文件中,留神 static 文件下图片门路 "tabBar": { "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [{ "pagePath": "pages/index/index", "iconPath": "static/images/tabbar2/basics.png", "selectedIconPath": "static/images/tabbar2/basics_cur.png", "text": "首页" },{ "pagePath": "pages/fangke/fangke", "iconPath": "static/images/tabbar2/plugin.png", "selectedIconPath": "static/images/tabbar2/plugin_cur.png", "text": "访客" }, { "pagePath": "pages/my/my", "iconPath": "static/images/tabbar2/about.png", "selectedIconPath": "static/images/tabbar2/about_cur.png", "text": "我的" }] }自定义的tabbar,用的colorUI的tabbar组件下载源码解压,复制根目录的 /colorui 文件夹到你的根目录传送门 colorUI-uniAPP传送门 colorUI原理是一个主页面引入多个页面,在主页面进行切换显示。这样能够解决切换时闪动的问题。main.js全局引入componentsimport basics from './pages/basics/home.vue'Vue.component('basics',basics)import components from './pages/component/home.vue'Vue.component('components',components)import plugin from './pages/plugin/home.vue'Vue.component('plugin',plugin)在主页面index.vue文件中, <basics v-if="PageCur=='basics'"></basics><components v-if="PageCur=='component'"></components><plugin v-if="PageCur=='plugin'"></plugin><view class="cu-bar tabbar bg-white shadow foot"> <view class="action" @click="NavChange" data-cur="basics"> <view class='cuIcon-cu-image'> <image :src="'/static/tabbar/basics' + [PageCur=='basics'?'_cur':''] + '.png'"></image> </view> <view :class="PageCur=='basics'?'text-green':'text-gray'">元素</view> </view> <view class="action" @click="NavChange" data-cur="component"> <view class='cuIcon-cu-image'> <image :src="'/static/tabbar/component' + [PageCur == 'component'?'_cur':''] + '.png'"></image> </view> <view :class="PageCur=='component'?'text-green':'text-gray'">组件</view> </view> <view class="action" @click="NavChange" data-cur="plugin"> <view class='cuIcon-cu-image'> <image :src="'/static/tabbar/plugin' + [PageCur == 'plugin'?'_cur':''] + '.png'"></image> </view> <view :class="PageCur=='plugin'?'text-green':'text-gray'">扩大</view> </view></view>在APP.vue记得引入colorUI的css ...

May 8, 2021 · 1 min · jiezi