木灵鱼儿
阅读:2986
vue 通过js触发element ui的图片预览组件
element ui的图片预览组件并没有单独提供出来,默认是在image组件里面一起使用,但是有的时候,我们需要点击某一个自定义按钮,然后弹出图片预览,但是,又不需要使用el-image组件,于是乎,有了这篇笔记。
首先思路并不是我的,我也是看了下同事,他网上找的教程,然后我看了下,在掘金找到一篇文章:《Vue中使用element-ui的内置组件实现图片预览全局调用功能》;深受启发,于是也记下自己的笔记。
首先思路是两个:
- element ui的图片预览本身是一个vue组件
- vue.extend构造器将vue组件通过js的方式构造出来,new出来的这个构造器,他的属性为组件的属性以及其他(其他就是我也不明白)
那么就很简单了,我们将图片预览组件引入,通过构造器构造出来,拿到构造后的实例,实例的属性就是组件的配置,我们再把组件的show方法挂载的全局vue的原型上,不就可以在任何地方通过this.xxx
方法触发了吗?
当然,也没有那么简单,还是有点曲折,我们一一解决。
引入图片预览组件
组件的路径大概是:element-ui/packages/image/src/image-viewer
我们查看这个组件,可以看到,他其实是没有v-if指令的,这就导致这个组件一使用,就在html上显示了。
查看一下element的image组件,可以看到,是在外面做了v-if
所以,我们也需要这么做,这样的话就不能直接引入再通过构造器构造了,我们需要一个中间层,用于v-if管理。
所以我们需要创建一个vue组件:Preview.vue
<template>
<transition name="viewer-fade">
<ElImageViewer v-if="show" :urlList="urlList"
:on-close="closeViewer" />
</transition>
</template>
<script>
import ElImageViewer from "element-ui/packages/image/src/image-viewer";
export default {
props: {
urlList: {
type: Array,
default: () => [],
},
},
data() {
return {
show: false,
};
},
methods: {
closeViewer() {
this.show = false;
},
},
components: {
ElImageViewer,
},
};
</script>
组件里面目前用了两个属性一个方法,show用于控制是否显示关闭,closeViewer方法是一个回调,当用户点击了关闭后会触发这个回调方法,我们就需要将show设置为false。
urlList就是图片的数组了,由于图片可以是多个,所以用的数组。
此时中间管理层我们已经做好了,下面开始构造他
vue.enxted构造组件
构造器我们需要使用到Vue实例,而且我们希望的是,这个组件可以像普通组件一样,import引入,然后vue.use()
激活,所以我们要手动先写一个组件的js文件,配合use方法使用。
use方法接收一个参数,这个参数可以是对象,也可以是函数,如果是对象的话,该对象就必须提供一个install的属性,这个属性是一个方法,接收一个参数,就是Vue实例。
因为我们需要import引入刚刚创建的中间管理层组件,所以只能使用对象的形式。
代码如下:
preview.js:
import PreviewItem from "./Preview.vue";
const Preview = {};
Preview.install = function (Vue) {
const PreviewConstructor = Vue.extend(PreviewItem);
const instance = new PreviewConstructor();
instance.$mount(document.createElement("div"));
document.body.appendChild(instance.$el);
Vue.prototype.$showImg = function (urlList=[]) {
instance.urlList = urlList
instance.show = true;
}
}
export default Preview;
大概原理:
引入管理中间件组件,创建一个对象Preview,给对象添加install方法,接收到vue实例对象。
通过vue实例对象的extend构造器,将管理中间件组件作为参数传入,此时会return出一个vue组件的构造函数,我们new出这个构造函数。
此时dom并没有生成,我们需要通过这个new出的构造函数的$mount方法,将它挂载到元素上,但是此时我们并不需要他真实挂载到网页的某个地方,所以我们创建一个div元素,将组件挂载到div中,这样他就不会出现在网页中去。
然后我们再通过instance组件的构造函数实例的$el属性,拿到dom,在将它传入网页的body中去。
此时我们的元素v-if为false,所以并不会显示。
但是,我们还没有办法触发让他显示,但是我们已知了两个条件:
- 有全局的Vue对象了
- instance实例已经可以通过他控制组件的属性
所以我们可以创建一个方法,然后挂载到Vue的原型上,方法接收一个数组,也就是图片数组,并且在方法触发时,控制instance的show属性为true。
然后我们导出这个Preview对象;
main.js 激活
在main.js文件中
import Preview from "./preview.js";
Vue.use(Preview);
这样就行了, 我们可以在项目的vue组件里面,使用:
this.$showImg(["xxx"])
来触发图片预览组件。
谈谈动画
element 原装组件触发的图片预览弹窗,第一次显示的时候会有动画的,关闭的时候就没有动画了,但是我按照图片组件的那种引入方式写,不知道为什么,就是不会有动画出现。
我想了下,可能是因为预览组件transition元素里面并没有使用v-if或者v-show导致的,但是原装里面没有使用,为啥会有动画????
所以很无奈,我只能在管理中间层组件那使用了一个transition元素包裹,这样效果就和官方的保持了一致,但是我也不知道为什么官方的可以有动画,所以,等待以后明白了再说吧,或者有大佬点醒下我。
关于预览组件点击遮罩层关闭的问题
其实官方组件已经考虑到这个问题了,但是并没有使用,可能是体验不好把!
打开图片预览组件,我们找到prop属性,里面有这个一个配置:
maskClosable: {
type: Boolean,
default: true,
},
这个属性字面意思是mask元素的close开关,默认是true,其实表示的是默认点击mask遮罩层的时候,是可以关闭预览弹窗的。
因为我们在去methods里面找handleMaskClick
方法,这个方法是绑定在mask元素上的:
<div class="el-image-viewer__mask" @click.self="handleMaskClick"></div>
方法内容为:
handleMaskClick() {
if (this.maskClosable) {
this.hide();
}
},
hide() {
this.deviceSupportUninstall();
this.onClose();
},
可以看到,handleMaskClick会判断maskClosable是否为true,如果为true,那么就会触发hide方法,hide则会在关闭一些事件监听后,触发onClose,这个是由prop接收的回调。
那么为什么会有人认为element ui的图片预览组件不支持点击遮罩层关闭呢?
我看了下框架的更新日志,这个点击mask关闭功能是在 2.15.0版本更新的,也就是说在那之前,是没有这个功能的,所以,这是个历史遗留问题,好在,现在都有解决方式了。
issues地址:https://github.com/ElemeFE/element/pull/20652
self修饰符表示事件必须是绑定的这个元素本身触发的才会触发函数,不会被冒泡啥的触发。
所以,我们如果想开关这个功能,就需要在中间层绑定这个属性,并prop接收一个对应的设置。
具体后面看完整代码
一些其他配置
图片预览组件还有一些其他配置:
- zIndex 层级
- onSwitch 当图片切换时的回调,参数为图片的index下标
- initialIndex 首次显示时显示的图片index下标
- appendToBody 是否允许传入body
差不多就是这些,所以,如果想完美一点的配置,我们就应该在管理中间层都要对这些参数进行绑定,并且在prop中加上接收对应属性的配置
完整版管理中间件
<template>
<transition name="viewer-fade">
<ElImageViewer v-if="show" :z-index="zIndex" :initial-index="imageIndex" :urlList="urlList"
:on-close="closeViewer" :on-switch="switchViewer" :appendToBody="appendToBody"
:maskClosable="maskClosable" />
</transition>
</template>
<script>
import ElImageViewer from "element-ui/packages/image/src/image-viewer";
export default {
props: {
urlList: {
type: Array,
default: () => [],
},
zIndex: {
type: Number,
default: 2000,
},
onSwitch: {
type: Function,
default: () => {},
},
onClose: {
type: Function,
default: () => {},
},
initialIndex: {
type: Number,
default: 0,
},
appendToBody: {
type: Boolean,
default: true,
},
maskClosable: {
type: Boolean,
default: true,
},
},
data() {
return {
show: false,
};
},
methods: {
closeViewer() {
this.show = false;
this.onClose();
},
switchViewer(index) {
this.onSwitch(index);
},
},
components: {
ElImageViewer,
},
};
</script>
构造器调整
preview.js:
import PreviewItem from "./Preview.vue";
const Preview = {};
Preview.install = function (Vue) {
const PreviewConstructor = Vue.extend(PreviewItem);
const instance = new PreviewConstructor();
instance.$mount(document.createElement("div"));
document.body.appendChild(instance.$el);
Vue.prototype.$showImg = function (urlList=[],initialIndex=0,onSwitch=()=>{}) {
//在这里加上一些配置
instance.urlList = urlList;
instance.initialIndex = initialIndex;
instance.onSwitch = onSwitch;
instance.show = true;
}
}
export default Preview;
具体的一些用法,可能会有一些自定义,所以这里是一个示例,没有经过测试,主要是同事写好了,我再去改的话有点吃饱了,就记个笔记在这。
如果你在使用中发现了问题,欢迎留言反馈,我会第一时间处理的,所以留言一定要留真实邮箱地址,才能接收到我的回复邮件。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
实现一个点击空白区域关闭显示的自定义指令
typescriptimport type { DirectiveBinding } from "vue"; export default { bind(el: HTMLElement, binding: DirectiveBinding<Function>) { //声明一个给document绑定的事件 function documentClick(event: Event) { const target = event.target as unknown as Node; if (el.contains(t...
使用vue2.7的一些踩坑事项
eslint校验的一些问题(暂时无解)在初始化项目时勾选了eslint校验之后,升级vue 2.7版本后,eslint-plugin-vue这个插件需要升级到9+版本,我目前使用的版本是:"eslint-plugin-vue": "^9.4.0"具体的一些可以参考官方提供的2.7升级指南:2.7日志官方居然把这个写在了变更日志里面,按道理最好官方的文档上也有一份说明的,但是目前没有。虽然eslint的依赖更新到新版后确实解决了一些项目启动报错的问题,但是有时候我们的SFC单文件组件开发的时候,template中的一些变量绑定还是会出现波浪线警告,这...
正确使用vue3的ts类型声明
前言使用了ts最头疼的是什么,除了类型声明应该没有第二家了,那么在vue3中如何正确的声明ts类型,代表着我们踏出了认识vue3的第一步,这非常重要,所以为此水个文章,分享给有需要的人。Volar 插件一开始我对于Volar并没有太大的需要,因为一直使用的Vetur,而且这个插件刚出来时并不完善,各种视频up讲的那个一键分屏功能其实也并不好用,虽然是个很有意思的东西,但是没有那种非要使用它的点,所以当时的我怀着这么一个疑问?为什么要用Volar ?现在我就通过两张图告诉你,它有多香!我们在template里面写代码,绑定变量最烦的是什么,就是我们写了个对象,但是忘了它的属性有哪些啊,使用...

关于给css自动添加浏览器前缀
前言为了兼容之前的旧浏览器版本,特别是安卓4.4这种低版本,transform是一定得增加浏览器前缀的,但是我在项目中遇到了设置无效的问题,极度蛋疼,下面是我的解决教程,当然没这个问题,看这篇文章,相信你对如果给项目增加浏览器前缀,会有很充分的认识。教程给css增加浏览器前缀,业界的做法就是使用postcss,目前webpack与vue cli他们需要安装的依赖略有不同:webpack:pnpm i postcss postcss-loader autoprefixer -D添加对应的rules{ test: /.s?css$/, use: [ ...省略...
vuex 动态注册和卸载模块
概述一般情况下,我们的vuex数据都是静态的,store在首次初始化后数据的格式就定好了,在日常使用中也确实应该这么做。但是,随着业务的发展,vuex可能会变得非常的大,或者在多页面打包的时候,每个页面都需要vuex,但是如果把每个页面的vuex都写在一起,你会发现,原来我a页面可能只需要30个vuex的数据监听,但是会多出来其他页面的数据,这显然不应该的。所以,我们需要一个能够动态加载模块的方法,每个页面动态加载自己的vuex数据使用。api了解vuex官方提供了几个api:registerModule动态注册模块apiunregisterModule卸载一个动态模块hasModule...
vue-i18n 的使用方式
安装vue2版需要安装8.x版本的,9.x的是vue3版本使用上大同小异。vue2安装:yarn add vue-i18n@8vue3安装:yarn add vue-i18n封装官方虽然支持很不错的用法,但是自定义处理是难免的。vue3文件目录结构├─ src │ ├─ language │ │ ├─ lang │ │ │ ├─ en.json │ │ │ └─ zh.json │ │ ├─ core │ │ │ ├─ i18n.ts │ │ │ ├─ customization.ts │ │ │ └─ language.ts │ │ ├─ i...
vue router 一个重定向页面的思路
当项目需要和其他项目进行沟通的时候,往往常见的做法就是,我在a网站点击一个按钮,在链接中携带query参数啥的,然后去访问b网站页面。此时可能会有两种情况:跳转的链接就是b网站的具体链接地址。跳转的链接是b网站的一个跳板,跳板会对参数做一些操作,然后进行重定向。两种做法都各有优势:第一种省事简单,但是如果以后b网站链接层级发生变化,那么就会导致链接不可能,到时候还需要进行修改,很痛苦。第二种的话,我们需要写一个跳板页面,但是通过一些参数要求,甚至自身加上一些逻辑处理,那么他的功能性会更强一些。那么,在vue中,做一个重定向页面,怎么做?思路思路1利用路由守卫,当链接上存在某个参数的时候,...
vue 过滤器 驼峰与短横线相互转换的方法
自己去注册吧,提供的是es6导出的方法//短横线转驼峰 export const dashToHump = function (value) { const textArr = value.split("-"); return textArr.map((item, index) => { if (index === 0) return item.toLowerCase(); return item.slice(0, 1).toUpperCase() + item.slice(1); }) .join("")...
使用vue.draggable拖拽组件遇到的一些问题
资源github:vue.draggable中文文档:vue.draggable中文文档api参考文档:sortablejsvue.draggable是基于sortablejs的vue封装,所有有些api官方并不会有过多的解释,可以去sortablejs查看下拖拽无法触发页面滚动当拖拽的内容大于页面宽高时,页面滚动就是一个必然的需求,但是vue.draggable默认情况并不能触发滚动。官方设置里有一个属性:scroll,如果为true时就能触发滚动,但是默认属性就是true;所以这个配置可以说是无效的。解决方案:cannot set scrollSensitivity19年的时候就有提...

关于 element table多选里面实现单选的偷懒做法
在elment的table多选中增加单选逻辑,这个也不能说产品的问题,单选和多选应该算是比较基础的应用,但是,element并没有对单选做支持。于是我有了一个偷懒思路!前提由于table的一键全选按钮无法进行细致化操作,无法控制点击时选中的数量,只能在选中后的回调里面处理,所以,我的做法是单选时隐藏这个按钮。 selectable方法可以返回布尔值来表示当前格子是否允许勾选或者取消,其实就是禁用的意思。<el-table-column type="selection" :selectable="onSelectable"></el...
