在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 : { 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 } }, },
子组件:图片放大器组件(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 : { 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); } } }