记一次小程序样式优化重构

更新日期: 2020-03-14阅读: 2.2k标签: 小程序

上周花了 3 天的时间和老大一起重构了一下小程序的样式开发,虽然说在开发的过程中遇到了一些问题,但是最终减少了不少样式代码,同时功能上也更加强大。进一步来说,如果在后面我们的小程序用户想要自己定制化主题,也可以很快的实现。


全局样式开发

之前的小程序开发中,我们全方面使用了 Component 构造小程序组件以及页面(页面也可以使用 Component 构造器来编写)。当然一方面是因为小程序 Component 的开发体验非常好,拥有类似于 vue mixin, watch 的 behaviors 和 observers,比 Page 构造器强大了很多。另一方面,对于业务较重的小程序来说, Component 也有性能优势。可以参照 滴滴开源小程序框架Mpx 中的 Page与Component setData性能对照。

在开发过程中,有很多样式是可以复用的。如果在之前开发中经常使用 Bootstrap 之类的 ui 库,那么你就会习惯使用这种库的 utilities 类。但是默认情况下,自定义组件的样式只受到自定义组件 wxss 的影响。不会受到全局样式 app.wxss 的影响。所以我们只能通过增加 @import 语法来辅助各个组件进行开发。

@import "xxx.css";

如果你使用 CSS 预处理器来辅助小程序开发的话,可能就需要通过 gulp-insert 为编译出来的 wxss 文件前置添加该语句。请注意: 之所以 @import 需要前置,是因为 @import 语法会把引入的样式按照导入的位置来生效,也就是说,按照 CSS 同等权重看先后的规则来说,如果把 @import 放在中间位置,前面位置定义的样式可能会被 @import 给覆盖掉。

小程序全局样式

当然,小程序基础库版本在 2.2.3 以上就支持了addGlobalClass 配置项,即在 Component 的 options 中设置 addGlobalClass: true 。

Component({
  options: {
    addGlobalClass: true
  }
})

该配置项目表示页面级别的 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面。也就是说我们可以用该配置替代之前的每个组件的 @import。只要在 app.wxss 上导入 CSS 样式即可,同时我们可以在页面上对组件内部的样式进行修改。不过需要说明的是: 该配置并不影响父子组件间的样式。各个子组件只受到 app.wxss 和页面的样式的侵入。小程序开发基本上以页面为单位,所以这个配置是非常适合开发的。不过在之前的开发中并没有在意过这个配置。

组件样式隔离

当然了,在后面的版本 2.6.5 中,微信小程序也提供了更为详细的隔离选项 styleIsolation 。

Component({
  options: {
    styleIsolation: 'isolated'
  }
})
  • isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值)。
  • apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面。
  • shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用)。

styleIsolation 浅析

如果大家不想了解太多,只想使用的话, 简短来说:

大家在组件中直接使用 apply-shared,如果当前的 Component 构造器应用于页面,那么不要配置隔离选项即可。其余的隔离选项都是基本没什么用的。

styleIsolation 详解

isolated 等同于什么都不干,设置不设置一般没有区别,所以可以当该配置项目不存在。

apply-shared 等同于addGlobalClass: true,也是最有用的配置项 。

shared 最复杂,在子组件设置了样式,不但会影响自身和页面(同时包括了其他设置了apply-shared 或 shared 的自定义组件),同时呢,又会被页面样式和其他设置了 shared 的组件样式影响。在我使用该功能的过程中,我认为,这个配置项千万不要在组件中去使用,除非你“疯了”。

但是不介绍这个配置项目又不行,因为当你使用 Component 去构建页面时候,该页面的配置项目默认就是 shared。这是因为页面又需要全局样式,又需要影响其他设置了apply-shared 或 shared 的自定义组件。

不过可以放心的是: 小程序样式隔离是以页面为单位,不会影响全局样式,即使当前页面你有组件使用了以 shared 影响了当前页面。跳转到下一个页面中,不会出现问题。所以我们基本上按照上面的设置即可。

针对于页面级别的 Component 还有几个额外的样式隔离选项可用:

  • page-isolated 表示在这个页面禁用 app.wxss ,同时,页面的 wxss 不会影响到其他自定义组件;
  • page-apply-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式不会影响到其他自定义组件,但设为 shared 的自定义组件会影响到页面;
  • page-shared 表示在这个页面禁用 app.wxss ,同时,页面 wxss 样式会影响到其他设为 apply-shared 或 shared 的自定义组件,也会受到设为 shared 的自定义组件的影响。

基本上这些配置都会让页面上禁用 app.wxss,所以在开发中并不使用。大家如果有需求,可以自行研究。

从小程序基础库版本 2.10.1 开始,也可以在页面或自定义组件的 json 文件中配置 styleIsolation (这样就不需在 js 文件的 options 中再配置)。例如:

{
  "styleIsolation": "isolated"
}

其他样式配置功能

诸如 外部样式类) 和 引用页面或父组件的样式) 这些功能,大家也可酌情学习使用。不过有了组件样式隔离之后,这些功能可能就有些鸡肋,我可以直接通过页面的样式控制组件内部的样式。而且外部样式类功能需要父组件直接提供样式,不会被 app.wxss 所影响。

在样式隔离功能使用的情况下,我们可以大幅度减少各个组件的代码。并且让整个小程序内部更加干净整洁,可重用性更高。同时我们的主题色等全局配置都可以通过修改 app.wxss 来修改。


CSS var 定制主题

var 功能简单描述

如果当年 CSS 预处理器变量对于我来说是开启了新世界的大门,那么 CSS 变量这个功能对于无疑就是晴天霹雳。

// 在 body 选择器中声明了两个变量
body {
  --primary-color: #7F583F;
  --secondary-color: #F7EFD2;
}

/** 同一个 CSS 变量,可以在多个选择器内声明。优先级高的会替换优先级低的 */
.a {
  --primary-color: #FFF;
  --secondary-color: #F4F4F4;
}

/** 使用 CSS 变量 */
.btn-primary {
  color: var(--primary-color)
}

前端的领域中,标准的实现总是比社区的约定要慢的多,前端框架最喜欢的 $ 被 Sass 变量用掉了。而最常用的 @ 也被 Less 用掉了。官方为了让 CSS 变量也能够在 Sass 及 Less 中使用,无奈只能妥协的使用 --。

当然,我们也可以通过 JS 来操作 CSS 变量。如此,CSS 变量可以动态的修改。


// 设置变量
document.body.style.setProperty('--primary', '#7F583F');

// 读取变量
document.body.style.getPropertyValue('--primary').trim();
// '#7F583F'

// 删除变量
document.body.style.removeProperty('--primary');

var 默认配置

事实上,var() 函数还可以使用第二个参数,表示变量的默认值。如果该变量此前没有定义,就会使用这个默认值。如果让我来思考,我肯定无法想象出结合 Less 和 CSS 变量便可以实现小程序样式的默认配置。这里我们参考了有赞的 Vant Weapp 的做法。有赞代码 theme.less 如下所示:

// 先导入所有 less 变量
@import (reference) './var.less';

// 利用正则去替换变量
.theme(@property, @imp) {
  @{property}: e(replace(@imp, '@([^() ]+)', '@{$1}', 'ig'));
  @{property}: e(replace(@imp, '@([^() ]+)', 'var(--$1, @{$1})', 'ig'));
}

函数效果如下所示:

@import '../common/style/theme.less';

.van-button {
  // ... 其他省略
  .theme(height, '@button-default-height');
  .theme(line-height, '@button-line-height');
  .theme(font-size, '@button-default-font-size');
}

// => 编译之后

.van-button{
   // ... 其他省略
  height:44px;
  height:var(--button-default-height,44px);
  line-height:20px;
  line-height:var(--button-line-height,20px);
  font-size:16px;
  font-size:var(--button-default-font-size,16px);
}

我们可以看到每调用一次 Less 函数将会被编译成两个属性。第一个属性的设定对于不支持 CSS 变量的设备可以直接使用,如果当前设备支持 CSS 变量,则会使用 CSS 变量,但是由于当前 css 变量未定义,就会使用变量的默认值。

经过这种函数的修改,我们就可以完成定制主题。详细请参考 Vant Weapp 定制主题

// component.wxml
<van-button class="my-button">
  默认按钮
</van-button>

// component.wxss

.my-button {
  --button-border-radius: 10px;
  --button-default-color: #f2f3f5;
}

大家可能有时候会想,这样的话,不是有更多的代码了吗?其实未必,事实上我们可以直接直接在页面内部定义变量样式。其他组件直接通过样式隔离去使用页面内的变量。当然了,事实上书写的代码多少,重点在于想要控制默认样式的粒度大小。粒度越小,则需要在各个组件内部书写的变量越多,粒度大,我们也就不必考虑太多。

当然了,我们可以基于用户机型提供默认和适合当前机型修改的的样式配置,这样的话。即使用户想要自己定义,也不会出现样式特别怪异的状况。


鼓励一下

如果你觉得这篇文章不错,希望可以给与我一些鼓励,在我的 github 博客下帮忙 star 一下。
博客地址


链接: https://fly63.com/article/detial/8342

微信小程序开发中遇到的坑

开发小程序的过程中踩的坑不可谓不多,而有些坑也实在是让人郁闷,不扒一扒难以平我心头之愤呐。

微信小程序更新机制_微信小程序的2种更新方式

小程序的启动方式:冷启动和热启动,小程序冷启动时,会检查小程序是否有最新版本。如果有则将异步下载最新版本,但是仍将运行当前版本等到下一次冷启动时再运行最新版本。

微信小程序报错Do not have xx handler in current page的解决方法总汇

最近在做小程序开发的时候,发现小程序老是报Do not have xxx handler in current page... 惊不惊喜,意不意外,这是什么原因引起的呢?下面就整排查错误的解决办法。

微信小程序-自动定位并将经纬度解析为具体地址

微信小程序-微信小程序可以通过API获取当前位置的经纬度,在微信小程序开发文档中可以找到这个API的使用示例,但是需要获取具体地址就需要使用到外部的API(此处用到的是腾讯的位置服务)

微信小程序框架推荐_分享好用的小程序前端开发框架

选择优秀的框架,能帮助我们节省开发时间,提高代码重用性,让开发变得更简单。下面就整理关于微信小程序的前端框架,推荐给大家。

微信小程序UI组件、实用库、开发工具、服务端、Demo整理分享

小程序开放至今,许多公司企业已经开发出了自己的小程序。这篇文章主要整理分享:微信小程序UI组件、开发框架、实用库、开发工具、服务端、Demo等

微信小程序实现右侧菜单的功能效果

这篇文章主要讲解微信小程序如何实现 侧边栏滑动 功能 ,首先实现的思路为:wxml页面结构分为2层:侧边栏菜单、正文部分;正文部分监听touchstart、touchmove、touchend触摸事件

微信小程序之程序、页面注册及生命周期

微信小程序生命周期函数:onLoad: 页面加载。onShow: 页面显示每次打开页面都会调用一次。onReady: 页面初次渲染完成,onHide: 页面隐藏,onUnload: 页面卸载。在小程序中所有页面的路由全部由框架进行管理

微信小程序_实现动画旋转的多种方式

三种办法实现小程序的动画效果: 每帧setData()、使用Animation实现旋转效果、使用keyfreams。在wxss中通过控制transform组件的属性,来实现旋转效果,我也是采用的这种方式,性能上面提示非常多

微信小程序Socket的实现_基于socket-io

在小程序进行socket链接的时候发现:在1.7.0版本之前,一个微信小程序同时只能有一个 WebSocket 连接,而且在连接socket的时候,发现在还没有进行subscribe的情况下,就直接进行了广播,并且自动关闭了socket连接。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!