有志者事竟成。

小程序文本换行算法

1.简介

最近公司项目需要,用户输入文本计算换行字符,话不多上代码,这是之前写的一个例子,仅供参考

2.上代码

<template>
    <view class="container">
        <view style=" word-break:break-all;word-wrap:break-word; white-space:pre-wrap;
        font-size: 15px; width: 200px; overflow: hidden; line-height: 25px;">
            {{data}}
        </view>
        <view id="one" style=" word-break:break-all;word-wrap:break-word; white-space:pre-wrap;
        font-size: 15px; max-width: 200px; overflow: hidden; line-height: 25px; display: inline-block;
            background: red;">
            {{str}}
        </view>
    </view>
</template>

<script>
    var query;
    export default {
        data() {
            return {
                str:'',
                height:null,
                width:null,
                data:'',
                lineHeight:25 //记录行高判断是否产生换行
            };
        },
        methods: {
            setData(obj) {
                let that = this;
                let keys = [];
                let val, data;
                Object.keys(obj).forEach(function(key) {
                    keys = key.split('.');
                    val = obj[key];
                    data = that.$data;
                    keys.forEach(function(key2, index) {
                        if (index + 1 == keys.length) {
                            that.$set(data, key2, val);
                        } else {
                            if (!data[key2]) {
                                that.$set(data, key2, {});
                            }
                        }
                        data = data[key2];
                    })
                });
            },
            getBoxHeight() { //获取左右两边高度
                return new Promise((resolve, reject) => {
                    query = wx.createSelectorQuery();
                    query.select('#one').boundingClientRect();
                    query.exec((res) => {
                        this.height = res[0].height
                        this.width = res[0].width
                        this.setData({
                            height: res[0].height,
                            width: res[0].width,
                        })
                        resolve();
                    });
                })
            },
            async getWrapString(str,styles){
                if(!str||str.length<=0) return '';
                this.data = str
                //下面将上面初步处理的字符串进行字符分割。
                var words = [],temp = str.split(' ');//根据单词边界进行初次分割,分割后的non-CJK字符会变成一个整体,但CJK字符需要进行二次分割
                //2.对英文单词或一串中文进行二次分割
                for(var i=0;i<temp.length;i++){
                    //将包含CJK字符的项进行单字分割后存入words数字中 //另外,如果设置了break-word则将英文单词分割为单字
                    if(this.isCJKCharacter(temp[i])){
                        words.push.apply(words,temp[i].split(''));
                    }else{//不包含CJK字符的项则视为一个整体直接存进words数组
                        words.push(temp[i]);
                    }
                }
                //预留用一个二维数组保存计算结果,如lines=[['12',' ','中'],['asdf','哈']]则表示结果有2行,第一行为'12 中',第二行为'asdf哈'
                var lines = [],oneline=[],widthlist=[]//oneline是一维数组,保存一行中的单词
                // //3.遍历求解换行位置,即尝试向行容器中添加字符。
                for(var i=0;i<words.length;i++){
                    var word = words[i];
                    this.str += word //往行容器中增加内容
                    await this.setData({
                        str: this.str
                    })
                    await this.getBoxHeight();
                    if(word == '\n'){//如果当前单词是换行符
                        //则将之前的内容存为1行,并追加保存一个空行
                        lines.push(oneline,[]);
                        widthlist.push(this.width);
                        //清空行容器
                        this.str = ''
                        //开始记录新行
                        oneline = [];
                        //结束本次循环
                        continue;
                    }
                    if(this.height <= this.lineHeight){//如果没有产生换行
                        //将当前单词或单字追加记录到oneline中
                        oneline.push(word);
                    }else{//如果产生了换行
                        widthlist.push(this.width);
                        //前面的单词存为一行
                        lines.push(oneline);
                        //清空行容器
                        this.str = ''
                        //开始记录新行
                        oneline=[];
                        //回退,在新行中尝试添加当前单词或单字
                        i--;
                        continue;
                    }
                    await this.getBoxHeight();
                }
                //3.1矫正,手动插入最后一行。
                lines.push(oneline);
                widthlist.push(this.width);
                //4.收尾工作4.1将二维数组还原为字符串
                var list = []
                var string = '';
                for(var i=0;i<lines.length;i++){
                    string+=lines[i].join('')+'\n';
                    if(lines[i].join('')){
                        list.push({
                            text:lines[i].join(''),
                            width:null
                        })
                    }
                }
                list.forEach((item,index) => {
                    item.width = widthlist[index]
                })
                string = string.substring(0,string.length-1);
                console.log(lines)
                console.log(oneline)
                console.log(widthlist)
                console.log(string)
                console.log(list)
                //4.2移除行容器
                this.str = ''
                //返回计算结果
                // return list;
            },
            //传入一个字符串,判断是否包含CJK字符串,CJK即中国日本韩国文字字符。
            isCJKCharacter(ch){
                /*
                参考网站:https://blog.csdn.net/iteye_4476/article/details/81652883,来源Unicode官网
                CJK字符不同于其他字符,CJK字符可以在任意地方换行,不像英文字符等正常情况必须在单词后换行
                截止20190725,根据我查到的资料(Unicode 5.0版),js中的Unicode为2个字节,CJK字符在2个字节的unicode中包括以下范围
                //大多数情况下,可以取1.~5.来判断CJK字符
                1.标准CJK文字
                    1.1 [\u3400-\u3db5] => CJK统一表意文字扩展A (发行版3.0)
                    1.2 [\u4e00-\u9fa5] => CJK统一表意文字 (发行版1.1) (常用来简单判断中文字符)
                    1.3 [\u9fa6-\u9fbb] => CJK统一表意文字 (发行版4.1)
                    1.4 [\uf900-\ufa2d] => CJK兼容文字 (发行版1.1)
                    1.5 [\ufa30-\ufa6a] => CJK兼容文字 (发行版3.2)
                    1.6 [\ufa70-\ufad9] => CJK兼容文字 (发行版4.1)
                    (以下两项编码超过两个字节,js中暂时不能用,但是还是写一下(js中无法使用的编码范围前面有双斜杠//标志):
                    //1.7 [\u20000-\u2a6d6] => CJK统一表意文字扩展B (发行版3.1)
                    //1.8 [\u2f800-\u2fa1d] => CJK兼容补充 (发行版3.1)) 
                2. [\uff00-\uffef] => 全角中英文标点符号、半宽片假名、半宽平假名、半宽韩文字母
                3. [\u2e80-\u2eff] => CJK部首补充
                4. [\u3000-\u303f] => CJK标点符号
                5. [\u31c0-\u31ef] => CJK笔划
                6. [\u2f00-\u2fdf] => 康熙部首
                7. [\u2ff0-\u2fff] => 汉字结构描述字符
                8. [\u3100-\u312f] => 注音符号
                9. [\u31a0-\u31bf] => 注音符号(闽南语客家语扩展)
                10. [\u3040-\u309f] => 日文平假名
                11. [\u30a0-\u30ff] => 日文片假名
                12. [\u31f0-\u31ff] => 日文片假名拼音扩展
                13. [\uac00-\ud7af] => 韩文拼音
                14. [\u1100-\u11ff] => 韩文字母
                15. [\u3130-\u318f] => 韩文兼容字母
                //16. [\u1d300-\u1d35f] => 太玄经符号
                17. [\u4dc0-\u4dff] => 易经六十四卦象
                18. [\ua000-\ua48f] => 彝文音节
                19. [\ua490-\ua4cf] => 彝文部首
                20. [\u2800-\u28ff] => 盲文符号
                21. [\u3200-\u32ff] => CJK字母及月份
                22. [\u3300-\u33ff] => CJK特殊符号(日期合并)
                23. [\u2700-\u27bf] => 装饰符号(非CJK专用)
                24. [\u2600-\u26ff] => 杂项符号(非CJK专用)
                25. [\ufe10-\ufe1f] => 中文竖排标点
                26. [\ufe30-\ufe4f] => CJK兼容符号(竖排变体、下划线、顿号)
                */
                var cjk = {
                    NO1Unihan: ['\\u3400-\\u3db5','\\u4e00-\\u9fa5','\\u9fa6-\\u9fbb','\\uf900-\\ufa2d','\\ufa30-\\ufa6a','\\ufa70-\\ufad9','',''],
                    NO2UFF00: ['\\uff00-\\uffef'],
                    NO3U2E80: ['\\u2e80-\\u2eff'],
                    NO4U3000: ['\\u3000-\\u303f'],
                    NO5U31C0: ['\\u31c0-\\u31ef'],
                    NO6U2F00: ['\\u2f00-\\u2fdf'],
                    NO7U2FF0: ['\\u2ff0-\u2fff'],
                    NO8U3100: ['\\u3100-\\u312f'],
                    NO9U31A0: ['\\u31a0-\\u31bf'],
                    NO10U3040: ['\\u3040-\\u309f'],
                    NO11U30A0: ['\\u30a0-\\u30ff'],
                    NO12U31F0: ['\\u31f0-\\u31ff'],
                    NO13UAC00: ['\\uac00-\\ud7af'],
                    NO14U1100: ['\\u1100-\\u11ff'],
                    NO15U3130: ['\\u3130-\\u318f'],
                    NO16U1D300: [''],//\\u1d300-\\u1d35f
                    NO17U4DC0: ['\\u4dc0-\\u4dff'],
                    NO18UA000: ['\\ua000-\\ua48f'],
                    NO19UA490: ['\\ua490-\\ua4cf'],
                    NO20U2800: ['\\u2800-\\u28ff'],
                    NO21U3200: ['\\u3200-\\u32ff'],
                    NO22U3300: ['\\u3300-\\u33ff'],
                    NO23U2700: ['\\u2700-\\u27bf'],
                    NO24U2600: ['\\u2600-\\u26ff'],
                    NO25UFE10: ['\\ufe10-\\ufe1f'],
                    NO26UFE30: ['\\ufe30-\\ufe4f']
                };
                var reg,str='[';
                for(var k in cjk){
                    str+=cjk[k].join('');
                }
                str+=']+';
                if(str!='[]+'){
                    reg = new RegExp(str,'m');
                    return reg.test(ch);
                }
                return null;
            }
        },
        onLoad() {
            
        },
        onShow() {
            this.getWrapString('as中文加快速度\n爱上对方过后就山东科技撒的谎撒娇肯定会撒娇肯定会啥接电话撒接电话按时接电话阿萨德毫无二带娃U盾挥洒接电话杀菌灯哭了去玩儿童与欧普讽德诵功邯郸市规划光伏发电更好的发几个aahsdashdgsahdgsahdgahsdashdgsahdgsahdgsahdg自行车VB\n你们',{"font-size":"12px","width":"80px"})
            // var i = 0
            // var interval = setInterval(function(){
            //     getApp().mtj.trackEvent('mall', {
            //       name: '测试百度统计' + i, 
            //     });
            //     getApp().mtj.trackEvent('machinedetail', {
            //       mach: i, 
            //     });
            //     i++
            //     console.log('百度统计' + i)
            //     if(i == 4){
            //         uni.reLaunch({ url: '../mall/text'})
            //         clearInterval(interval);
            //     }
            // }, 1000);
        }
    }
</script>
<style lang="scss">
    
</style>

3.效果

 

3.结语
本文写于2021-3-26,算法其实上周就写好了,不过没有时间整理成博客,整理成博客之后也没有太多时间去雕琢。写出来是方便自己查阅,也让一些和我一样曾经纠结于小程序的换行机制的小伙伴们有一些启发。最后还是那句话,走过路过点个赞再走呗。被人关注还是有一些开心的。后续会继续优化。

posted on 2021-04-01 10:56  阿长*长  阅读(656)  评论(0编辑  收藏  举报

导航