vue2自定义指令实现文字缩放
前言
当前指令根据浏览器的不同,可缩放到的最小fontsize不同,以浏览器Chrome118+版本为例,谷歌已关闭最小字体大小默认更改,故字体在此环境下可缩放至0px。对于其他浏览器,可以根据需要添加判断,当内容缩放到一定程度后还是溢出, 则可考虑缩略或scale缩放等实现兼容。
一、指令使用方法
通过v-common-table-adaptest绑定至html标签,值为默认字体的大小(即字体开始缩放的大小如’17’),注意需要给绑定的标签设置宽度
<div v-common-table-adaptest="'17'" class="text-wrap">
{{ text ? text : '请在下方输入框输入内容' }}
</div>
import Vue from 'vue';
//自定义指令
const commonTableAdaptest = {
update(el, binding) {
Vue.nextTick(() => {
adjustFontSize(el, binding.value);
});
},
bind(el, binding) {
Vue.nextTick(() => {
adjustFontSize(el, binding.value);
});
}
};
function adjustFontSize(el, fontSize) {
// 更新前先初始化,避免已缩小的内容,更改text后无法还原
el.style.fontSize = fontSize + 'px';
// 获取DOM样式
let computedStyle = window.getComputedStyle(el);
let paddingLeft = parseFloat(computedStyle.paddingLeft);
let paddingRight = parseFloat(computedStyle.paddingRight);
// 计算el的内容宽度
let elInnerWidth = el.clientWidth - paddingLeft - paddingRight;
let textContent = el.textContent || el.innerText;
let currentFontSize = parseFloat(computedStyle.fontSize);
let fontFamily = computedStyle.fontFamily;
// 借助canvas获取文本宽度
const getTextWidth = (text, fontSize, fontFamily) => {
// 创建canvas元素
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// 设置字体样式,包括字体大小和字体系列
context.font = `${fontSize}px ${fontFamily}`;
// 测量文本宽度
const metrics = context.measureText(text);
return metrics.width;
};
let textWidth = getTextWidth(textContent, currentFontSize, fontFamily);
while (textWidth > elInnerWidth && currentFontSize > 0) {
currentFontSize -= 1;
textWidth = getTextWidth(textContent, currentFontSize, fontFamily);
}
el.style.fontSize = currentFontSize + 'px';
}
思路:dom加载、更新时都重新计算dom的宽度和dom里文本的宽度,当文本宽度大于dom宽度时则将dom的字体大小减1px,直至dom宽度大于文本宽度或字体大小为0时结束。其中计算文本宽度时使用canvas协助计算,降低性能损耗。
二、使用步骤
1.完整demo
代码如下(示例):
<template>
<div class="container">
<div v-common-table-adaptest="'17'" class="text-wrap">
{{ text ? text : '请在下方输入框输入内容' }}
</div>
<div style="margin-top: 20px">
<input v-model="text" placeholder="在此输入文本内容" type="text" />
</div>
</div>
</template>
<script>
import Vue from 'vue';
//自定义指令
const commonTableAdaptest = {
update(el, binding) {
Vue.nextTick(() => {
adjustFontSize(el, binding.value);
});
},
bind(el, binding) {
Vue.nextTick(() => {
adjustFontSize(el, binding.value);
});
}
};
function adjustFontSize(el, fontSize) {
// 更新前先初始化,避免已缩小的内容,更改text后无法还原
el.style.fontSize = fontSize + 'px';
// 获取DOM样式
let computedStyle = window.getComputedStyle(el);
let paddingLeft = parseFloat(computedStyle.paddingLeft);
let paddingRight = parseFloat(computedStyle.paddingRight);
// 计算el的内容宽度
let elInnerWidth = el.clientWidth - paddingLeft - paddingRight;
let textContent = el.textContent || el.innerText;
let currentFontSize = parseFloat(computedStyle.fontSize);
let fontFamily = computedStyle.fontFamily;
// 借助canvas获取文本宽度
const getTextWidth = (text, fontSize, fontFamily) => {
// 创建canvas元素
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// 设置字体样式,包括字体大小和字体系列
context.font = `${fontSize}px ${fontFamily}`;
// 测量文本宽度
const metrics = context.measureText(text);
return metrics.width;
};
let textWidth = getTextWidth(textContent, currentFontSize, fontFamily);
while (textWidth > elInnerWidth && currentFontSize > 0) {
currentFontSize -= 1;
textWidth = getTextWidth(textContent, currentFontSize, fontFamily);
}
el.style.fontSize = currentFontSize + 'px';
}
export default {
directives: {
'common-table-adaptest': commonTableAdaptest // 注册自定义指令
},
name: 'test',
data() {
return {
text: ''
};
},
methods: {},
created() {},
mounted() {}
};
</script>
<style scoped>
.container {
padding: 20px;
}
.text-wrap {
padding: 10px;
display: inline-block;
background-color: rgb(74, 223, 228);
width: 180px;
line-height: 40px;
white-space: nowrap;
font-size: 17px;
}
</style>
总结
当前指令只考虑了可以无限缩小的情况,如下其他场景后面陆续再补
1.缩放到一定大小字体后字体缩略(…)
2.浏览器不支持无限缩放,缩放到一定大小时(如12px)使用scale属性兼容
实现方法有很多哈,上述仅做参考,有问题的地方欢迎指正,有更好的方法欢迎指导哈~