【uniapp/nvue/js】nvue中 实现文本两端对齐效果 的 js解决方案
js代码实现在nvue中 文本两端对齐效果前言在你因为搜索关键词来到我这篇文章时,相信你已经深深的感受到nvue格式对样式编写的局限性了。比如,在nvue中不能用text-align:justify设置文本两端对齐。本人发现这个样式不能使用后,思考了许多代替解决的方法。但最终却发现,这个nvue吧,简直是把css两端对齐的方法全堵死了!text-align:justify不能用,letter-sp
nvue中 实现文本两端对齐效果 的 js解决方案
一、 前言
在你因为搜索关键词来到我这篇文章时,相信你已经深深的感受到nvue格式对样式编写的局限性了。
比如,在nvue中不能用text-align:justify设置文本两端对齐。
本人发现这个样式不能使用后,思考了许多代替解决的方法。但最终却发现,这个nvue吧,简直是把css两端对齐的方法全堵死了!text-align:justify不能用,letter-spacing 改字间距也不能用。
可是吧,需求又有这个需求,也不能不做不是?
毕竟俺们上面某位对这种小细节很有强迫症,我们之前也都简简单单解决了,所以这次,人家不是技术哪管咱们到这个nvue格式下是真的干啥啥不行了。
因为在网上也找不到什么解决的方法,所以本着没有粮食就要自己动手才能丰衣足食的观念,本人根据nvue能使用的css条件,用js写了一个算法,从理清思路,到编写逻辑代码,这篇代码用了一天多。虽然这件事很吃力不讨好,代码写得也比较稚嫩,但是本人在这个过程中还是感觉收获良多的。(一定程度锻炼了思维逻辑能力)
而且这样也算有了个备选方案,不至于感觉无计可施。
以下会记录本人写下这篇代码的所有思路历程。有兴趣的同学可以看完我这些思路历程,一起进步~~ 比较赶时间的同学,就跳到结尾看代码和使用方法吧。
二、思路历程
1.确定可用条件并构思
首先,我们知道nvue格式是只能使用flex布局,即display属性仅能为flex,且默认 flex-direction: column
。text-align:justify、letter-spacing不能使用,但是flex布局的justify-content: space-between
确定能使用。
justify-content: space-between
可以均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点 。 根据属性描述,这不就是有 '两端对齐’的概念在吗?
所以我就想到,能不能根据用这个属性去写一下算法呢?
根据条件,我的脑子生成了一个基本构思。
核心逻辑其实比较简单,也就是 将文本里的字符拆分成独立的块 用justify-content: space-between
让字符在父盒子里自适应两端对齐。
可以用这段简单的试验代码理解。
// template
<view class="box" >
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
<text>这</text>
</view>
// style
.box {
flex-direction: row;// nvue 默认 lex-direction: column,所以一定要改方向
flex-wrap: wrap;
width: 100rpx;
justify-content: space-between;
background-color: red;
}
确定思路,开始延展。
2.延展思路,编写逻辑,逐步优化
①将所有获取的文本拆分 splitLine()
//template
<view class="body">
<view class="box" v-for="(item,index) in newText">
<view v-for="it in item">
<text>{{it}}</text>
</view>
</view>
</view>
// style
.box{
flex-direction: row;
flex-wrap: wrap;
width: 200rpx;//需要手动调试,匹配宽度和合适的字符数
justify-content: space-between;
}
// script
export default {
data() {
return {
dataText: [
'这是什么呀?我完全看不到',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq,老师你手机啊喜欢过的卡号',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq,老师你手机啊喜欢过的卡号11111',
],
newText: []
}
},
onLoad() {
this.splitLine()
},
methods: {
splitLine() {
var that = this
this.dataText.forEach((v, i) => {
//设定一行的字符数line_num=10,定该文本的字符数为 word_num
//(需要手动调出合适当前父文本宽度的字符数)
var word = v.split('')
var word_num = v.split('').length
var line_num=10
var newWord=[]
if (word_num < line_num) {
//1.字符内容不到一行字符串不拆分
newWord[0]=v
that.newText[i] =newWord
} else if ((word_num % line_num) < line_num) {
//2.字符内容大于一行,但末行的字符少于一行字符 则需要截取前面字符串拆分,将多余字符截取为数组最后元素
var newWord = v.substring(0, word_num - (word_num % line_num)).split('')
var endWord = v.substring(word_num - (word_num % line_num), word_num)
newWord.push(endWord)
that.newText[i] = newWord
} else {
//3.字符内容大于一行且末行字符等于一行,全字符拆分即可
that.newText[i] = word
}
})
},
}
}
但是,实践后发现,只判断字符数来拆分,会因为中文与英文和数字的字符位置占据大小不一样,导致出现每行字间距之间差异很大的情况,所以我们应该是去判断字节数而不是字符数
②优化判断思路,用 <计算字节> 替代 <计算字符> 判断
一段文本里可能会包含英文、数字、中文等,要根据文本内容去计算字节数,首先要理解字节概念。
前端主要为UTF-8编码,则字符串中的字节数,单个的字符,包括英文字符,数字,特殊字符(不包含emoji)等是一个字节,中文的汉字是两个字节。
//将是中文的部分,替换成两个英文,这样字节就全部都是普通的字节了,此时字节的长度就是字符串的长度。
getBytesLength(str) {
return str.replace(/[^\x00-\xff]/g, 'xx').length;
},
所以我将之前的代码用字节思维再优化下,写了第一版的 splitBytesLine()
(需要手动调出合适当前父文本宽度的字节数 byte ,就是合适的中文字符数 * 2)
splitBytesLine(arr,byte) {
//参数说明:arr为原文本数组,byte设定每行的合适字节数
var that = this
var newTextArr=[]
arr.forEach((v, i) => {
//计算字符串的字节数
var bytes_num = this.getBytesLength(v)
//将字符串拆分成数组
var word = v.split('')
//定义处理后的数组存放容器
var newWord=[]
//根据文本字节对于单行字节数的情况处理
if (bytes_num < byte) {
// 字节不到一行情况,不拆分,字符串全部存入数组
console.log('字节不到一行情况')
newWord[0]=v
newTextArr[i] = newWord
} else if ((bytes_num % byte) < byte) {
// 字节有多行,并且最后一行不足一行字节
console.log('字节有多行,并且最后一行不足一行字节')
var word_num = v.split('').length
// 先假设字节余数ys为偶数6 (带上具体数据更好理解,小括号有写上公式)
// 截取最后同余数ys同数的(6)字符计算字节,设为e
// 1.if e=6 (e=ys),即最后字符皆为非中文字符,则截取文本 0至 word_num-ys【6】 拆分为数组,剩余字符串(6个字符)不拆分push进数组
// 2.if e=12 (e=ys*2),即最后字符皆为中文字符,则截取文本 0至 word_num-(ys/2) 【3】 拆分为数组,剩余字符串(3个字符)不拆分push进数组
// 3.if 6<ys<12 (ys<e<ys*2),即最后字符有中文字符和非中文字符,
// ① e%2为 0是偶数(8),截取文本 最后 e/2 的字符计算字节e2,if e2=ys,则截取文本0至 最后e/2; if e2<ys,截取word_num-(e/2 + 1) 至 word_num-(e/2 )字符计算字节k ==>> 如果k+e2>= ys,最终就截取文本 0至 word_num-(e/2 + 1) 拆分为数组,剩余字符串(e/2 + 1个字符)不拆分push进数组;
// 如果k+e2<ys,则继续截取word_num-(e/2 + 2) 至 word_num-(e/2 + 1)字符计算字节k2,直到(k+k2+...+kn)+e/2 >= ys,停止循环;
// if e2>ys,就截取 word_num-e/2至 word_num-(e/2 - 1)字符计算字节k ==> 如果 e2-k<=ys,就截取文本 0 至 word_num-(e/2 - 1),如果e2-k>ys 就继续截取word_num-(e/2 -1) 至 word_num-(e/2 - 2)字符计算字节k2,直到e/2 -(k+k2+...+kn) <= ys,停止循环;
// ② e%2为 1是偶数(9),截取文本 最后 e/2 +1 的字符计算字节e2,重复操作.
// 计算字节余数
var ys = bytes_num % byte
// 截取同字节余数数的最后字符
var jq = v.substring(word_num - ys, word_num)
// 计算最后字符的字节
var e = this.getBytesLength(jq)
if (e == ys) {
// 最后字符全是非中文字符情况
console.log('最后字符全是非中文字符情况')
var newWord = v.substring(0, word_num - ys).split('')
var endWord = v.substring(word_num - ys, word_num)
newWord.push(endWord)
newTextArr[i] = newWord
} else if (e == (ys * 2) ) {
// 最后字符全是中文字符情况
console.log('最后字符全是中文字符情况')
var newWord = v.substring(0, word_num - (ys / 2)).split('')
var endWord = v.substring(word_num - (ys / 2), word_num)
newWord.push(endWord)
newTextArr[i] = newWord
} else {
// 最后字符有中文字符和非中文字符情况
console.log('最后字符有中文字符和非中文字符情况')
if (e % 2) {
console.log('字节数为偶数情况')
// 字节数为偶数情况 // 目的:获取匹配余数ys的实际最后字符数截取文本,为优化效率,从中间截取左右加减,直到 ±k+e/2=ys
let jq2 = v.substring(word_num - (e / 2), word_num)
console.log(jq2)
var e2 = that.getBytesLength(jq2)
} else {
// 字节数为奇数情况
console.log('字节数为奇数情况')
let jq2 = v.substring(word_num - (e / 2)-1, word_num)
console.log(jq2)
var e2 = that.getBytesLength(jq2)
}
// 匹配最后字节的字符情况
if (e2 < ys) {
// 中位数值小于目标余数ys值,需要向左做加法
// 计算左边第一个单字符的字节
let jq3 = v.substring(word_num - (e / 2) - 1, word_num - (e / 2))
var k = that.getBytesLength(jq3)
// 逐步循环左边单字符并加上其字节数,直到字节数=余数ys,停止循环
for (let i = 1; i < (e / 2) + 1; i++) {
if (k + e2 >= ys) {
var newWord = v.substring(0, word_num - (e / 2) - i + 1).split('')
var endWord = v.substring(word_num - (e / 2 + i - 1), word_num)
break
} else {
let jq4 = v.substring(word_num - (e / 2) - i, word_num - (e / 2) - i + 1)
k = k + that.getBytesLength(jq4)
}
}
} else if (e2 > ys) {
// 中位数值大于目标余数ys值,需要向右做减法
// 计算右边第一个单字符的字节
let jq3 = v.substring(word_num - (e / 2), word_num - (e / 2) + 1)
var k = that.getBytesLength(jq3)
// 逐步循环右边单字符并减去其字节数,直到字节数=余数ys,停止循环
for (let i = 1; i < (e / 2) + 1; i++) {
if (e2 - k >= ys) {
var newWord = v.substring(0, word_num - (e / 2) + i + 1).split('')
var endWord = v.substring(word_num - (e / 2) + i + 1, word_num)
break
} else {
let jq4 = v.substring(word_num - (e / 2) + i, word_num - (e / 2) + i + 1)
k = k - that.getBytesLength(jq4)
}
}
} else {
var newWord = v.substring(0, word_num - (e / 2)).split('')
var endWord = v.substring(word_num - (e / 2), word_num)
}
newWord.push(endWord)
newTextArr[i] = newWord
}
} else {
// 字节有多行,且最后一行字节正好满一行,直接拆分成数组
console.log('字节有多行,且最后一行字节正好满一行,直接拆分成数组')
newTextArr[i] = word
}
})
return newTextArr
}
目前的算法可实现包含中文、英文、数字和*&%等特殊字符的文本两端对齐效果。
三、第一版算法的使用指南
①复制上面 splitBytesLine(),getBytesLength()方法到methods里。
②dataText 存放原文本,一个段落是一个数组元素。newTextDate 存放处理后的数组。调用方法,转换数据。
//template
data() {
return {
dataText: [
'这是什么呀?我完全看不到',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq,老师你手机啊喜欢过的卡号',
'这是什么呀?我完全看不到,好奇怪啊qwqwqwqwqwqwqwqwqwqwq,老师你手机啊喜欢过的卡号11111',
],
newTextDate: []
}
},
onLoad() {
this.newTextDate=this.splitBytesLine(this.dataText,34)
//参数说明:(原文本数组,每行的合适字节数)
},
③html嵌套两层for,外层循环段落,内层循环段落里的每一个文字。
//template
<view class="body">
<view class="box" v-for="(item,index) in newText">
//循环段落
<view v-for="it in item">
//循环文字
<text>{{it}}</text>
</view>
</view>
</view>
④写上必填样式
// style
.box{
flex-direction: row;
flex-wrap: wrap;
width: 298rpx;//需要手动调试,匹配宽度和合适的字符数
justify-content: space-between;
}
因为写的文章跨了几天时间,写法很稚嫩,文章中的一些代码可能大概会出现匹配不上还是啥bug的情况,如果发现文章有问题或者有大佬想指导建议俺都非常欢迎嗷~
然后其实我已经写了第二版的算法,代码也越来越长了 ,可以兼容多了些情况 ,并封装起来用了,但是写成文章真的太麻烦了 ,不过后续我还是会继续更新的~
————————————————————————————————————————————————————————
第二版本算法
来了来了,我终于来更新了
第二版算法,新增可支持第一行字数不同的情况(用于第一行缩进两格之类的需求)
function splitBytesLine(arr, byte_one, byte) {
//参数说明:arr为原文本数组,byte_one设定第一行字节数,byte设定每行的合适字节数
var newText = []
arr.forEach((v, i) => {
var bytes_num = v.replace(/[^\x00-\xff]/g, 'xx').length
var word = v.split('')
var middle = 0
var newWord = []
var startWord = []
var word_num = v.split('').length
if (bytes_num > byte_one) {
// 兼容第一行特殊化情况
console.log("兼容第一行特殊化情况")
var jq = v.substring(0, byte_one)
// 计算最前byte_one个字符的字节
var e = jq.replace(/[^\x00-\xff]/g, 'xx').length
console.log(e)
console.log(jq)
if (e == byte_one) {
// 最前字符全是非中文字符情况
console.log("最前字符全是非中文字符情况")
startWord[0] = v.substring(0, byte_one - 1)
startWord[1] = v.substring(byte_one - 1, byte_one)
var middle = byte_one
} else if (e / 2 == byte_one) {
// 最前字符全是中文字符情况
console.log("最前字符全是中文字符情况")
startWord[0] = v.substring(0, byte_one / 2 - 1)
startWord[1] = v.substring(byte_one / 2 - 1, byte_one / 2)
var middle = byte_one / 2
} else {
console.log("最前字符有中文字符和非中文字符情况")
// 最前字符有中文字符和非中文字符情况
// 前byte_one个字符的字节大于byte_one,需要向左做减法
// 计算左边第一个单字符的字节
let jq3 = v.substring(byte_one - 1, byte_one)
var k = jq3.replace(/[^\x00-\xff]/g, 'xx').length
for (let i = 1; i < byte_one + 1; i++) {
if ((e - k) <= byte_one) {
startWord[0] = v.substring(0, byte_one - i - 1)
// startWord[1] = ''
startWord[1] = v.substring(byte_one - i - 1, byte_one - i)
var middle = byte_one - i
break
} else {
let jq4 = v.substring(byte_one - i - 1, byte_one - i)
k = k + jq4.replace(/[^\x00-\xff]/g, 'xx').length
}
}
}
}
console.log(startWord)
if (startWord.length) {
newWord = newWord.concat(startWord)
}
console.log(newWord)
var middleWord = []
var endWord = ''
if (bytes_num <= byte_one) {
console.log('字节不到一行情况')
newWord[0] = v
newText[i] = newWord
} else if (bytes_num < (byte_one + byte)) {
// 字节不到两行情况
console.log("字节不到两行情况")
endWord = v.substring(middle, word_num)
newWord.push(endWord)
newText[i] = newWord
} else if (((bytes_num - byte_one) % byte) < byte) {
// 字节有多行,并且最后一行不足一行字节
console.log("字节有多行,并且最后一行不足一行字节")
// 计算字节余数
var ys = (bytes_num - byte_one) % byte
console.log("余数", ys)
// 截取同字节余数数的最后字符
var jq = v.substring(word_num - ys, word_num)
// 计算最后字符的字节
var e = jq.replace(/[^\x00-\xff]/g, 'xx').length
if (e == ys) {
// 最后字符全是非中文字符情况
console.log("最后字符全是非中文字符情况")
var middleWord = v.substring(middle, word_num - ys).split('')
var endWord = v.substring(word_num - ys, word_num)
} else if (e == (ys * 2)) {
// 最后字符全是中文字符情况
console.log("最后字符全是中文字符情况")
var middleWord = v.substring(middle, word_num - (ys / 2)).split('')
var endWord = v.substring(word_num - (ys / 2), word_num)
} else {
// 最后字符有中文字符和非中文字符情况
console.log("最后字符有中文字符和非中文字符情况")
if (e % 2) {
console.log("字节数为偶数情况")
// 字节数为偶数情况 // 目的:获取匹配余数ys的实际最后字符数截取文本,为优化效率,从中间截取左右加减,直到 ±k+e/2=ys
let jq2 = v.substring(word_num - (e / 2), word_num)
var e2 = jq2.replace(/[^\x00-\xff]/g, 'xx').length
} else {
// 字节数为奇数情况
console.log("字节数为奇数情况")
let jq2 = v.substring(word_num - (e / 2) - 1, word_num)
var e2 = jq2.replace(/[^\x00-\xff]/g, 'xx').length
}
// 匹配最后字节的字符情况
if (e2 < ys) {
// 中位数值小于目标余数ys值,需要向左做加法
// 计算左边第一个单字符的字节
let jq3 = v.substring(word_num - (e / 2) - 1, word_num - (e / 2))
var k = jq3.replace(/[^\x00-\xff]/g, 'xx').length
// 逐步循环左边单字符并加上其字节数,直到字节数=余数ys,停止循环
for (let i = 1; i < (e / 2) + 1; i++) {
if (k + e2 >= ys) {
var middleWord = v.substring(middle, word_num - (e / 2) - i + 1).split('')
var endWord = v.substring(word_num - (e / 2 + i - 1), word_num)
break
} else {
let jq4 = v.substring(word_num - (e / 2) - i, word_num - (e / 2) - i + 1)
k = k + jq4.replace(/[^\x00-\xff]/g, 'xx').length
}
}
} else if (e2 > ys) {
// 中位数值大于目标余数ys值,需要向右做减法
// 计算右边第一个单字符的字节
let jq3 = v.substring(word_num - (e / 2), word_num - (e / 2) + 1)
var k = jq3.replace(/[^\x00-\xff]/g, 'xx').length
// 逐步循环右边单字符并减去其字节数,直到字节数=余数ys,停止循环
for (let i = 1; i < (e / 2) + 1; i++) {
if (e2 - k >= ys) {
var middleWord = v.substring(middle, word_num - (e / 2) + i + 1).split('')
var endWord = v.substring(word_num - (e / 2) + i + 1, word_num)
break
} else {
let jq4 = v.substring(word_num - (e / 2) + i, word_num - (e / 2) + i + 1)
k = k - jq4.replace(/[^\x00-\xff]/g, 'xx').length
}
}
} else {
var middleWord = v.substring(middle, word_num - (e / 2)).split('')
var endWord = v.substring(word_num - (e / 2), word_num)
}
}
newWord = newWord.concat(middleWord)
newWord.push(endWord)
newText[i] = newWord
} else {
// 字节有多行,且最后一行字节正好满一行,直接拆分成数组
console.log("字节有多行,且最后一行字节正好满一行,直接拆分成数组")
newText[i] = word
}
})
console.log(newText)
return newText
}
不过但是发现写着写着有点鸡肋,就又换了一个思路去写
最终版
更多推荐
所有评论(0)