Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
本文主要實(shí)現(xiàn)在vue代碼中,將html代碼、js代碼以及css代碼嵌入div中,并使用html代碼與vue的通信,實(shí)現(xiàn)雙擊圖片,調(diào)用vue里面的方法,實(shí)現(xiàn)圖片的旋轉(zhuǎn)、放大等功能。
雙擊圖片會(huì)調(diào)用imgDbClick方法,此方法為html里面的方法。
<img ondblclick="imgDbClick(this)" src="http:127.0.0.1/test/test.png">
雙擊圖片時(shí)會(huì)調(diào)用此方法,此方法會(huì)發(fā)起跨域通信。
/*點(diǎn)擊圖片觸發(fā)*/
var imgDbClick=function (img) {
window.parent.postMessage({
cmd: 'dealImg',
params: {
url: img.src,
}
}, '*');
};
在下面的div中嵌入html代碼
<div id="showHtml">
</div>
下方代碼中的htmlStr為具體的html代碼。
let element=document.getElementById(activeName);
element.innerHTML=htmlStr;
因?yàn)閖s代碼存在文件服務(wù)器上,所以采用文件引入的方式。
//動(dòng)態(tài)綁定script
let scriptElement=document.createElement("script");
scriptElement.type="text/javascript";
scriptElement.src="http://127.0.0.1/test/common_code/common.js";
element.append(scriptElement);
css代碼存在文件服務(wù)器上,所以采用文件引入的方式。
let styleElement=document.createElement("link");
styleElement.rel="stylesheet";
styleElement.type="text/css";
styleElement.href="http://127.0.0.1/test/common_code/common.css";
element.append(styleElement);
監(jiān)聽(tīng)message,拿到圖片的地址,并使用viewer來(lái)實(shí)現(xiàn)旋轉(zhuǎn)、放大等功能
window.addEventListener('message',(event)=>{
const res=event.data;
if(res.cmd=='dealImg'){
let url=res.params.url;
//需要引入其它文件,見(jiàn)8、9、10
this.$viewerApi({
images: [url]
})
}
})
使用npm命令安裝v-viewer
npm install v-viewer
在main.js中全局引用
import 'viewerjs/dist/viewer.css'
import { api as viewerApi } from "v-viewer"
Vue.prototype.$viewerApi=viewerApi;
imagesArr為url數(shù)組,在需要使用的地方調(diào)用即可
this.$viewerApi({
images: imagesArr
})
創(chuàng)建一個(gè)組件插入body中,使用固定定位生成一個(gè)全局遮罩層,再把圖片放進(jìn)去
創(chuàng)建組件/components/PreviewImage/index.vue
搭建組件結(jié)構(gòu),傳入url數(shù)組,以及打開(kāi)的當(dāng)前圖片索引下標(biāo),以便進(jìn)行翻頁(yè)查看
如果遮罩層后面頁(yè)面有滾動(dòng)條時(shí)在組件打開(kāi)時(shí),需要禁止背景內(nèi)容隨鼠標(biāo)滾輪滾動(dòng),每次打開(kāi)關(guān)閉時(shí)給body動(dòng)態(tài)增加樣式 overflow: hidden屬性即可
<template>
<div v-if="show" class="previewImage_wrapper">
<div class="previewImage_image">
<img :src="previewImgList[currentIndex] || ''">
</div>
<div class="previewImage_close previewImage_btn" @click="closePreviewImage">×</div>
<div class="previewImage_navigation">
<span class="previewImage_navigation_left previewImage_btn" @click="prevImage"><</span>
<span class="previewImage_navigation_right previewImage_btn" @click="nextImage">></span>
</div>
</div>
</template>
<script>
export default {
props: {
visible: { // 顯示控制
type: Boolean,
default: false
},
previewImgList: { // url數(shù)組
type: Array,
default: ()=> []
},
currentIndex: { // 當(dāng)前圖片索引
type: Number,
default: 0
}
},
computed: {
// 雙向綁定
show: {
get() {
return this.visible
},
set(newVal) {
this.$emit('update:visible', newVal)
}
}
},
watch: {
visible: { // 給body動(dòng)態(tài)增加style屬性,禁止背景內(nèi)容的鼠標(biāo)滾輪滾動(dòng)
handler(newVal) {
if(newVal) {
document.body.style.overflow="hidden";
} else {
document.body.style.overflow="";
}
}
},
},
methods: {
// 上一張圖片
prevImage() {
if (this.currentIndex===0) {
this.currentIndex=this.previewImgList.length - 1
} else {
this.currentIndex--
}
},
// 下一張圖片
nextImage() {
if (this.currentIndex===this.previewImgList.length - 1) {
this.currentIndex=0
} else {
this.currentIndex++
}
},
// 關(guān)閉預(yù)覽圖片組件
closePreviewImage() {
this.show=false
}
},
mounted() { // 插入body
document.body.appendChild(this.$el);
},
destroyed() { // 組件銷毀后同步清除元素
this.$el.parentNode.removeChild(this.$el);
}
}
在打開(kāi)遮罩層時(shí)加上過(guò)渡效果,讓組件體驗(yàn)更好
定義過(guò)渡動(dòng)畫,使用vue推薦使用自帶的 組件,這樣切換顯示隱藏都會(huì)觸發(fā)過(guò)渡效果,如果以class類名的形式定義的過(guò)渡動(dòng)畫,在使用指令時(shí)v-if或者v-show 隱藏關(guān)閉時(shí)不會(huì)觸發(fā)結(jié)束的過(guò)渡效果
<transition name="zoom">
<!-- 組件 -->
</transition>
.zoom-enter, .zoom-leave-to { // 元素進(jìn)入和離開(kāi)時(shí)的動(dòng)作
transform: scale(0);
}
.zoom-enter-active, .zoom-leave-active { // 元素進(jìn)入和離開(kāi)時(shí)的過(guò)渡動(dòng)畫定義
transition: transform 0.3s;
}
效果如下
效果實(shí)現(xiàn)了,接下來(lái)還可以加入更多的功能
在圖片底部加一個(gè)控制工具欄,例如對(duì)預(yù)覽圖片的控制,放大、縮小、翻轉(zhuǎn)等。在封裝組件實(shí)現(xiàn)功能的時(shí)候我們應(yīng)當(dāng)先實(shí)現(xiàn)基礎(chǔ)功能,再深入開(kāi)發(fā)細(xì)節(jié)功能
想要實(shí)現(xiàn)元素的放大縮小,翻轉(zhuǎn),可以直接利用css3中transform屬性中的 scale rotate,然后使用 js 進(jìn)行動(dòng)態(tài)控制
<script>
export default {
data() {
return {
imgHandle: { // 圖片控制
scale: 1,
rotate: 0
}
}
},
methods: {
// 初始化還原圖片縮放旋轉(zhuǎn)控制
async initImgHandle() {
this.imgHandle={
scale: 1,
rotate: 0
}
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 放大圖片
async largeHandle() {
console.log(this.imgHandle.scale, 'scale')
this.imgHandle.scale=Number((this.imgHandle.scale + 0.2).toFixed(2)) // 使用toFixed防止小數(shù)點(diǎn)精度不準(zhǔn)
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 縮小圖片
async shrinkHandle() {
console.log(this.imgHandle.scale, 'scale')
if (this.imgHandle.scale===0.2) { // 最低縮放到0.2倍
return
}
this.imgHandle.scale=Number((this.imgHandle.scale - 0.2).toFixed(2)) // 使用toFixed防止小數(shù)點(diǎn)精度不準(zhǔn)
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
}
}
</script>
在進(jìn)行小數(shù)點(diǎn)計(jì)算的時(shí)候,要注意小數(shù)點(diǎn)的精度問(wèn)題,不然可能會(huì)導(dǎo)致計(jì)算出錯(cuò)產(chǎn)生bug,這里使用 toFixed 來(lái)解決下
在 JavaScript 中處理小數(shù)計(jì)算時(shí),會(huì)遇到舍入誤差導(dǎo)致計(jì)算結(jié)果不準(zhǔn)確的情況。這是由于 JavaScript 中采用的是雙精度浮點(diǎn)數(shù)格式(IEEE 754 標(biāo)準(zhǔn))來(lái)表示數(shù)字,而這種格式無(wú)法準(zhǔn)確地表示某些十進(jìn)制小數(shù)
接下來(lái)寫旋轉(zhuǎn)的方法,然后給元素綁定點(diǎn)擊事件就ok了
<script>
export default {
methods: {
// 向左翻轉(zhuǎn)
async turnLeftHandle() {
this.imgHandle.rotate=this.imgHandle.rotate - 90
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 向右翻轉(zhuǎn)
async turnRightHandle() {
this.imgHandle.rotate=this.imgHandle.rotate + 90
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
}
}
</script>
最后記得給img圖片加上過(guò)渡效果 transition: transform 0.3s ease; ,當(dāng)控制圖片操作的時(shí)候更平滑
最后的效果如下
組件完整代碼/components/PreviewImage/index.vue
<template>
<transition name="zoom">
<div v-if="show" class="previewImage_wrapper" @wheel="handleScroll">
<div class="previewImage_image">
<img ref="previewImage_img" :src="previewImgList[currentIndex] || ''">
</div>
<div class="previewImage_close previewImage_btn" @click="closePreviewImage">×</div>
<div class="previewImage_navigation">
<span class="previewImage_navigation_left previewImage_btn" @click="prevImage"><</span>
<span class="previewImage_navigation_right previewImage_btn" @click="nextImage">></span>
</div>
<div class="previewImage_toolbar">
<span class="previewImage_btn" @click="shrinkHandle">-</span>
<span class="previewImage_btn" @click="largeHandle">+</span>
<span class="previewImage_btn" @click="turnLeftHandle">?</span>
<span class="previewImage_btn" @click="initImgHandle">?</span>
<span class="previewImage_btn" @click="turnRightHandle">?</span>
</div>
</div>
</transition>
</template>
<script>
export default {
props: {
visible: { // 顯示控制
type: Boolean,
default: false
},
previewImgList: { // url數(shù)組
type: Array,
default: ()=> []
},
currentIndex: { // 當(dāng)前圖片索引
type: Number,
default: 0
}
},
data() {
return {
imgHandle: { // 圖片控制
scale: 1,
rotate: 0
}
}
},
computed: {
// 雙向綁定
show: {
get() {
return this.visible
},
set(newVal) {
this.$emit('update:visible', newVal)
}
}
},
watch: {
visible: { // 給body動(dòng)態(tài)增加style屬性,禁止背景內(nèi)容的鼠標(biāo)滾輪滾動(dòng)
handler(newVal) {
if(newVal) {
document.body.style.overflow="hidden";
this.initImgHandle() // 每次打開(kāi)圖片初始化
} else {
document.body.style.overflow="";
}
}
},
},
methods: {
// 鼠標(biāo)滾輪
handleScroll(event) {
if (event.deltaY > 0) {
// 向下滾動(dòng)事件
// console.log('向下滾動(dòng)');
this.shrinkHandle()
} else {
// 向上滾動(dòng)事件
// console.log('向上滾動(dòng)');
this.largeHandle()
}
},
// 向左翻轉(zhuǎn)
async turnLeftHandle() {
this.imgHandle.rotate=this.imgHandle.rotate - 90
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 向右翻轉(zhuǎn)
async turnRightHandle() {
this.imgHandle.rotate=this.imgHandle.rotate + 90
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 初始化還原圖片縮放旋轉(zhuǎn)控制
async initImgHandle() {
this.imgHandle={
scale: 1,
rotate: 0
}
await this.$nextTick()
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 放大圖片
async largeHandle() {
console.log(this.imgHandle.scale, 'scale')
this.imgHandle.scale=Number((this.imgHandle.scale + 0.2).toFixed(2)) // 使用toFixed防止小數(shù)點(diǎn)精度不準(zhǔn)
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 縮小圖片
async shrinkHandle() {
console.log(this.imgHandle.scale, 'scale')
if (this.imgHandle.scale===0.2) { // 最低縮放到0.2倍
return
}
this.imgHandle.scale=Number((this.imgHandle.scale - 0.2).toFixed(2)) // 使用toFixed防止小數(shù)點(diǎn)精度不準(zhǔn)
const element=this.$refs.previewImage_img
element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
},
// 上一張圖片
prevImage() {
if (this.currentIndex===0) {
this.currentIndex=this.previewImgList.length - 1
} else {
this.currentIndex--
}
this.initImgHandle()
},
// 下一張圖片
nextImage() {
if (this.currentIndex===this.previewImgList.length - 1) {
this.currentIndex=0
} else {
this.currentIndex++
}
this.initImgHandle()
},
// 關(guān)閉預(yù)覽圖片組件
closePreviewImage() {
this.show=false
}
},
mounted() { // 插入body
document.body.appendChild(this.$el);
},
destroyed() { // 組件銷毀后同步清除元素
this.$el.parentNode.removeChild(this.$el);
}
}
</script>
<style lang="less" scoped>
.previewImage_wrapper{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, .5);
z-index: 9999;
.previewImage_image{
display: flex;
align-items: center;
justify-content: center;
img {
width: 100vw;
height: 100vh;
object-fit: scale-down;
transition: transform 0.3s ease;
}
}
.previewImage_close{
position: absolute;
right: 20px;
top: 20px;
transition: transform 0.2s ease-out;
&:hover{
transform: scale(1.2);
}
}
.previewImage_navigation{
&_left{
position: absolute;
left: 15px;
top: 50%;
transform: translate(0, -50%);
transition: transform 0.2s ease-out;
}
&_right{
position: absolute;
right: 15px;
top: 50%;
transform: translate(0, -50%);
transition: transform 0.2s ease-out;
}
&_left:hover,&_right:hover{
transform: translate(0, -50%) scale(1.2);
}
}
.previewImage_toolbar{
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
display: flex;
align-items: center;
span{
margin-right: 10px;
transition: transform 0.2s ease-out;
&:hover{
transform: scale(1.1) ;
}
}
span:last-child{
margin-right: 0;
}
}
.previewImage_btn{
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #fff;
background-color: #606266;
border-radius: 50%;
cursor: pointer;
}
}
.zoom-enter, .zoom-leave-to { // 元素進(jìn)入和離開(kāi)時(shí)的動(dòng)作
transform: scale(0);
}
.zoom-enter-active, .zoom-leave-active { // 元素進(jìn)入和離開(kāi)時(shí)的過(guò)渡動(dòng)畫定義
transition: transform 0.3s;
}
.slide-enter, .slide-leave-to { // 元素進(jìn)入和離開(kāi)時(shí)的動(dòng)作
transform: translateX(100%);
}
.slide-enter-active, .slide-leave-active { // 元素進(jìn)入和離開(kāi)時(shí)的過(guò)渡動(dòng)畫定義
transition: transform 0.3s ease-in-out;
}
</style>
使用組件代碼
下是一個(gè)簡(jiǎn)單的示例代碼,用于實(shí)現(xiàn)鼠標(biāo)停留時(shí)圖片放大的效果:
/* 圖片樣式 */
.image {
width: 420px;
height: 280px;
transition: transform 0.2s;
}
/* 鼠標(biāo)停留時(shí)的樣式 */
.image:hover {
transform: scale(2.5);
}
在上述代碼中,定義了一個(gè) .image 類,用于設(shè)置圖片的初始樣式,包括寬度和高度。通過(guò) transition 屬性設(shè)置了圖片在變形時(shí)的過(guò)渡效果,時(shí)長(zhǎng)為 0.2 秒。
然后,當(dāng)鼠標(biāo)懸停在圖片上時(shí), .image:hover 類會(huì)將圖片進(jìn)行放大,通過(guò) transform: scale(2.5); 實(shí)現(xiàn)。其中, scale(2.5) 表示將圖片放大 2.5 倍。你可以根據(jù)實(shí)際需求調(diào)整放大的比例和過(guò)渡效果的時(shí)間。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。