在vue实际开发中,经常会涉及到:后台管理系统通过富文本编辑器编辑内容和图片,然后在前台系统进行反显,如果此时在H5端,图片就会显得很小,于是用户想通过点击图片放大可以查看大图。这在操作系统中也是属于常规操作,一般我们会通过v-html对富文本的内容进行渲染,那么在这种错综交杂的html代码中如何实现用户的需求呢?下面将针对此类问题进行详细阐述。

要实现富文本内图片点击实现放大器效果,在不改变<img />标签且不添加自定义指令的前提下放大图片,找了下没有找到合适的插件,就自己动手写一个图片放大器组件。

一、设计思路

富文本里的图片,最终应该是呈现这样的状态:

1
2
3
4
5
6
7
<div class="textarea">
<img src="./assets/1we32id.png" />
<div class="content">
<h1>侠名风前端博客的</h1>
<p>Rome was not built in a day - 侠名风大前端</p>
</div>
</div>

给富文本标签添加点击事件,并新建一个富文本图片放大的html结构;

1
2
3
4
5
6
<div class="textarea" v-html="detailInfo.text" @click="showImg($event)"></div>
<!-- 富文本图片放大 -->
<div class="imgDolg" v-show="ifShowBigger">
<i class="el-icon-close" id="imgDolgClose" @click.stop="ifShowBigger= false"></i>
<el-image ref="imgDolg" class="img" :src="imgSrc" fit="cover"></el-image>
</div>

点击事件,如果点击的是<img />标签,则识别浏览器,获取原生图片的大小和src,对获得的图片进行放大处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
data() {
return {
ifShowBigger: false,
imgSite: {
height: 0,
width: 0,
}, //图片属性
imgSrc:'', //图片路径
}
},
setImgBigger(e) {
if (e.target.nodeName === 'IMG') {
this.ifShowBigger = true //图片放大器组件开启
let userAgent = navigator.userAgent //识别浏览器
if (userAgent.indexOf('Chrome') > -1) {
this.imgSrc = e.target.currentSrc //谷歌
} else {
this.imgSrc = e.target.href //其他
}
this.imgSite.height = e.target.offsetHeight //原图片高度
this.imgSite.width = e.target.offsetWidth //原图片宽度
}

富文本图片放大css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.imgDolg {
width: 100vw;
height: 100vh;
position: fixed;
z-index: 9999;
background-color: rgba(140, 134, 134, 0.6);
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
#imgDolgClose {
position: fixed;
top: 35px;
cursor: pointer;
right: 7%;
font-size: 50px;
color: white;
}
.img {
width: 70%;
max-height: 90%;
}
}
.img-hidden {
width: 0 !important;
height: 0 !important;
}

以上就实现了简单的vue富文本图片放大的效果,下面讲此功能抽取成公共的组件,便于以后使用在其他项目中。

二、抽取成公共组件(BigImg)

要注意的是,由于<img />的属性限制,等比例放大组件只要赋值相应的高度或者宽度其一就可以了,所以要想最大限度的放大图片,并且不让放大的图片超出可视区域,需要对容器和图片的宽高比进行计算,取比例小一个进行赋值:

1
2
3
4
5
6
7
8
9
10
11
12
ifImgShow(val) {
if (val) {
const _H = document.body.offsetHeight ?? 0 //容器高度
const _W = document.body.offsetWidth ?? 0 //容器宽度

const V = _H / this.imgSite.height > _W / this.imgSite.width //容器和图片的宽高比,是否高比大于宽比

//取比例小的一个进行赋值
this.H = V ? null : '90vh'
this.W = V ? '90vw' : null
}
}

父组件

html结构代码:

1
2
3
4
5
6
7
8
9
<!-- 需要放大的富文本 -->
<div @click="setImgBigger" v-html="" />
<!-- 图片放大组件 -->
<big-img
:ifImgShow="ifShowBigger"
:imgSrc="imgSrc"
:imgSite="imgSite"
@closeBigImg="ifShowBigger = false"
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
data() {
return {
ifShowBigger: false, //图片放大器开关
imgSite: {
height: 0,
width: 0,
}, //图片属性
imgSrc: '', //图片地址
}
},
methods: {
/**
* @description: 图片放大
* @param e
* @return void
*/
setImgBigger(e) {
if (e.target.nodeName === 'IMG') {
this.ifShowBigger = true //打开图片放大器开关
let userAgent = navigator.userAgent //获取浏览器属性
if (userAgent.indexOf('Chrome') > -1) { //Google
this.imgSrc = e.target.currentSrc
} else { //其他
this.imgSrc = e.target.href
}
//保存原图片属性
this.imgSite.height = e.target.offsetHeight
this.imgSite.width = e.target.offsetWidth
}
},
},

子组件:图片放大器组件(BigImg)

这里用了css变量

1
2
3
4
5
6
7
<template>
<div class="img-view" @click="getClose" :style="cssVar" v-show="ifImgShow">
<div class="img-layer">
<img :src="imgSrc" alt="图片地址错误" />
</div>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
export default {
props: {
ifImgShow: {
type: Boolean,
default: false,
},
imgSrc: {
type: String,
default: '',
},
imgSite: {
type: Object,
default: () => {
return {}
},
},
},
data() {
return {
H: 0,
W: 0,
}
},
computed: {
cssVar({ H, W }) {
const _site = {
'$height': H,
'$width': W,
}
return _site
},
},
watch: {
ifImgShow(val) {
if (val) {
const _H = document.body.offsetHeight ?? 0 //容器高度
const _W = document.body.offsetWidth ?? 0 //容器宽度

const V = _H / this.imgSite.height > _W / this.imgSite.width //容器和图片的宽高比,是否高比大于宽比

this.H = V ? null : '90vh'
this.W = V ? '90vw' : null
}
},
},
methods: {
/**
* @description: 关闭图片放大
* @return void
*/
getClose() {
this.$emit('closeBigImg')
},
},
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@keyframes scale-out-tr {
0% {
-webkit-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: 100% 0%;
transform-origin: 100% 0%;
opacity: 1;
}
100% {
-webkit-transform: scale(0);
transform: scale(0);
-webkit-transform-origin: var($witdh, 10) var($height, 20);
transform-origin: var($witdh, 10) var($height, 20);
opacity: 1;
}
}
.img-view {
.img-layer {
width: 100%;
height: 100%;
position: fixed;
z-index: 5;
top: 0;
left: 0;
background: rgba(0, 0, 0, 0.7);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;

img {
height: var($height);
width: var($width);
}
}
}