微信小程序-全局字体大小切换方案(处女作)

2,632 阅读3分钟

web 端和小程序设置根元素字体大小区别

在 web 端如果要做全局字体大小切换方案,我们首先会想到用 rem 这样的相对单位来设置字体大小,rem 的原理想必大家都知道的。rem 是响应式的一种,是相对于根元素(即html元素) font-size 计算值的倍数的一个css单位。比如 html 设置字体大小为 16px,那么 2rem 实际大小就是 32 px。这时想做全局字体大小切换,我们只需要动态设置 html 根字号大小,很简单直接设置document.documentElement.style.fontSize = "18px"即可。

html {
  font-size: 16px;
}

p {
  font-size: 2rem;
}

在小程序中,我们也是可以用 rem 单位的,可以在 app.wxss 中给 page 标签设置字号大小,然后在自定义组件中使用方式和 web 端是一致的。但是至今为止,微信小程序官方并未开放 全局动态设置 page 样式的相关 api,或者直接修改 app.wxss 的 方式,因此这个方案在小程序中是行不通的。值得庆幸的是,虽然没有直接设置 page 样式这样的 api,但是官方在版本号 2.9.0 之后,出了 page-meta 这样的页面属性配置方案,其中 root-font-size 就是页面的根字体大小属性。接下来我们就利用这个配置项来完成小程序的方案。

小程序全局字体大小切换具体实施步骤

组件新增 page-meta 配置

这里需要注意 page-meta 标签,必须写在页面的最上面,只能是页面内的第一个节点。

// my-component.wxml
<page-meta root-font-size="{{fontSize}}rpx"></page-meta>
 
  <view class="intro1">组件</view>
  <view class="intro2">组件</view>
  <view class="intro3">组件</view>
// my-component.js
Component({
  /**
   * 组件的初始数据
   */
  data: {
    fontSize: 100,
  },

  pageLifetimes: {
    show: function() {
      console.log("Behavior show 逻辑")
      const fz = wx.getStorageSync('font-size');
      this.setData({
        fontSize: fz
      })
    }
  }
    
  /**
   * 组件的方法列表
   */
  methods: {
   
  }
})

我们试想一下,每个自定义组件中都要给 data 定义一个 fontSize 属性,在生命周期 show 方法中设置 fontSize 熟悉值,也太麻烦了吧?接下来是时候引入混入的概念了

给每个组件新增混入 behaviors

behaviors 是用于组件间代码共享的特性,类似于 vue 中的 mixin。每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 behaviors参考文档

  1. 新增 behavior.js

先在 data 中定义好 fontSize 默认值。如果曾切换过 fontSize,这里就可以用小程序的本地存储功能,类似 web 端的 localStorage ,随后就可以在 生命周期-show (组件展示的时候会执行该函数)方法中重新设置 fontSize 了

module.exports = Behavior({
  data: {
    fontSize: 100, // 默认 100 方便初始化样式代码时好计算
  },
  pageLifetimes: {
    show: function() {
      console.log("Behavior show 逻辑")
      // 这里使用了小程序的本地存储功能
      const fz = wx.getStorageSync('font-size');
      if(fz) {
        this.setData({
          fontSize: fz
        })
      }
    }
  }
})
  1. 在自定义组件使用 behavior
// my-component.js
var myBehavior = require('behavior')
Component({
  behaviors: [myBehavior],

  /**
   * 组件的方法列表
   */
  methods: {
   
  }
})

不过以上步骤,虽然能解决重复定义 fontSize 和 show 的繁琐问题,但每个组件还是都要引入 behavior。我们再想一下,能不能不手动引入,在组件生成的时候自动添加呢?答案是可以的!请接着往下看

改造 Component,自动引入 behavior

下面代码中的 extendComponent 函数,大家是不是看着很熟悉,没错这就是所谓的高阶组件。在 app.js 启动函数中调用

var myBehavior = require('behavior.js')
const OriginalComponent = Component;

/*  扩展原生的 Component,新增 behaviors 属性,避免每个组件都重复写一次*/
function extendComponent(Com) {
  return function (options) {
    options.behaviors = [myBehavior];
    return Com(options);
  };
}

App({
  onLaunch: function () {
    const fz = wx.getStorageSync('font-size');
    if (!fz) {
      wx.setStorageSync('font-size', 100)
    }
    Component = extendComponent(OriginalComponent);
  },

  globalData: {
    
  }
})

至此,主要步骤都介绍完了

注意点:考虑到小程序的 Page 和 Component 配置项是有不同的,我们在定义 page 页面的时候统一用 Component 就可以了。参考链接1 参考链接2