奇奇怪怪需求之js实现换行(Vue)

311 阅读2分钟

如何用js实现换行

模拟数据:

  • 姓名:某某;
  • 性别:未知;
  • 年龄:18岁;
  • 个人理想:一大堆....

要求: 当一行能容下是并列,不能容下时换行。也就是说当一行能容下姓名性别时,性别不换行;如果不能容下,性别换行,以此类推

数据

data = 
[
    '姓名:阿泽;',
    '身高:180cm;',
    '年龄: 18岁;',
    '个人理想: 他11岁进入职业棋坛,13岁成为最年轻的世界围棋冠军。不知从何时开始,他的心里就像荒地吹进了一丝暖风,只要想到她心情就会很好,只要看见她就会不由自主地微笑,第一次想走出棋盘,走进那个女孩的世界。'
]

html

<div>
    <span v-for="(item, index) in data" :key="index">
        <br v-show="falseOrTrue[index]" />
        <span :class="wrap?'f-wrap':'f-nowrap'">{{ item }}</span>
    </span>
</div>

// 添加数据
widthArr: [], // 记录每个span的宽度
falseOrTrue: [], // 记录每个br是否出现
bodyWidth: 0, // 窗口宽度
maxDeep: 0, // 递归最大深度

// css
*{
    padding: 0;
    margin: 0;
}
.f-wrap{
    white-space: wrap;
}
.f-nowrap{
    white-space: nowrap;
}

只有当 white-space: nowrap; 时才能通过getBoundingClientRect()获取宽度,如果设置为wrap时,获取到的宽度为auto
[注:我也不知道为什么?有人能解答吗]

实现

mounted(){
    // 1. 获取每个span的宽度
    document.querySelectAll('.f-nowrap').froEach((item, index)=>this.widthArr[index] = item.getBoundingClientRect().width);
    
    // 2. 获取最大递归深度,设置falseOrTrue
    this.maxDeep = this.widthArr.length;
    this.falseOrTrue = new Array(this.maxDeep).fill(false);
    
    // 3. 所有的span都设置为white-space: wrap;
    this.wrap = true;
    
    //4. 调用一次检查函数
    this.checkFalseOrTrue();
    
    // 5. 监听窗口的变化
    let _this = this;
    window.addEventListener('resize', function(){
        _this.checkFalseOrTrue();
    })
}


methods:{
    // 检查函数
    checkFalseOrTrue()
    {
        this.bodyWidth = document.body.clientWidth;
        this.loopTocheck(this.widthArr[0], 1);
        this.$forceUpdate();
    },
    loopTocheck(remainder, deep)
    {
        // 出口
        if(deep >= this.maxDeep)
        {
            return ;
        }
        
        // remainder % this.bodyWidth: 拿的是上一个元素占了一行bodyWidth的多少
        // (remainder % this.bodyWidth) + this.widthArr[deep]: 就是上一个多余的+当前的宽度是否大于bodyWidth
        // 大于: 换行,把当前宽度传递给下一个, deep+1
        // 小于: 不换行,把这行的总宽度传递给下一个, deep+1
        let sum = (remainder % this.bodyWidth) + this.widthArr[deep];
        if(sum > this.bodyWidth)
        {
            this.falseOrTrue[deep] = true;
            return this.loopTocheck(this.widthArr[deep], deep + 1);
        }
        else
        {
            this.falseOrTrue[deep] = false;
            return this.loopTocheck(sum, deep + 1);
        }
    }
}