通过css和js实现多行文本省略时省略号不在最右边

131 阅读5分钟

1.通过css实现

  • html:

    <body>
    <div class='warn'>
    	<div class='text more-line-3'><span style='width:50%'></span>《长恨歌》是唐代诗人白居易创作的一首长篇叙事诗。此诗可分为三大段,从“汉皇重色思倾国”至“惊破霓裳羽衣曲”共三十二句为第一段,写唐玄宗和杨贵妃的爱情生活、爱情效果,以及由此导致的荒政乱国和安史之乱的爆发。从“九重城阙烟尘生”至“魂魄不曾来入梦”共四十二句为第二段,写马嵬驿兵变,杨贵妃被杀,以及此后唐玄宗对杨贵妃朝思暮想,深情不移。从“临邛道士鸿都客”至“此恨绵绵无绝期”共四十六句为第三段,写唐玄宗派人上天入地到处寻找杨贵妃和杨贵妃在蓬莱宫会见唐玄宗使者的情形</div>
    </div>
    </body>
    
  • 然后我们来写多行文本省略

      .warn{
    		display: -webkit-box;
    	}
    	.text{
    		font-size:14px;
    		width:100%;
    	}
    	.more-line-1{
    		text-overflow: ellipsis;
    		white-space: nowrap;
    		overflow: hidden;
    	}
    	.more-line-3{
    		display: -webkit-box;
    		-webkit-line-clamp: 3;
    		-webkit-box-orient: vertical;
    		overflow: hidden;
    	}
    

    现在省略是到了最右边的,我们需要让省略号在中间的地方

    image.png

  • 所以我们需要使用浮动让设置的text里面的span悬浮在右下角

    	.text span{
    		float: right;
    		height: 14px;
    		margin-top: 48px;
    	}
    

    但是这样会存在右边空出一块

    image.png

  • 最终我们需要多个右浮动元素,让span贴合到文字里面去

    	.text::before{
    		content: '';
    		float: right;
    		width: 0px;
    		height:calc(100% - 14px);
    		background: red
    	}
    	.text span{
    		float: right;
    		clear: both;
    	}
    

    image.png

  • 总结:

    1. 通过在文本内多设置一个span或者其他标签,将这个标签右浮动到最下角,占据一部分文本内容,实现省略号向左挤动
    2. 通过设置::before的右浮动和高度,让span只是占据最后一行的宽度
    3. 最终css:
    .warn{
    		display: -webkit-box;
    	}
    	.text{
    		font-size:14px;
    		width:100%;
    	}
    	.more-line-1{
    		text-overflow: ellipsis;
    		white-space: nowrap;
    		overflow: hidden;
    	}
    	.more-line-3{
    		display: -webkit-box;
    		-webkit-line-clamp: 3;
    		-webkit-box-orient: vertical;
    		overflow: hidden;
    	}
    	.text::before{
    		content: '';
    		float: right;
    		width: 0px;
    		height:calc(100% - 14px);
    		background: red
    	}
    	.text span{
    		float: right;
    		clear: both;
                         text-align: right;
                        font-size: 14px;
                        line-height: 14px;
    	}
    
    • 当然我们还可以通过shape-outside来实现其他文字环绕span的标签实现,这样就不需要写.text::before这一块代码了,详情
                          .text span {
                                  float: right;
                                  clear: both;
                                  margin-top: 65px;//上面几行的高度
                                  shape-outside: border-box;
                          }
      
  • 最后(也可以实现下图的效果):

    image.png

    1. 需要修改.text span
      	.text span{
      		float: right;
      		clear: both;
      		width: 80%;
      		height: 14px;
      		text-align: right;
      		line-height: 1;
      	}
      
    2. span里面添加日期<span style='width:50%'>2022.11.17</span>

2.js实现

  • html:
    <body>
    	<div class='warn'>
    		<div class='text more-line-3'>《长恨歌》是唐代诗人白居易创作的一首长篇叙事诗。此诗可分为三大段,从“汉皇重色思倾国”至“惊破霓裳羽衣曲”共三十二句为第一段,写唐玄宗和杨贵妃的爱情生活、爱情效果,以及由此导致的荒政乱国和安史之乱的爆发。从“九重城阙烟尘生”至“魂魄不曾来入梦”共四十二句为第二段,写马嵬驿兵变,杨贵妃被杀,以及此后唐玄宗对杨贵妃朝思暮想,深情不移。从“临邛道士鸿都客”至“此恨绵绵无绝期”共四十六句为第三段,写唐玄宗派人上天入地到处寻找杨贵妃和杨贵妃在蓬莱宫会见唐玄宗使者的情形</div>
    	</div>
    </body>
    
  • css:
    		.warn{
    			display: -webkit-box;
    		}
    		.text{
    			font-size:14px;
    			width:100%;
    		}
    		.more-line-1{
    			text-overflow: ellipsis;
    			white-space: nowrap;
    			overflow: hidden;
    		}
    		.more-line{
    			display: -webkit-box;
    			-webkit-line-clamp: 3;
    			-webkit-box-orient: vertical;
    			overflow: hidden;
    		}
    
  • js:
    1. 通过获取内容的font-size和dom的宽度计算出一行显示的文字
    2. 特殊判断占比为1的,通过css进行省略
    3. 最后通过slice截取内容并添加省略号
    // dom:节点 (document.getElementsByClassName('text')[0])
    	// line:行数(3)
    	// ratio:最后一行占比(0.5)
    	function textMore(dom,line,ratio){
    		var className= dom.getAttribute('class');
    		var fontSize=0
    		var domWidth=dom.offsetWidth
    		if(window.getComputedStyle){
    			fontSize=window.getComputedStyle(dom)['font-size'].split('px')[0]
    		}else{
    			fontSize=obj.currentStyle['fontSize'].split('px')[0]
    		}
    		var lineFontNum=parseInt(domWidth/fontSize)
    		if(ratio==1){
    			className=className.replace('more-line','').replace('more-line-1','')
    			if(line==1){
    				dom.setAttribute('class',className+' more-line-1')
    			}else{
    				dom.setAttribute('class',className+' more-line')
    				dom.style['-webkit-line-clamp']=line
    			}
    		}else{
    			var numFont=(line-1)*lineFontNum
    			numFont+=parseInt(lineFontNum*ratio)
    			document.getElementsByClassName('text')[0].innerText=document.getElementsByClassName('text')[0].innerText.slice(0,numFont)+'...'
    		}
    
    	}
    	textMore(document.getElementsByClassName('text')[0],3,0.5)
    

抽离组件

textOmit

<template>
  <div :id="txtId"  class='warn' :style="{'--lineHeight':`${1/row * 100}%`}">
    <div class='text' :class="[row ===1 ?'line-1':`line-clamp-${row}`]"><i v-if="lastTxt && row>0">{{lastTxt}}</i>{{txt}}<span v-if="lastTxt && row>0" @click="emit('lastClick')">{{lastTxt}}</span></div>
  </div>
</template>
<script lang="ts" setup>
import {defineProps,defineEmits,watch} from 'vue'
 const props = defineProps({
    row:  {
      type: Number,
      default: 1
    },
   txt:{
    type: String,
    default: ''
   },
   lastTxt:{
     type: [String,Number],
     default: ''
   }
})
const emit = defineEmits(['lastClick'])
 
const txtId= ref<string>(`${new Date().getTime()}_${Math.random()*10000000000}`)

 watch([()=>props.txt,()=>props.row],()=>{
   console.log(props.txt,props.row)
   nextTick(()=>{
    

        if(props.row>0){
          // 横行判断
          if(props.row===1){
            const textElements = document.getElementById(txtId.value)?.querySelectorAll('.text') || [];
            textElements.forEach(el => {
              el.removeAttribute('show-scroll')
              const isClamped = el.scrollWidth > el.clientWidth;
              if (isClamped) {
                el.setAttribute('show-scroll','2')
              }
            });
          }else{
            // 竖项判断
            const textElements = document.getElementById(txtId.value)?.querySelectorAll('.text') || [];
            textElements.forEach(el => {
              el.removeAttribute('show-scroll')
              const isClamped = el.scrollHeight > el.clientHeight;
              if (isClamped) {
                el.setAttribute('show-scroll','1')
              }
            });
          }
        }
    
   })
 },{immediate:true,deep:true})

</script>
<style scoped>

.warn{
  display: -webkit-box;
}
.text{
  font-size:14px;
  width:100%;
  position: relative;
}

.text::before{
  content: '';
  float: right;
  width: 0px;
  height:calc(100% - var(--lineHeight));
  background: red
}
.text i{
  float: right;
  clear: both;
  opacity: 0;
  display: none;
}

.text[show-scroll='1'] span {
  position: absolute;
  bottom: 0;
  right: 0;
}

.line-1{
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.line-clamp-2{
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.line-clamp-3{
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.line-clamp-4{
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.text[show-scroll='1'] i,.text[show-scroll='2'] i {
  display: revert;
}

.text[show-scroll='2'] span {
  position: absolute;
  right: 0;
}
</style>

使用:

<textOmit :row="2" txt="《长恨歌》是唐代诗人白居易创作的一首长是唐代诗人白居易创作的一首长是唐代诗人白居易创白居易创作的一首长是唐代诗人白居易创"></textOmit>


<textOmit :row="2" last-txt="更多》" txt="《长恨歌》是唐代诗人白居易创作的一首长是唐代诗人白居易创作的一首长是唐代诗人白居易创白居易创作的一首长是唐代诗人白居易创"></textOmit>