- 写一个能自定义尺寸、样式的switch
小程序原生的switch不能灵活的修改宽高、样式,很不方便,我这边参考WeUI的开关,写了一个可以自定义尺寸样式的switch组件。 直接上代码:https://gitee.com/piscdong/wechat-switch 效果如下图,可以自定义宽高,可以做成方角的 [图片] 代码分析 这个switch主要的难点就是点击后背景颜色变换的动画,这里用到了css的transition、transform两个属性来实现动画,以及::before和::after两个伪元素。 wxml基本结构为: [代码]<view class="switch"> <view></view> </view> [代码] 父级view是整个switch容器,会用到::before做背景色切换动画,::after做禁用时的灰色遮罩。内部的一个view是来回切换的白点。未选中时默认class是switch,选中时增加一个class:switch_checked。 选中状态到未选中状态背景有一个从中间变大到全部的白色动画,所以需要给父级view设置一个颜色作为背景色。 [代码].switch { ... background: #00c000; position: relative; } [代码] 未选中时::before覆盖整个容器,选中时::before设置[代码]transform: scale(0);[代码],这样选中时白色区域就会缩放到最小,再加上transition实现动画效果。 [代码].switch::before { display: block; content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: 9999rpx; background: #fff; transition: all 0.35s cubic-bezier(0.45, 1, 0.4, 1); } .switch_checked::before { transform: scale(0); } [代码] 来回移动的白点,未选中时通过[代码]left: 0;[代码]定位到左侧,选中时将left设置为100%定位到右侧,但是这样白点会完全移出容器范围,所以还需要加上[代码]transform: translateX(-100%);[代码]将白点向左再一定自身宽度的100%,同样加上transition实现动画效果。 [代码].switch view { position: absolute; top: 0; left: 0; width: 60rpx; height: 60rpx; border-radius: 50%; background: #fff; box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.4); transition: all 0.35s cubic-bezier(0.45, 1, 0.4, 1); } .switch_checked view { left: 100%; transform: translateX(-100%); } [代码] 关于“::” 最后搭车说一下“:”和“::”,“:”是伪类,“::”是伪元素。按照我的理解:伪类不会在dom中增加节点,只不过是css选择器的一种特殊效果;伪元素会增加节点,flex布局中会影响到其他元素。 为了保证兼容性,css3是允许伪元素使用单个冒号。
2019-12-24 - 小程序开发新能力解读
这个月小程序释放了什么新能力?又有哪些新规则?收藏课程,及时了解小程序开发动态,听官方为你解读新能力。
2023-01-17 - 总结
[视频] 你好,我是李艺。 上节课我们主要学习了如何通过接口获取小程序的性能数据,感谢你一直坚持学习到了现在。下面我们以第1讲讲过的小程序启动流程为主线,一起梳理一下在这个流程之上都有哪些具体的性能优化技巧。下面我们分别从环境准备,代码注入,及首屏渲染三个部分查看冷启动流程里面具体涉及到了哪些优化节点。 首先看环境准备。在这个里边一共有四个节点,在第二个节点里边代码包下载,校验及初始化。下面一共涉及到三讲的优化。第4讲使用独立分包和分包预下载。第5.1讲,减少分包大小,在分包页面里边使用占位组件。第5.3讲,减少主包大小,JS分布异步化加载与执行及插件代码的分包异步化。 下面我们看第二部分。这个部分一共分为主要的两个节点,在第一个节点框架及第三方基础代码初始化这个节点下面,在插件自定义组件扩展库代码注入的时候有第4讲与它相关,使用独立分包和分包预下载,尽量减少全局组件,全局插件的使用。第二点,开发者代码注入,在这里面分为逻辑层开发者代码注入和视图层开发者代码注入,其中在逻辑层开发者代码注入的时候涉及到第6.5讲,延迟同步调用和加快启动流程。在视图层开发者代码注入的时候涉及到第3讲加快注入速度,代码按需注入与初始渲染缓存,这里包括静态缓存与动态缓存两种。 下面我们继续看首屏渲染,下面分为五个节点。 第一个节点逻辑层页面初始化,也就是initDataSendTime这个事件触发的时候,同时有Page.onLoad事件派发,在这个下面一共分为八个方面的优化技巧。第一个是5.4讲使用WXWebAssembly优化运算性能,第6.1讲使用异步转同步的编程范式,第6.3讲在worker中进行耗时运算,第6.4讲在后端使用Go语言异步执行逻辑运算代码,第6.5讲延迟同步操作,使用串发复合命令延迟同步调用。首屏只加载单页所需的数据,第6.6讲小程序转至后台状态,不再调用setData更新视图。第8.4讲脚本优化技巧,及时清除定时器,添加的全局监听要及时移除。小心使用全局对象,第8.5讲setData调用优化合并多次调用。减少data中数据的定义,使用index局部更新长列表数据。 下面看第二个节点视图层,这里涉及到viewLayerRenderStartTime这个节点事件。其中包括Page.onShow事件的派发,下面一共涉及到五点内容。第2.4讲优化视图页动画效果,第2.5讲重渲染与自定义组件优化,第8.1讲视图代码优化技巧在动态列表中使用wx:key属性,使用catch代替bind,使用防抖函数与节流函数,尽量减少wxml节点,降低页面重渲染的压力。第8.2讲wxss优化技巧。给滚动列表开启惯性滚动,使用hover-class实现按钮的单击态,清除无用的wxss样式代码。第8.3讲UI优化技巧,使用padding及伪元素扩展元素的可单击区域。 下面看第三点开发者代码,从后端拉取数据准备data这方面的一些优化技巧,这里一共涉及到四点。第6.2讲尽量提前开始数据拉取,使用并发复合命令对齐不同文件的代码执行点。第6.7讲优化数据拉取,使用数据预拉取与周期性更新创建云函数提供数据,使用并发复合命令的竞赛模式拉取数据。第6.8讲 优化后端接口,开启缓存,使用Http2与Quic协议。第8.6讲网络请求优化,使用缓存将网络请求按优先级排序。 下面看第四个节点页面渲染,在下面一共涉及到六讲相关的内容。第2.2讲优化长列表显示,使用recycle-view组件。第2.3讲使用页面容器。第5.2讲减少主包及主包大小,在主页中使用占位组件,使用封面页代替主页。第8.7讲,图片优化技巧,图片压缩与使用腾讯云cos转存本地图片。第9.2讲使用原生类型节点,绕过逻辑层直接更新视图内容。上面所有优化技巧都是基于小程序的冷启动流程而存在的,在学习与应用这些优化技巧的时候,有三点内容我们一定要烂熟于心。第一点,小程序的冷启动流程特点,这部分内容我们在第1讲已经详细介绍了。第二点小程序的双线程运行机制,这部分内容介绍也在第1讲里边。第三点小程序的重渲染机制,这部分内容详细介绍在第2.5讲。这三点关于冷启动流程双线程运行机制及重渲染的内容,它们是枝干,所有优化技巧都是在它们的基础之上展开的枝叶。 下面我们看推荐阅读,这里有一些文章链接,如屏幕上所示,它们的内容都很不错,为本课程的打造提供了不少的创作灵感,推荐给你阅读。 下面我们看致谢与课程总结,这个课程在打造过程当中参考了不少的优秀的开源组件和社区教程,在此我们一并感谢,这些教程以及开源组件库的链接,如屏幕上所示。这个课程在以下方面富有一些创造性,在这里请允许我总结一下。 第一点,使用异步转同步编程范式,结合立即执行函数,在保证代码清晰性,可阅读性的前提之下提高主线程的执行效率。 第二点,将优先级自动排序的列队应用于网络请求当中提高网络操作的执行效率。 第三点,使用串发复合指令,在多个文件里面延迟非重要同步代码的执行。 第四点,使用并发复合指令,在多个文件中对齐代码执行点,使用竞赛模式基于多种渠道竞相拉取主页数据。 前两项多多少少或许与其他课程在方法上有些重合,但第三项,第四项关于命令模式的优化在其他地方我还没有看到过,算是这门课程的创新点,如有雷同纯属巧合。在优化策略上,整体来讲大体可以分为两类。第一类以空间换时间,例如数据预拉取,周期性更新,初始渲染缓存,使用LocalStorage缓存接口等等这些技巧,都属于以空间换时间的技巧。第二类以时间换空间,例如使用虚拟DOM,使用长列表组件,这一类都是属于以时间换空间的优化技巧,无论怎样的优化技巧,本质上精神都是一致的。精神就是现人现地,立足小程序的启动流程,双线程运行机制和重渲染机制,具体项目具体分析,以一个字节,一个字节去抠,一个毫秒,一个毫秒去节省的细致精神,一点点进行优化。在这个地方抠下了一点,在那个地方省下了一点,整体上性能就提升了。如果你在这个地方凑合一下,在那个地方也马虎一样,那么整体上性能也就下降了。 2017年微信小程序刚上线,那一年还有不少企业絮絮叨叨在质疑,在思考小程序到底值不值得去做。2022年第一季度小程序日活已经达到了5亿以后,已经没有企业在思考这个问题了。其他平台类似的技术生态的跟风和学习,以及小程序日活数字的日益增长,已经证明了这个技术赛道是对的,选择小程序作为产品的运营阵地,尤其是作为第一个运营阵地,已经成为初创企业的一个共识,纵然现在虽然小程序还有这样与那样的不足,但是我们同时也应该看到它一直都在快速迭代和快速进化。目前小程序在性能方面已经具备了这么多的调试工具和优化技巧,开发者在遇到性能问题的时候,已经没有什么好抱怨的了。把原理学好,把JS语言学好,把优化技能学好,完全可以把产品的性能优化好,甚至在一定范围之内还可以媲美原生应用。 源码地址: https://gitee.com/geektime-geekbang_admin/weapp_optimize 最后我们说一下源码,本课涉及到所有示例源码都可以从屏幕上的这个位置进行下载,源码是分课程划分目录的,例如6.6对应就是第6.6讲的示例源码。以上就是本课程的全部内容了,限于我的能力有限,这个课程有不完善的地方,恳请读者朋友多多批评指正。
2022-07-15 - 多个input输入完成自动切换到下一个输入框
需求: 一个input输入完回车,切换到下一个input。 思路: JS里声明2个变量: focus是否获得焦点,focusIndex需要焦点的序号。wxml中给input设置id,设置focus属性由这两个变量来控制。在JS的输入完成监听事件里获取下一个input的id序号并修改变量。 js: [代码]Page({ /** * 页面的初始数据 */ data: { ... // 是否获取焦点 focus: false, // 需要获取焦点的序号 focusIndex: 0 }, // 输入完成事件 confirmListener (event) { let currentIndex = event.currentTarget.dataset.categoryIndex if (currentIndex < input的数量 - 1) { this.setData({ focus: true, focusIndex: currentIndex + 1 }) }else { this.setData({ focus: false }) } }, // 输入时事件 inputListener(event) { ... let currentIndex = event.currentTarget.dataset.categoryIndex if (this.focusIndex != currentIndex) { this.setData({ focusIndex: currentIndex }) } }, }) [代码] wxml: [代码]<input id="input{{index}}" data-category-index="{{index}}" bindinput="inputListener" bindconfirm="confirmListener" focus="{{focus && focusIndex == index}}" [代码]
2021-10-28 - video-swiper短视频轮播,解决方案2(增加动态加载数据)
实现短视频小程序指定到某个视频开始轮播,方案1已经解析过,这里就不多说了,不懂的可以请移步到这里查看:https://developers.weixin.qq.com/community/develop/article/doc/000c2e0afc8cc8b2a96b36d665b413 这里主要讲的是,如何进行动态加载数据问题 第一步,在获取数据列表中加个条件判断,如果超过你设置的长度就算二次获取数据,进行数据切割加到将要预览的数组里面,代码如下(主要看条件判断,这里以10个数据为例): videoList: { type: Array, value: [], observer: function observer() { var newVal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; if (newVal.length) { newVal.map((item, index) => { return item.idxKey = index + 1; }); if (newVal.length<=10) { this._videoListChanged(newVal); } else { // 重点是这里的条件判断 // 防止当前数组被污染 let arr = JSON.parse(JSON.stringify(newVal)); // 去掉已有的数据 let nextArr = arr.splice(this.data.total); this.data.nextQueue.push(...nextArr); } this.setData({total: newVal.length}) } } } 第二步,在每次滑动视频时,判断下当前视频总数和剩下视频个数,满足条件即可请求加载数据,代码如下: // 判断总数据是否大于等于10,并且下滑剩下4个视频开始请求接口拿数据;这里大小可以根据自己需求修改 if (total>=10 && nextQueue.length < 5) { this.triggerEvent('UpdataVideo', {}); } 就加这两步,轻松完成一个短视频,从定位到某个视频开始播放,到数据没有时进行预加载视频。 有什么问题,欢迎随时咨询。 完整版代码片段:https://developers.weixin.qq.com/s/Ikk98ymm7tph
2021-04-14 - 这个报错怎么处理????
真机上出现: Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors。 这是什么错误????怎么处理????没感觉出啥错误!!!!
2019-04-03 - 云函数获取openid
代码如下: app.js: //如果担心openid的安全,就用这个函数 getCloudOpenid: async function () { return this.openid = this.openid || (await wx.cloud.callFunction({name: 'login'})).result.OPENID }, //最佳方案。 getOpenid: async function () { (this.openid = this.openid || wx.getStorageSync('openid')) || wx.setStorageSync('openid', await this.getCloudOpenid()) return this.openid }, 任何page: onLoad: async function () { console.log(this.openid = await getApp().getOpenid()) }, //在本page的其他函数里获得openid。 yourFunc: function(){ console.log(this.openid) } 云函数login: const cloud = require('wx-server-sdk') cloud.init() exports.main=async()=>{return cloud.getWXContext()}
2020-10-18 - 将小程序原生异步函数promisify后,在async/await中使用
目前,小程序中支持使用async/await有三种模式: 1、不勾选es6转es5,不勾选增强编译;该模式是纯es7的async/await,需要基础库高版本。 2、勾选es6转es5,勾选增强编译;一般是因为调用了第三方的es5插件,通过增强编译支持async/await。 3、勾选es6转es5,不勾选增强编译;手工引入runtime.js支持async/await。 据最近更新情况,原生的函数已经大部分同时原生支持同步化了,不需要本方案转化了,直接加上await即可;比如wx.chooseImage、wx.showModal。。。具体有哪些,可以自己试。 如果只是wx.request的同步化,可参考: https://developers.weixin.qq.com/community/develop/article/doc/0004cc839407a069f77a416c056813 app.js代码: function promisify(api) { return (opt, ...arg) => { return new Promise((resolve, reject) => { api(Object.assign({}, opt, { success: resolve, fail: reject }), ...arg) }) } } App({ globalData: {}, chooseImage: promisify(wx.chooseImage), request: promisify(wx.request), getUserInfo: promisify(wx.getUserInfo), onLaunch: function () { }, }) 某page的index.js代码: const app = getApp() testAsync: async function(){ let res = await app.chooseImage() console.log(res) res = await app.request({url:'url',method:'POST',data:{x:0,y:1}}) console.log(res) }, [图片]
2020-10-20