uni-app中动态修改字体大小
最近在一个uni-app的小程序项目要做一个字体大小修改功能,动态切换大字模式,相当于老年模式。由于在小程序中无法直接通过修改根节点下的font-size,在网上搜索了一圈,说可以通过动态设置page-meta下的root-font-size来实现。但由于项目已经写了几十个页面了,在代码各处已经通过text-xx的unocss的预设样式设置好了字体大小,在每个页面中再去添加page-meta侵入太大,也不可能去再去每处设置字体大小的地方修改。经过一番摸索,发现直接通过修改scss下动态变量的方式就可轻松实现。
创建font-base
主要配置便是在unocss.config.js中添加test-xx到rules,用于动态替换默认预设的text-xx的字体大小样式:
import { defineConfig } from 'unocss'
import transformerDirectives from '@unocss/transformer-directives'
import presetWeapp from 'unocss-preset-weapp'
import { presetShades } from '@viarotel-org/unocss-preset-shades'
import { presetUni } from '@uni-helper/unocss-preset-uni'
import { primaryColor } from '@/configs'
const presetMain = presetUni({ attributify: false })
const presets = [
presetMain,
presetShades(primaryColor),
]
const transformers = [ transformerDirectives() ]
const rules = []
presets.push(presetWeapp({
transform: true
}))
const arr = [
... 关键配置...
[ /^text-(\d+)$/, ([ , d ]) => ({ 'font-size': `calc(var(--font-base) * ${d / 10})` }) ],
]
rules.push(...arr)
export default defineConfig({
theme: {
colors: {
primary: 'var(--primary-color, #FFA011)',
},
},
presets,
transformers,
rules,
shortcuts: {
'text-title': 'font-bold text-16 text-grey-222',
},
})
在rules中添加 [ /^text-(\d+)$/, ([ , d ]) => ({ 'font-size': calc(var(--font-base) * ${d / 10})}) ]
规则,表示将text-xx后面的数字*10来变更字体的大小。如text-12即表示font-size:var(--font-base)*1.2
,text-16即表示font-size:var(--font-base)*1.6
, 这样就不用修改原页面中通过text-12或text-16设置的样式了,只用动态修改–font-base的大小即可。
添加–font-base
–font-base即这里面的基准字体大小,可以在App.vue下预设,如:
page {
:root {
--font-base: 10px;
/* H5基准 */
}
@media (platform: mp-weixin) {
:root {
--font-base: 20rpx;
/* 小程序基准 */
}
}
}
这里设置了 --font-base为10px,在小程序下设为20rpx,具体可以参照UI设计稿尺寸,以便直接使用设计稿上字体大小,由于这里参照的UI设计稿使用的375px的尺寸,故直接设置为10px和20rpx,这样在设计稿上为16px大小字体直接使用text-16即可。
动态修改–font-base
最关键的步骤便是如何动态修改这里的–font-base了。通过前面两步已经预设了字体大小,现在要动态修改字体大小来实现切换老年模式即可。但小程序中没有document节点,无法直接通过document.documentElement.style.setProperty('--font-base', size)
的方式来修改。这里只有折中在每个页面的根节点里添加一个style='--font-base:30rpx'
来实现动态修改。但由于每个页面都这样的样式太麻烦,也无法动态修改。我们可能封装一个base-page的组件来包裹,并使用vuex或pinia来实现状态管理即可。完整代码如下:
import { defineStore } from 'pinia'
import storage from '@/utils/storages'
export const useAppStore = defineStore({
id: 'app',
state () {
return {
themeConfig: storage.get('app/themeConfig') || {
fontBaseSize:'20rpx',
},
}
},
getters: {
fontBaseSize: state => state.themeConfig?.fontBaseSize,
},
actions: {
updateFontBaseSize (size) {
this.themeConfig.fontBaseSize = size
storage.set('app/themeConfig', this.themeConfig)
},
})
封装base-page:
<template>
<view class="page" :style="styles">
<slot></slot>
</view>
</template>
<script setup>
import { useAppStore } from '@/store/app'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
const appStore = useAppStore()
const { fontBaseSize } = storeToRefs(appStore)
const styles = computed(() => [
{ '--font-base': fontBaseSize.value },
])
</script>
<style lang="scss" scoped></style>
然后在页面中的根节点直接使用base-page即可:
<template>
<base-page class="w-full flex-col">
<view class="w-full row justify-between items-center">
<view class="flex-1">
<text>老年模式</text>
</view>
<view class="row items-center">
<uv-switch @change="clickFontMode"></uv-switch>
</view>
</view>
</base-page>
</template>
<script setup>
import { useAppStore } from '@/store/app'
const appStore = useAppStore()
const clickFontMode = v => {
appStore.updateFontBaseSize(v ? ‘30rpx’ : '20rpx')
}
</script>
<style lang="scss" scoped></style>
可直接预设大字模式下的字体大小,也可通过滑块动态改变。