- 微信小程序自定义导航栏组件(完美适配所有手机),可自定义实现任何你想要的功能
背景 在做小程序时,关于默认导航栏,我们遇到了以下的问题: Android、IOS手机对于页面title的展示不一致,安卓title的显示不居中 页面的title只支持纯文本级别的样式控制,不能够做更丰富的title效果 左上角的事件无法监听、定制 路由导航单一,只能够返回上一页,深层级页面的返回不够友好 探索 小程序自定义导航栏已开放许久>>了解一下,相信不少小伙伴已使用过这个功能,同时不少小伙伴也会发现一些坑: 机型多如牛毛:自定义导航栏高度在不同机型始终无法达到视觉上的统一 调皮的胶囊按钮:导航栏元素(文字,图标等)怎么也对不齐那该死的胶囊按钮 各种尺寸的全面屏,奇怪的刘海屏,简直要抓狂 一探究竟 为了搞明白原理,我先去翻了官方文档,>>飞机,点过去是不是很惊喜,很意外,通篇大文尽然只有最下方的一张图片与这个问题有关,并且啥也看不清,汗汗汗… 我特意找了一张图片来 [图片] 分析上图,我得到如下信息: Android跟iOS有差异,表现在顶部到胶囊按钮之间的距离差了6pt 胶囊按钮高度为32pt, iOS和Android一致 动手分析 我们写一个状态栏,通过wx.getSystemInfoSync().statusBarHeight设置高度 Android: [图片] iOS:[图片] 可以看出,iOS胶囊按钮与状态栏之间距离为:4px, Android为8px,是不是所有手机都是这种情况呢? 答案是:苹果手机确实都是4px,安卓大部分都是7和8 也会有其他的情况(可以自己打印getSystemInfo验证)如何快速便捷算出这个高度,请接着往下看 如何计算 导航栏分为状态栏和标题栏,只要能算出每台手机的导航栏高度问题就迎刃而解 导航栏高度 = 胶囊按钮高度 + 状态栏到胶囊按钮间距 * 2 + 状态栏高度 注:由于胶囊按钮是原生组件,为表现一致,其单位在各种手机中都为px,所以我们自定义导航栏的单位都必需是px(切记不能用rpx),才能完美适配。 解决问题 现在我们明白了原理,可以利用胶囊按钮的位置信息和statusBarHeight高度动态计算导航栏的高度,贴一个实现此功能最重要的方法 [代码]let systemInfo = wx.getSystemInfoSync(); let rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null; //胶囊按钮位置信息 wx.getMenuButtonBoundingClientRect(); let navBarHeight = (function() { //导航栏高度 let gap = rect.top - systemInfo.statusBarHeight; //动态计算每台手机状态栏到胶囊按钮间距 return 2 * gap + rect.height; })(); [代码] gap信息就是不同的手机其状态栏到胶囊按钮间距,具体更多代码实现和使用demo请移步下方代码仓库,代码中还会有输入框文字跳动解决办法,安卓手机输入框文字飞出解决办法,左侧按钮边框太粗解决办法等等 胶囊信息报错和获取不到 问题就在于 getMenuButtonBoundingClientRect 这个方法,在某些机子和环境下会报错或者获取不到,对于此种情况完美可以模拟一个胶囊位置出来 [代码]try { rect = Taro.getMenuButtonBoundingClientRect ? Taro.getMenuButtonBoundingClientRect() : null; if (rect === null) { throw 'getMenuButtonBoundingClientRect error'; } //取值为0的情况 if (!rect.width) { throw 'getMenuButtonBoundingClientRect error'; } } catch (error) { let gap = ''; //胶囊按钮上下间距 使导航内容居中 let width = 96; //胶囊的宽度,android大部分96,ios为88 if (systemInfo.platform === 'android') { gap = 8; width = 96; } else if (systemInfo.platform === 'devtools') { if (ios) { gap = 5.5; //开发工具中ios手机 } else { gap = 7.5; //开发工具中android和其他手机 } } else { gap = 4; width = 88; } if (!systemInfo.statusBarHeight) { //开启wifi的情况下修复statusBarHeight值获取不到 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20; } rect = { //获取不到胶囊信息就自定义重置一个 bottom: systemInfo.statusBarHeight + gap + 32, height: 32, left: systemInfo.windowWidth - width - 10, right: systemInfo.windowWidth - 10, top: systemInfo.statusBarHeight + gap, width: width }; console.log('error', error); console.log('rect', rect); } [代码] 以上代码主要是借鉴了拼多多的默认值写法,android 机子中 gap 值大部分为 8,ios 都为 4,开发工具中 ios 为 5.5,android 为 7.5,这样处理之后自己模拟一个胶囊按钮的位置,这样在获取不到胶囊信息的情况下,可保证绝大多数机子完美显示导航头 吐槽 这么重要的问题,官方尽然没有提供解决方案…竟然提供了一张看不清的图片??? 网上有很多ios设置44,android设置48,还有根据不同的手机型号设置不同高度,通过长时间的开发和尝试,本人发现以上方案并不完美,并且bug很多 代码库 Taro组件gitHub地址详细用法请参考README 原生组件npm构建版本gitHub地址详细用法请参考README 原生组件简易版gitHub地址详细用法请参考README 由于本人精力有限,目前只计划发布维护好这2种组件,其他组件请自行修改代码,有问题请联系 备注 上方2种组件在最下方30多款手机测试情况表现良好 iPhone手机打电话和开热点导致导航栏样式错乱,问题已经解决啦,请去demo里测试,这里特别感谢moments网友提出的问题 本文章并无任何商业性质,如有侵权请联系本人修改或删除 文章少量部分内容是本人查询搜集而来 如有问题可以下方留言讨论,微信zhijunxh 比较 斗鱼: [图片] 虎牙: [图片] 微博: [图片] 酷狗: [图片] 知乎: [图片] [图片] 知乎是这里边做的最好的,但是我个人认为有几个可以优化的小问题 打电话或者开启热点导致样式错落,这也是大部门小程序的问题 导航栏下边距太小,看起来不舒服 搜索框距离2侧按钮组距离不对等 自定义返回和home按钮中的竖线颜色重了,并且感觉太粗 如果您看到了此篇文章,请赶快修改自己的代码,并运用在实践中吧 扫码体验我的小程序: [图片] 创作不易,如果对你有帮助,请移步Taro组件gitHub原生组件gitHub给个星星 star✨✨ 谢谢 测试信息 手机型号 胶囊位置信息 statusBarHeight 测试情况 iPhoneX 80 32 281 369 48 88 44 通过 iPhone8 plus 56 32 320 408 24 88 20 通过 iphone7 56 32 281 368 24 87 20 通过 iPhone6 plus 56 32 320 408 24 88 20 通过 iPhone6 56 32 281 368 24 87 20 通过 HUAWEI SLA-AL00 64 32 254 350 32 96 24 通过 HUAWEI VTR-AL00 64 32 254 350 32 96 24 通过 HUAWEI EVA-AL00 64 32 254 350 32 96 24 通过 HUAWEI EML-AL00 68 32 254 350 36 96 29 通过 HUAWEI VOG-AL00 65 32 254 350 33 96 25 通过 HUAWEI ATU-TL10 64 32 254 350 32 96 24 通过 HUAWEI SMARTISAN OS105 64 32 326 422 32 96 24 通过 XIAOMI MI6 59 28 265 352 31 87 23 通过 XIAOMI MI4LTE 60 32 254 350 28 96 20 通过 XIAOMI MIX3 74 32 287 383 42 96 35 通过 REDMI NOTE3 64 32 254 350 32 96 24 通过 REDMI NOTE4 64 32 254 350 32 96 24 通过 REDMI NOTE3 55 28 255 351 27 96 20 通过 REDMI 5plus 67 32 287 383 35 96 28 通过 MEIZU M571C 65 32 254 350 33 96 25 通过 MEIZU M6 NOTE 62 32 254 350 30 96 22 通过 MEIZU MX4 PRO 62 32 278 374 30 96 22 通过 OPPO A33 65 32 254 350 33 96 26 通过 OPPO R11 58 32 254 350 26 96 18 通过 VIVO Y55 64 32 254 350 32 96 24 通过 HONOR BLN-AL20 64 32 254 350 32 96 24 通过 HONOR NEM-AL10 59 28 265 352 31 87 24 通过 HONOR BND-AL10 64 32 254 350 32 96 24 通过 HONOR duk-al20 64 32 254 350 32 96 24 通过 SAMSUNG SM-G9550 64 32 305 401 32 96 24 通过 360 1801-A01 64 32 254 350 32 96 24 通过
2019-11-17 - 微信小程序-自定义导航栏-免费开源
先看看效果吧。 [图片] [图片] [图片] [图片] 两种状态(可在组件灵活配置) 1,在tabBar页面,统一显示在左边。(看上面图片) 2,在非tabBar页面,统一显示在中间。(看上面图片) 配置返回弹窗:(对物理按键无效 1,将需要返回弹窗的页面路径配置在returnWindow数组里面即可。 [图片] 2,wxml页面,设置弹窗内容 [图片] [图片] 引用:(需要开发版Nightily工具才能正常体验 app.json全局配置"navigationStyle": "custom"。或者单个页面也行。app.json全局引入自定义组件和icon图标。需要引入weui。路径的话,自己看着办。app.json相对你组件的位置。 [图片] 3,到页面wxml引用了,就一行代码。<navigation title="搜索"></navigation> [图片] 解释: [图片] index即首页。 tabBarList中的页面即展示左边标题。不在的页面则展示左边菜单,中间标题。可到组件中灵活配置 returnWindow返回需要弹窗的页面数组。 样式方面: 使用的是cover-view+fixed定位 真实案例小程序:(问卷调查时间) [图片] 代码片段: https://developers.weixin.qq.com/s/UA7X0emv7wes
2020-04-28 - CSS 火焰?不在话下
正文从下面开始。 今天的小技巧是使用纯 CSS 生成火焰,逼真一点的火焰。 嗯,长什么样子?在 CodePen 上输入关键字 [代码]CSS Fire[代码],能找到这样的: [图片] 或者这样的: [图片] 我们希望,仅仅使用 CSS ,效果能再更进一步吗?能不能是这样子: [图片] 如何实现 嗯,我们需要使用 [代码]filter[代码] + [代码]mix-blend-mode[代码] 的组合来完成。 很多 CSS 华而不实的效果都是 [代码]filter[代码] + [代码]mix-blend-mode[代码],很有意思,但是业务中根本用不上,当然多了解了解总没坏处。 如上图,整个蜡烛的骨架, 除去火焰的部分很简单,掠过不讲。主要来看看火焰这一块如何生成,并且如何赋予动画效果。 Step 1: filter blur && filter contrast 模糊滤镜叠加对比度滤镜产生的融合效果。 单独将两个滤镜拿出来,它们的作用分别是: [代码]filter: blur()[代码]: 给图像设置高斯模糊效果。 [代码]filter: contrast()[代码]: 调整图像的对比度。 但是,当他们“合体”的时候,产生了奇妙的融合现象。 先来看一个简单的例子: [图片] 仔细看两圆相交的过程,在边与边接触的时候,会产生一种边界融合的效果,通过对比度滤镜把高斯模糊的模糊边缘给干掉,利用高斯模糊实现融合效果。 利用上述 [代码]filter blur & filter contrast[代码],我们要先生成一个类似火焰形状的三角形。(略去过程) 这里类似火焰形状的三角形的具体实现过程,在这篇文章有详细的讲解:你所不知道的 CSS 滤镜技巧与细节 [图片] 父元素添加 [代码]filter: blur(5px) contrast(20)[代码],会变成这样: [图片] Step 2: 火焰粒子动画 看着已经有点样子了,接下来是火焰动画,我们先去掉父元素的 [代码]filter: blur(5px) contrast(20)[代码] ,然后继续 。 这里也是利用了 [代码]filter[代码] 的融合效果,我们在上述火焰中,利用 SASS 随机均匀分布大量大小不一的圆形棕色 div ,隐匿在火焰三角内部,大概是这样: [图片] 接下来,我们再利用 SASS,给中间每个小圆赋予一个从下往上逐渐消失的动画,并且均匀赋予不同的 [代码]animation-delay[代码],看起来会是这样: [图片] OK,最重要的一步,我们再把父元素的 [代码]filter: blur(5px) contrast(20)[代码] 打开,神奇的火焰效果就出来了: [图片] Step 3: mix-blend-mode 润色 当然,上述效果已经很不错了。经过各种尝试,调整参数,最后我发现加上 [代码]mix-blend-mode: screen[代码] 混合模式,效果更好,得到头图上面的最终效果如下: [图片] 完整源码在我的 CodePen 上:CodePen Demo – CSS Fire 另外一些效果 当然,掌握了这种方法后,这种生成火焰的技巧也可以迁移到其他效果去。下图是我鼓捣到另外一个小 Demo,当 hover 到元素的时候,产生火焰效果: [图片] CodePen Demo – Hover Fire 嗯,这些其实都是对滤镜及混合模式的一些搭配运用。按照惯例,肯定有人会留言喷了,整这些花里胡哨的有什么用,性能又不好,业务中敢上不把你的腿给打骨折。 [图片] 于我而言,虚心接受各种批评质疑及各种不同的观点,当然我是觉得搞技术一方面是实用,另一方面是兴趣使然,自娱自乐。希望喷子绕道~ 回到正题,了解了这种黏糊糊湿答答的技巧后,还可以折腾出其他很多有意思的效果,当然可能需要更多的去尝试,如下面使用一个标签实现的滴水效果: [图片] CodePen Demo – 单标签实现滴水效果 值得注意的细节点 动画虽然美好,但是具体使用的过程中,仍然有一些需要注意的地方: CSS 滤镜可以给同个元素同时定义多个,例如 [代码]filter: blur(5px) contrast(150%) brightness(1.5)[代码] ,但是滤镜的先后顺序不同产生的效果也是不一样的; 也就是说,使用 [代码]filter: blur(5px) contrast(150%) brightness(1.5)[代码] 和 [代码]filter: brightness(1.5) contrast(150%) blur(5px)[代码] 处理同一张图片,得到的效果是不一样的,原因在于滤镜的色值处理算法对图片处理的先后顺序。 滤镜动画需要大量的计算,不断的重绘页面,属于非常消耗性能的动画,使用时要注意使用场景。记得开启硬件加速及合理使用分层技术; [代码]blur()[代码] 混合 [代码]contrast()[代码] 滤镜效果,设置不同的颜色会产生不同的效果,这个颜色叠加的具体算法暂时没有找到很具体的规则细则,使用时比较好的方法是多尝试不同颜色,观察取最好的效果; 细心的读者会发现上述效果都是基于黑色底色进行的,动手尝试将底色改为白色,效果会大打折扣。 最后 本文只是简单的介绍了整个思路过程,许多 CSS 代码细节,调试过程没有展现出来。主要几个 CSS 属性默认大家已经掌握了大概,阅读后可以自行去了解补充更多细节: [代码]filter[代码] [代码]mix-blend-mode[代码] 更多精彩 CSS 技术文章汇总在我的 Github – iCSS ,持续更新,欢迎点个 star 订阅收藏。 好了,本文到此结束,希望对你有帮助 😃 如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。 最后,新开通的公众号求关注,形式希望是更短的篇幅,质量更高一些的技巧类文章,包括但不局限于 CSS: [图片]
2019-04-26 - 【开箱即用】分享几个好看的波浪动画css效果!
以下代码不一定都是本人原创,很多都是借鉴参考的(模仿是第一生产力嘛),有些已忘记出处了。以下分享给大家,供学习参考!欢迎收藏补充,说不定哪天你就用上了! 一、第一种效果 [图片] [代码]//index.wxml <view class="zr"> <view class='user_box'> <view class='userInfo'> <open-data type="userAvatarUrl"></open-data> </view> <view class='userInfo_name'> <open-data type="userNickName"></open-data> , 欢迎您 </view> </view> <view class="water"> <view class="water-c"> <view class="water-1"> </view> <view class="water-2"> </view> </view> </view> </view> //index.wxss .zr { color: white; background: #4cb4e7; /*#0396FF*/ width: 100%; height: 100px; position: relative; } .water { position: absolute; left: 0; bottom: -10px; height: 30px; width: 100%; z-index: 1; } .water-c { position: relative; } .water-1 { background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjYwMHB4IiBoZWlnaHQ9IjYwcHgiIHZpZXdCb3g9IjAgMCA2MDAgNjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiPgogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCAzLjQgKDE1NTc1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT53YXRlci0xPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IuaIkSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc2tldGNoOnR5cGU9Ik1TUGFnZSI+CiAgICAgICAgPGcgaWQ9Ii0iIHNrZXRjaDp0eXBlPSJNU0FydGJvYXJkR3JvdXAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMjEuMDAwMDAwLCAtMTMzLjAwMDAwMCkiIGZpbGwtb3BhY2l0eT0iMC4zIiBmaWxsPSIjRkZGRkZGIj4KICAgICAgICAgICAgPGcgaWQ9IndhdGVyLTEiIHNrZXRjaDp0eXBlPSJNU0xheWVyR3JvdXAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyMS4wMDAwMDAsIDEzMy4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0wLDcuNjk4NTczOTUgTDQuNjcwNzE5NjJlLTE1LDYwIEw2MDAsNjAgTDYwMCw3LjM1MjMwNDYxIEM2MDAsNy4zNTIzMDQ2MSA0MzIuNzIxMDUyLDI0LjEwNjUxMzggMjkwLjQ4NDA0LDcuMzU2NzQxODcgQzE0OC4yNDcwMjcsLTkuMzkzMDMwMDggMCw3LjY5ODU3Mzk1IDAsNy42OTg1NzM5NSBaIiBpZD0iUGF0aC0xIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==") repeat-x; background-size: 600px; -webkit-animation: wave-animation-1 3.5s infinite linear; animation: wave-animation-1 3.5s infinite linear; } .water-2 { top: 5px; background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjYwMHB4IiBoZWlnaHQ9IjYwcHgiIHZpZXdCb3g9IjAgMCA2MDAgNjAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sbnM6c2tldGNoPSJodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2gvbnMiPgogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCAzLjQgKDE1NTc1KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT53YXRlci0yPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IuaIkSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc2tldGNoOnR5cGU9Ik1TUGFnZSI+CiAgICAgICAgPGcgaWQ9Ii0iIHNrZXRjaDp0eXBlPSJNU0FydGJvYXJkR3JvdXAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xMjEuMDAwMDAwLCAtMjQ2LjAwMDAwMCkiIGZpbGw9IiNGRkZGRkYiPgogICAgICAgICAgICA8ZyBpZD0id2F0ZXItMiIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTIxLjAwMDAwMCwgMjQ2LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgPHBhdGggZD0iTTAsNy42OTg1NzM5NSBMNC42NzA3MTk2MmUtMTUsNjAgTDYwMCw2MCBMNjAwLDcuMzUyMzA0NjEgQzYwMCw3LjM1MjMwNDYxIDQzMi43MjEwNTIsMjQuMTA2NTEzOCAyOTAuNDg0MDQsNy4zNTY3NDE4NyBDMTQ4LjI0NzAyNywtOS4zOTMwMzAwOCAwLDcuNjk4NTczOTUgMCw3LjY5ODU3Mzk1IFoiIGlkPSJQYXRoLTIiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDMwMC4wMDAwMDAsIDMwLjAwMDAwMCkgc2NhbGUoLTEsIDEpIHRyYW5zbGF0ZSgtMzAwLjAwMDAwMCwgLTMwLjAwMDAwMCkgIj48L3BhdGg+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==") repeat-x; background-size: 600px; -webkit-animation: wave-animation-2 6s infinite linear; animation: wave-animation-2 6s infinite linear; } .water-1, .water-2 { position: absolute; width: 100%; height: 60px; } .back-white { background: #fff; } @keyframes wave-animation-1 { 0% { background-position: 0 top; } 100% { background-position: 600px top; } } @keyframes wave-animation-2 { 0% { background-position: 0 top; } 100% { background-position: 600px top; } } .user_box { display: flex; z-index: 10000 !important; opacity: 0; /* 透明度*/ animation: love 1.5s ease-in-out; animation-fill-mode: forwards; } .userInfo_name { flex: 1; vertical-align: middle; width: 100%; margin-left: 5%; margin-top: 5%; font-size: 42rpx; } .userInfo { flex: 1; width: 100%; border-radius: 50%; overflow: hidden; max-height: 50px; max-width: 50px; margin-left: 5%; margin-top: 5%; border: 2px solid #fff; } [代码] 二、第二种效果 [图片] [代码]//index.wxml <view class="waveWrapper waveAnimation"> <view class="waveWrapperInner bgTop"> <view class="wave waveTop" style="background-image: url('https://s2.ax1x.com/2019/09/26/um8g7n.png')"></view> </view> <view class="waveWrapperInner bgMiddle"> <view class="wave waveMiddle" style="background-image: url('https://s2.ax1x.com/2019/09/26/umGZ38.png')"></view> </view> <view class="waveWrapperInner bgBottom"> <view class="wave waveBottom" style="background-image: url('https://s2.ax1x.com/2019/09/26/umGuuQ.png')"></view> </view> </view> //index.wxss .waveWrapper { overflow: hidden; position: absolute; left: 0; right: 0; height: 300px; top: 0; margin: auto; } .waveWrapperInner { position: absolute; width: 100%; overflow: hidden; height: 100%; bottom: -1px; background-image: linear-gradient(to top, #86377b 20%, #27273c 80%); } .bgTop { z-index: 15; opacity: 0.5; } .bgMiddle { z-index: 10; opacity: 0.75; } .bgBottom { z-index: 5; } .wave { position: absolute; left: 0; width: 500%; height: 100%; background-repeat: repeat no-repeat; background-position: 0 bottom; transform-origin: center bottom; } .waveTop { background-size: 50% 100px; } .waveAnimation .waveTop { animation: move-wave 3s; -webkit-animation: move-wave 3s; -webkit-animation-delay: 1s; animation-delay: 1s; } .waveMiddle { background-size: 50% 120px; } .waveAnimation .waveMiddle { animation: move_wave 10s linear infinite; } .waveBottom { background-size: 50% 100px; } .waveAnimation .waveBottom { animation: move_wave 15s linear infinite; } @keyframes move_wave { 0% { transform: translateX(0) translateZ(0) scaleY(1) } 50% { transform: translateX(-25%) translateZ(0) scaleY(0.55) } 100% { transform: translateX(-50%) translateZ(0) scaleY(1) } } [代码] 三、第三种效果 [图片] [代码]//index.wxml <view class="container"> <image class="title" src="https://ftp.bmp.ovh/imgs/2019/09/74bada9c4143786a.png"></image> <view class="content"> <view class="hd" style="transform:rotateZ({{angle}}deg);"> <image class="logo" src="https://ftp.bmp.ovh/imgs/2019/09/d31b8fcf19ee48dc.png"></image> <image class="wave" src="wave.png" mode="aspectFill"></image> <image class="wave wave-bg" src="wave.png" mode="aspectFill"></image> </view> <view class="bd" style="height: 100rpx;"> </view> </view> </view> //index.wxss image{ max-width:none; } .container { background: #7acfa6; align-items: stretch; padding: 0; height: 100%; overflow: hidden; } .content{ flex: 1; display: flex; position: relative; z-index: 10; flex-direction: column; align-items: stretch; justify-content: center; width: 100%; height: 100%; padding-bottom: 450rpx; background: -webkit-gradient(linear, left top, left bottom, from(rgba(244,244,244,0)), color-stop(0.1, #f4f4f4), to(#f4f4f4)); opacity: 0; transform: translate3d(0,100%,0); animation: rise 3s cubic-bezier(0.19, 1, 0.22, 1) .25s forwards; } @keyframes rise{ 0% {opacity: 0;transform: translate3d(0,100%,0);} 50% {opacity: 1;} 100% {opacity: 1;transform: translate3d(0,450rpx,0);} } .title{ position: absolute; top: 30rpx; left: 50%; width: 600rpx; height: 200rpx; margin-left: -300rpx; opacity: 0; animation: show 2.5s cubic-bezier(0.19, 1, 0.22, 1) .5s forwards; } @keyframes show{ 0% {opacity: 0;} 100% {opacity: .95;} } .hd { position: absolute; top: 0; left: 50%; width: 1000rpx; margin-left: -500rpx; height: 200rpx; transition: all .35s ease; } .logo { position: absolute; z-index: 2; left: 50%; bottom: 200rpx; width: 160rpx; height: 160rpx; margin-left: -80rpx; border-radius: 160rpx; animation: sway 10s ease-in-out infinite; opacity: .95; } @keyframes sway{ 0% {transform: translate3d(0,20rpx,0) rotate(-15deg); } 17% {transform: translate3d(0,0rpx,0) rotate(25deg); } 34% {transform: translate3d(0,-20rpx,0) rotate(-20deg); } 50% {transform: translate3d(0,-10rpx,0) rotate(15deg); } 67% {transform: translate3d(0,10rpx,0) rotate(-25deg); } 84% {transform: translate3d(0,15rpx,0) rotate(15deg); } 100% {transform: translate3d(0,20rpx,0) rotate(-15deg); } } .wave { position: absolute; z-index: 3; right: 0; bottom: 0; opacity: 0.725; height: 260rpx; width: 2250rpx; animation: wave 10s linear infinite; } .wave-bg { z-index: 1; animation: wave-bg 10.25s linear infinite; } @keyframes wave{ from {transform: translate3d(125rpx,0,0);} to {transform: translate3d(1125rpx,0,0);} } @keyframes wave-bg{ from {transform: translate3d(375rpx,0,0);} to {transform: translate3d(1375rpx,0,0);} } .bd { position: relative; flex: 1; display: flex; flex-direction: column; align-items: stretch; animation: bd-rise 2s cubic-bezier(0.23,1,0.32,1) .75s forwards; opacity: 0; } @keyframes bd-rise{ from {opacity: 0; transform: translate3d(0,60rpx,0); } to {opacity: 1; transform: translate3d(0,0,0); } } [代码] wave.png(可下载到本地) [图片] 在这个基础上,再加上js的代码,即可实现根据手机倾向,水波晃动的效果 wx.onAccelerometerChange(function callback) 监听加速度数据事件。 [图片] [代码]//index.js Page({ onReady: function () { var _this = this; wx.onAccelerometerChange(function (res) { var angle = -(res.x * 30).toFixed(1); if (angle > 14) { angle = 14; } else if (angle < -14) { angle = -14; } if (_this.data.angle !== angle) { _this.setData({ angle: angle }); } }); }, }); [代码] 四、第四种效果 [图片] [代码]//index.wxml <view class='page__bd'> <view class="bg-img padding-tb-xl" style="background-image:url('http://wx4.sinaimg.cn/mw690/006UdlVNgy1g2v2t1ih8jj31hc0p0qej.jpg');background-size:cover;"> <view class="cu-bar"> <view class="content text-bold text-white"> 悦拍屋 </view> </view> </view> <view class="shadow-blur"> <image src="https://raw.githubusercontent.com/weilanwl/ColorUI/master/demo/images/wave.gif" mode="scaleToFill" class="gif-black response" style="height:100rpx;margin-top:-100rpx;"></image> </view> </view> //index.wxss @import "colorui.wxss"; .gif-black { display: block; border: none; mix-blend-mode: screen; } [代码] 本效果需要引入ColorUI组件库
2019-09-26