背景
element-ui没有直接用js调用图片的组件,自己写一下
写图片预览组件前,我们要了解两个vue方法:
1:h()
它是render函数的辅助函数,用来创建虚拟DOM。
它接受三个参数,第一个是需要创建的组建或者普通标签;第二个是传递给组建的props或者标签属性;第三个参数是标签内加上内容,第一个参数为组件是无效。
2:render()
render函数就是将h()方法生成的虚拟DOM转换成真实DOM,再渲染到指定DOM下。
它接受两个参数,第一个是h()生出的虚拟DOM;第二个是渲染到哪个DOM下。
// 创建标签
const vNode = h('div', {
class: 'demo'
}, '内容')
render(vNode, document.body)
// 相当于在body标签下创建
// <div class="demo">内容</div>
// 创建组件
const vNode = h(imagePreview, {
url,
cancelHandler
})
render(vNode, document.body)
// 相当于在body标签下创建
// <imagePreview :url="url" :cancelHandler="cancelHandler" />
了解了这两个方法后我们就可以分三步走来写图片预览组件了。
实现
第一步
我们建一个图片预览组件image.vue,主要就两点,一个是接收外部传入的图片url,另一个是关闭图片预览事的回调事件。
<template>
<div class="wrap">
<img :src="url" alt="">
<div class="close" @click="handleCancel">x</div>
</div>
</template>
<script setup>
import { onMounted, ref, render } from 'vue';
const props = defineProps({
// 接收传入的图片url
url: {
type: String,
default: ''
},
// 关闭回调事件
cancelHandler: {
type: Function
}
})
// 关闭事件
const handleCancel = () => {
// 调用回调事件
props.cancelHandler()
// 清空dom
render(null, document.body)
}
</script>
<style lang="less" scoped>
.wrap {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background-color: rgba(0, 0, 0, .2);
img {
max-width: 100%;
max-height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.close {
position: absolute;
right: 20px;
top: 20px;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
background-color: #fff;
border-radius: 50%;
cursor: pointer;
}
}
</style>
第二步
创建imgPreview.js来生成图片预览组件dom,以及将创建方法暴露出去。
import { h, render } from 'vue'
import image from './imagePreview.vue'
export const imagePreview = (url) => {
// 使用promise,在关闭预览后,.then里可以做后面的操作
return new Promise((reslove, reject) => {
// 关闭后reslove()
const cancelHandler = () => {
reslove()
}
// 创建图片预览组件虚拟dom
const vNode = h(image, {
url,
cancelHandler
})
// 将图片预览组件渲染到body标签下
render(vNode, document.body)
})
}
第三步
就是调用imagePreview方法来使用图片预览组件了
<template>
<div class="demo">
<button @click="handlePreview">预览图片</button>
</div>
</template>
<script setup>
import { imagePreview } from '@/components/imagePreview.js'
const handlePreview = () => {
imagePreview('https://img2.baidu.com/it/u=2719958522,3840000478&fm=253&fmt=auto&app=138&f=JPEG?w=380&h=380').then(() => {
console.log('关闭图片')
})
}
</script>
<style lang="less" scoped>
</style>