最近项目新加了个需求,系统文字从接口获取。如登录页面标题,和系统标题。其中发现遇到了一个问题。文字背景是一张图片,图片是自适应缩放的,所以可适应文字的宽度只能是按比列。所以能想到的办法就是标题文字随着外层的宽度变化,字体也跟着变化,显示完整的标题文字。
以下方法可以获取文字长度 放入utils文件夹中
const FontUtils = {
// 获取字符串总长度[半角算0.5]
getStringLength: (content) => {
if (!content) return 0
const regExALL = /[^\x00-\xff]/g
const regExHalf = /[\x00-\xff]/g
// 全角
const allAngle = content.match(regExALL)
// 半角
const halfAngle = content.match(regExHalf)
// 总长度
return Math.ceil(((halfAngle ? halfAngle.length : 0) * 0.5) + (allAngle ? allAngle.length : 0))
},
// 单行最大字数(totalSize:不带换行符的总字数)
getMaxWordsPerLine: (totalSize) => {
return Math.ceil(Math.sqrt(2 * totalSize))
},
// 计算总行数(totalSize:总字数,maxWordsPerLine:每行最大文字个数)
getLineNum: (totalSize, maxWordsPerLine) => {
// return Math.ceil(maxWordsPerLine / 2)
return Math.ceil(totalSize / maxWordsPerLine)
},
// 计算字号(width:屏幕宽度,maxWordsPerLine:每行最大字数)
getFontSize: (width, height, maxWordsPerLine) => {
// 设置字体 为了字体更好看不超出,默认再减2
const fontSize = Math.floor(width / maxWordsPerLine * 0.96)
if (fontSize > height) {
return Math.floor(height * 0.96)
}
return fontSize
},
// 计算行高(height:屏幕高度,lineNum:行数)
getLineHeight: (height, lineNum) => {
return Math.floor(height / lineNum)
}
}
export default FontUtils
封装文字宽度组件,其中登录的文字后边有图片,并且是可以居中的状态,所以图片也封装到组件。
当页面宽度变化的时候文字也会跟着变化。
<template>
<div id="headerText" class="headerText">{{ title }}<img
v-if="img&&show"
class="img"
src="../../assets/img/SMOOTH .png"
alt=""
></div>
</template>
<script>
import FontViewUtils from '@/utils/FontViewUtils'
import getPageTitle from '@/utils/get-page-title'
export default {
name: 'HeaderText',
props: {
size: {
type: Number,
default: 0
},
img: {
type: Boolean,
default: false
}
},
data() {
return {
textWidth: '',
textlength: '',
ResizeObserver: '',
title: this.$store.getters.title,
show: false
}
},
mounted() {
this.getTitle()
},
beforeDestroy() {
// 销毁时消除元素的尺寸监听
this.ResizeObserver.disconnect()
},
methods: {
async getTitle() {
if (this.img) {
this.title = await getPageTitle()
}
this.$nextTick(() => {
this.autoFontSize()
})
},
autoFontSize() {
const el = document.getElementById('headerText')
this.textlength = FontViewUtils.getStringLength(this.title)
this.textWidth = this.textlength * this.size
let boxWidth = document.getElementById('headerText').offsetWidth
this.compileWidth(this.textWidth, boxWidth)
this.addResizeListen(el, this.debounce((entries) => {
const width = entries[0].contentRect.width
this.compileWidth(this.textWidth, width)
}, 500))
},
compileWidth(textWidth, boxWidth) {
const el = document.getElementById('headerText')
if (this.img) {
boxWidth = boxWidth - 147
this.show = true
}
if (textWidth > boxWidth) {
el.style.fontSize = Math.floor(boxWidth / this.textlength) + 'px'
el.style.height = Math.floor(boxWidth / this.textlength) + 'px'
} else {
el.style.fontSize = this.size + 'px'
el.style.height = this.size + 'px'
}
},
// 监听尺寸变化
addResizeListen(dom, callback) {
this.ResizeObserver = new ResizeObserver(entries => {
if (callback) callback(entries)
})
this.ResizeObserver.observe(dom)
},
// 防抖
debounce(func, wait) {
let timer
return function() {
const context = this // 注意 this 指向
const args = arguments // arguments中存着e
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
}
}
</script>
<style lang="scss" scoped>
.headerText {
width: 100%;
margin: 0 auto;
font-family: 'FZMHK';
font-size: 0px;
background-image: linear-gradient(to bottom, #2088df, #23a8df);
-webkit-background-clip: text; /* 背景被裁剪成文字的前景色 */
-webkit-text-fill-color: transparent; /* 文字填充颜色变透明 */
letter-spacing: -1.6px;
display: flex;
justify-content: center;
// align-items:baseline;
.img {
width: 117px;
height: 15px;
margin-left: 30px;
align-self: flex-end;
}
}
</style>