精确实现popover效果:内容超出容器则tooltips+popover展
⽰,反之⽆效果
前端中对于:“⽂字超出tooltip展⽰,⿏标滑过⽓泡展⽰所有内容”,这样的需求是很常见的,element-ui也有专门的组件el-popover组件⽀持类似需求的实现
要实现这样的效果,使⽤el-popover组件即可。
<el-table-column prop="date" label="原始popover" width="180">
<template slot-scope="{row}">
<el-popover placement="top" trigger="hover">
<p >{{row.first}} </p>
<p slot="reference"
>{{row.first}}</p>
</el-popover>
</template>
</el-table-column>
这样⼀律不做区分内容长短,全部使⽤⽓泡,如果内容没有超出容器,也会有⽓泡展⽰,略显粗暴。
这样效果其实并不好,实际需求⼀般还会有⼀句:如果不超过容器宽度则不展⽰⽓泡。即便产品不指出,前端也应该处理⼀下。因此再做⼀点优化,对内容做个判断,字数超出⼀定值才展⽰⽓泡,通过if-else实现
<el-table-column prop="date" label="原始popover" width="180">
<template slot-scope="{row}">
<el-popover placement="top" trigger="hover" v-if="row.first.length > 30">
<p >{{row.first}}</p>
<p
slot="reference">{{row.first}}
</p>
</el-popover>
<p v-else>{{row.first}}</p>css特效文字
</template>
</el-table-column>
或者通过el-popover的disabled属性设置
<el-table-column prop="date" label="原始popover" width="180">
<template slot-scope="{row}">
<el-popover :disabled="row.first.length <= 30" placement="bottom" trigger="hover">
<p >{{row.first}}</p>
<p slot="reference"
>{{row.first}}
</p>
</el-popover>
</template>
</el-table-column>
但是这样的实现⽅式⽆法精确计算出何时会出发tooltips效果,因为tlltips是css实现的,底层是浏览器去计算内容和容器的相对宽度实现的,但并未通过浏览器api给到前台,所以就⽆法精确控制⽓泡的出发时机。如果包含⼀些特殊符号、英⽂等字符,简单通过长度判断就更不够精确了,⽐如:
中⽂长度超过12,css就计算出超出容器,需要tooltips展⽰,所以⽓泡也设置为12
但是如果含有英⽂字符或数字就⽆法精确了
能看到,长度依然是12,由于英⽂字符和数字、特殊字符、中⽂等的宽度各不相同,导致实际容还没超出容器,tooltips还未展⽰,但⽓泡通过字符长度这个单⼀维度判断出已达设置上限,⽓泡被触发。⼀般情况下⽓泡是⽤来展⽰固定宽度容器⽆发展⽰的更多内容,本⾝会遮挡⼀部分其它内容,影响体验,不是必要的时候最好不展⽰。如果⽆法精确控制或者说相对更加精确控制的话,就会造成体验上的不佳。
介于此,经过⼀番研究,问题的本质是内容宽度超出容器宽度时,然后做⼀些操作,如何能精确呢?就⽬前看来,js计算是最精确的,能精确到1px。
思路:
利⽤el-popover做⼆次封装,通过js计算内容dom的宽度和容器dom宽度,进⾏⽐较,动态修改disabled属性。默认单⾏tooltips,计算⽅程:容器宽度 < 内容宽度 时展⽰⽓泡;
多⾏tooltips同理,⽀持配置⾏数即可,计算⽅程:容器宽度 * ⾏数 < 内容宽度 时展⽰⽓泡
代码:
<template>
<div class="auto-popover">
<el-popover
:title="title"
:width="width"
:offset="offset"
:transition="transition"
:popper-options="popperOptions"
:open-delay="openDelay"
:
placement="placement"
:trigger="trigger"
:disabled="!showBubble"
>
<!-- 不启⽤插槽,则泡泡默认和content⼀直,为传⼊popoverValue -->
<template v-if="useSlot">
<!-- 启⽤插槽,如果只启⽤content,则泡泡和content⼀致 -->
<slot v-if="useSlotBubble" name="bubble"></slot>
<p v-else class="my-popover">
<slot name="content"></slot>
</p>
</template>
<p v-else class="my-popover">{{popoverValue}}</p>
<div slot="reference">
<div
ref="container"
:class="{
'plain-ellipsis': rows == 1,
'auto-popover-ellipsis': rows != 1,
'auto-popover_row-2': rows == 2,
'auto-popover_row-3': rows == 3,
'auto-popover_row-4': rows == 4,
'auto-popover_row-5': rows == 5,
'auto-popover_row-6': rows == 6,
'auto-popover_row-7': rows == 7,
'auto-popover_row-8': rows == 8,
'auto-popover_aligin-left': aligin==='left',
}"
>
<slot v-if="useSlotContent" name="content"></slot>
<span v-else>{{popoverValue}}</span>
</div>
<!-- 计算宽度 -->
<div v-if="useSlot" class="cal-content" ref="content">
<slot name="content"></slot>
</div>
<div class="cal-content" ref="content" v-else>
<span>{{popoverValue}}</span>
</div>
</div>
</el-popover>
</div>
</template>
<script>
export default {
name: 'auto-popover',
props: {
props: {
popoverValue: '',
// ⾏数
rows: {
type: [Number, String],
default: 1,
},
// 强制展⽰bubble,不⽤计算
forceShowBubble: {
type: Boolean,
default: false,
},
// ⽂字对齐⽅式
aligin: String,
trigger: { type: String, default: 'hover' },
title: String,
width: {
type: String,
default: '150px',
},
offset: {
type: Number,
default: 0,
},
transition: String,
popperOptions: Object,
popperClass: String,
openDelay: Number,
placement: String,
},
data() {
return {
showBubble: false,
};
},
components: {},
computed: {
// 是否采⽤slot⽅式
useSlot() {
return Object.keys(this.$slots).length;
},
useSlotContent() {
return Object.keys(this.$slots).indexOf('content') > -1; },
useSlotBubble() {
return Object.keys(this.$slots).indexOf('bubble') > -1; },
},
watch: {
popoverValue: {
immediate: true,
handler(val) {
this.$nextTick(() => {
this.calculateWidth();
});
},
},
},
mounted() {},
methods: {
// 计算实际内容和容器之间的宽度关系
calculateWidth() {
calculateWidth() {
let container = this.$ainer;
let content = this.$t;
let rows = +ws;
let containerW = container.offsetWidth;
let contentW = content.offsetWidth;
// console.log(containerW - 8);
// console.log(contentW);
if(this.forceShowBubble) {
this.showBubble = this.forceShowBubble;
}else {
if ((containerW - 8) * rows < contentW) {
this.showBubble = true;
} else {
this.showBubble = false;
}
}
console.log(this.showBubble);
},
},
};
</script>
<style lang='scss' scoped>
.auto-popover {
.cal-content {
white-space: nowrap;
display: inline-block;
position: absolute;
left: -100000px; // fix:防⽌影⼦dom在容器中撑开容器,影响实际宽度,⽐如table⾥ visibility: hidden;
}
.auto-popover-ellipsis {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
.auto-popover_row-2 {
-webkit-line-clamp: 2;
}
.auto-popover_row-3 {
-webkit-line-clamp: 3;
}
.auto-popover_row-4 {
-webkit-line-clamp: 4;
}
.auto-popover_row-5 {
-webkit-line-clamp: 5;
}
.
auto-popover_row-6 {
-webkit-line-clamp: 6;
}
.auto-popover_row-7 {
-webkit-line-clamp: 7;
}
.auto-popover_row-8 {
-webkit-line-clamp: 8;
}
.auto-popover_aligin-left {
text-align: left;
}
}
</style>
<style lang="scss">
.my-popover {
max-width: 300px;
word-break: break-all;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论