Javascript 常用封装(二)
1.字符串占位宽度
- 计算占位宽度:字符串的占位宽度除了涉及到具体的字符串内容,还与字体大小有关,可以将其放入Dom中来获取实际占位宽度
//计算字符串的占位宽度
function getTextWidth(str = '',font_size=12) {
const dom = document.createElement('span')
dom.style.display = 'inline-block'
dom.style['font-size'] = font_size + 'px'
dom.textContent = str
document.body.appendChild(dom)
const width = dom.clientWidth
document.body.removeChild(dom)
return width;
}
//计算字符串数组中的最大宽度
function getMaxWidthByArray(text_arr=[],font_size=12){
//计算设备编号占位的最大宽度
var max_width = 0
text_arr.forEach(function(str){
var now_text_width = getTextWidth(str,font_size)
if(now_text_width > max_width){
max_width = now_text_width
}
})
return max_width
}
2.树形对象转换
- 由来:多层级数据在存储时,是每个数据平级存储,通过id与pid字段进行进行关联,后台返回这些数据时,可能没经过转换,直接以数组形式返回,前端需要自己转换成树形对象
<script>
//封装方法:一维数组转树形对象
function buildTree(array, id = "id", parent_id = "pid") {
//不是数组则返回
if (!Array.isArray(array)) {
return []
}
// 创建临时对象
let temp = {};
// 创建需要返回的树形对象
let tree = {};
// 先遍历数组,将数组的每一项添加到temp对象中
for (let i in array) {
temp[array[i][id]] = array[i];
}
// 遍历temp对象,将当前子节点与父节点建立连接
for (let i in temp) {
// 判断是否是根节点下的项
if (temp[i][parent_id] !== 0) {
//是否存在该父节点 存在才添加
if (temp[temp[i][parent_id]]) {
//父节点是否已经存在children属性 没有则新建
if (!temp[temp[i][parent_id]].children) {
temp[temp[i][parent_id]].children = new Array()
}
temp[temp[i][parent_id]].children.push(temp[i])
}
} else {
tree[temp[i][id]] = temp[i];
}
}
return tree;
}
</script>
<script>
//待转换的数据格式
var menu_list = [
{
id: 1,
pid: 0,
title: "一级菜单"
},
{
id: 2,
pid: 1,
title: "二级菜单A"
},
{
id: 3,
pid: 1,
title: "二级菜单B"
}
]
//转换
var menu_tree = buildTree(menu_list, "id", "pid")
console.log(menu_tree)
</script>
-
思路解析:
1.函数假定条件:根节点id必须是0,也就是说一级节点的pid要==0
2.先假设所有节点都是一级节点,设置临时对象进行存储,然后遍历临时对象中的key,将其挂载到对应的pid中
3.遍历临时对象的节点,如果父节点是0,则添加到目标树形对象中,如果不是,则添加到对应的pid中(重要!!!,表面是给一级属性赋值,其实因为引用的关系,可能操作的是更深层次的节点)
4.返回目标树形对象(没有找到pid的节点数据将被丢失) -
总结:正常的思路,都是操作树形对象,给所有的节点找到对应的pid节点进行挂载,因为pid是多层次嵌套的,为了找到对应的pid,通常所需要递归遍历,但是这里非常聪明,利用对象是引用类型的机制,直接操作一级节点来代替多层次嵌套节点
3.数字转换为金额格式
- 使用toLocaleString()可将小数转成金额格式
- 注意,如果是整数,需要转换成小数才能调用toLocaleString()
var num = 123456789
//转换成小数
num = parseFloat(num)
//转换金额格式
num.toLocaleString() //'123,456,789'
- 封装一个方法:将数字的每个字符拆开遍历(从后往前)重新拼接,遇到第3*n个字符且不是最后一个字符,则额外多输出一个","
<script>
function numForamt(nun){
//转换成字符串,在转换成数组
var arr = (nun + '').split('')
//要输出的结果
var result = ""
//遍历数组元素,从后面开始,每3个元素就添加一个 ","
for(var i = arr.length - 1;i>=0;i--){
//当前下标(从前往后)
var index = arr.length - 1 - i
//是否是第3*n个字符,且不是最后一个字符,需要额外输出一个 ","
if((index + 1)%3 == 0 && index != (arr.length - 1)){
//拼接
result = ("," + arr[i] + result)
}else{
//拼接
result = (arr[i] + result)
}
}
return result
}
console.log(numForamt(123456789)) //123,456,789
</script>
4.浮点数乘法
- 浮点数直接计算会有问题,自己封装了一个,先转换乘整数进行计算,后除以对应的百分数即可
<script>
//小数乘法,转换为正数再计算,然后在除以对应的百分数
function floatMultiplication(value = 0, multiplier){
//转换为整数的函数
function toIntValue(_value){
//小数点下标
var index = _value.toString().indexOf('.')
//如果是整数,直接返回
if(index == -1){
return {
intValue: _value, divisor: 1
}
}
//小数点后的未数(需要被除的数)
var divisor = Math.pow(10, _value.toString().length - index - 1)
//转换为整数
var intValue = Number(_value.toString().slice(0,index) + _value.toString().slice(index+1))
return {
intValue, divisor
}
}
//转换为正数计算,后再整除10的幂
var valueObj = toIntValue(value)
var multiplierObj = toIntValue(multiplier)
return (valueObj.intValue * multiplierObj.intValue) / (valueObj.divisor * multiplierObj.divisor)
}
//原生测试 不准
console.log('1.5*1.2 = ',1.5*1.2) //1.7999999999999998
//测试
console.log(floatMultiplication(1.5,1.2)) //1.8
</script>
5.递归查询是否有目标值
- 在多级嵌套的数据中,通过递归的方式查询是否存在目标值
- 需要4个人参数:目标数据(数组或者对象),目标值,目标值所在的属性,嵌套数组的属性值
<script>
var list = [
{
value: 1, children: [
{
value: 2,
children: [
{
value: 3
},
{
value: 4
}
]
}
]
},
{
value: 5,children: [
{
value: 6
},
]
},
{
value: 7,children: [
{
value: 8
}
]
}
]
//多级嵌套数据是否有目标值
//参数一:目标数据(数组或者对象)
//参数二:目标值
//参数三:目标属性
//参数四:数组属性名称
function hasValue(data = {},target_value = '', key = 'value', list_key = 'children'){
//数组类型
if(Array.isArray(data)){
//遍历元素,依次判断
for(var i=0;i<data.length;i++){
if(data[i][key] == target_value){
//已经找到匹配值 返回查找结果
return true
}else if(data[i][list_key] && data[i][list_key].length > 0){
//没找到,从子元素中递归查找,并得到查找结果
var flag = hasValue(data[i][list_key],target_value)
//如果找到,则退出函数
if(flag){
return true
}
}
}
}else if(data && typeof data == 'object'){
//对象类型
if(data[key] == target_value){
//返回匹配结果
return true
}
}else{
//基本类型
if(data == target_value){
//返回匹配结果
return true
}
}
//返回本轮查找结果(走到最后一步就是没找到)
return false
}
var flag = hasValue(list,5)
</script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了