整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          在vue中嵌入的html代碼中圖片使用v-viewe

          在vue中嵌入的html代碼中圖片使用v-viewer實現旋轉、放大等功能

          、前情提要

          本文主要實現在vue代碼中,將html代碼、js代碼以及css代碼嵌入div中,并使用html代碼與vue的通信,實現雙擊圖片,調用vue里面的方法,實現圖片的旋轉、放大等功能。

          二、具體實現

          1、要嵌入到vue代碼中的部分html代碼

          雙擊圖片會調用imgDbClick方法,此方法為html里面的方法。

           <img ondblclick="imgDbClick(this)" src="http:127.0.0.1/test/test.png">
          

          2、imgDbClick方法

          雙擊圖片時會調用此方法,此方法會發起跨域通信。

          /*點擊圖片觸發*/
          var imgDbClick=function (img) {
              window.parent.postMessage({
                  cmd: 'dealImg',
                  params: {
                      url: img.src,
                  }
              }, '*');	
          };
          

          3、vue中的代碼

          在下面的div中嵌入html代碼

                    <div id="showHtml">
                    </div>
          

          4、嵌入html代碼

          下方代碼中的htmlStr為具體的html代碼。

                    let element=document.getElementById(activeName);
                    element.innerHTML=htmlStr;
          

          5、嵌入js代碼

          因為js代碼存在文件服務器上,所以采用文件引入的方式。

                    //動態綁定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);
          

          6、嵌入css代碼

          css代碼存在文件服務器上,所以采用文件引入的方式。

            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);
          

          7、監聽html的通信

          監聽message,拿到圖片的地址,并使用viewer來實現旋轉、放大等功能

                    window.addEventListener('message',(event)=>{
                      const res=event.data;
                      if(res.cmd=='dealImg'){
                        let url=res.params.url;
                        //需要引入其它文件,見8、9、10
                        this.$viewerApi({
                          images: [url]
                        })
                      }
                    })
          

          8、使用v-viewer

          使用npm命令安裝v-viewer

          npm install v-viewer
          

          9、全局引用

          在main.js中全局引用

          import 'viewerjs/dist/viewer.css'
          import { api as viewerApi } from "v-viewer"
          Vue.prototype.$viewerApi=viewerApi;
          

          10、使用

          imagesArr為url數組,在需要使用的地方調用即可

                    this.$viewerApi({
                        images: imagesArr
                    })
          

          三、實現效果

          裝步驟

          插入body,制作全局遮罩層、禁止背景滾動

          創建一個組件插入body中,使用固定定位生成一個全局遮罩層,再把圖片放進去

          創建組件/components/PreviewImage/index.vue

          搭建組件結構,傳入url數組,以及打開的當前圖片索引下標,以便進行翻頁查看

          如果遮罩層后面頁面有滾動條時在組件打開時,需要禁止背景內容隨鼠標滾輪滾動,每次打開關閉時給body動態增加樣式 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數組
                type: Array,
                default: ()=> []
              },
              currentIndex: { // 當前圖片索引
                type: Number,
                default: 0
              }
            },
            computed: {
              // 雙向綁定
              show: {
                get() {
                  return this.visible
                },
                set(newVal) {
                  this.$emit('update:visible', newVal)
                }
              }
            },
            watch: {
              visible: { // 給body動態增加style屬性,禁止背景內容的鼠標滾輪滾動
                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++
                }
              },
              // 關閉預覽圖片組件
              closePreviewImage() {
                this.show=false
              }
            },
            mounted() { // 插入body
              document.body.appendChild(this.$el);
            },
            destroyed() { // 組件銷毀后同步清除元素
              this.$el.parentNode.removeChild(this.$el);
            }
          }
          

          定義組件過渡動畫

          在打開遮罩層時加上過渡效果,讓組件體驗更好

          定義過渡動畫,使用vue推薦使用自帶的 組件,這樣切換顯示隱藏都會觸發過渡效果,如果以class類名的形式定義的過渡動畫,在使用指令時v-if或者v-show 隱藏關閉時不會觸發結束的過渡效果

          <transition name="zoom">
              <!-- 組件 -->
          </transition>
          .zoom-enter, .zoom-leave-to { // 元素進入和離開時的動作
            transform: scale(0);
          }
          .zoom-enter-active, .zoom-leave-active { // 元素進入和離開時的過渡動畫定義
            transition: transform 0.3s;
          }
          

          效果如下

          效果實現了,接下來還可以加入更多的功能

          結合 transform 實現圖片控制

          在圖片底部加一個控制工具欄,例如對預覽圖片的控制,放大、縮小、翻轉等。在封裝組件實現功能的時候我們應當先實現基礎功能,再深入開發細節功能

          想要實現元素的放大縮小,翻轉,可以直接利用css3中transform屬性中的 scale rotate,然后使用 js 進行動態控制

          <script>
          export default {
              data() {
                return {
                  imgHandle: { // 圖片控制
                    scale: 1,
                    rotate: 0
                  }
                }
              },
              methods: {
              // 初始化還原圖片縮放旋轉控制
              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防止小數點精度不準
                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防止小數點精度不準
                const element=this.$refs.previewImage_img
                element.style.transform=`scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)`
              },
              }
          }
          </script>

          在進行小數點計算的時候,要注意小數點的精度問題,不然可能會導致計算出錯產生bug,這里使用 toFixed 來解決下

          在 JavaScript 中處理小數計算時,會遇到舍入誤差導致計算結果不準確的情況。這是由于 JavaScript 中采用的是雙精度浮點數格式(IEEE 754 標準)來表示數字,而這種格式無法準確地表示某些十進制小數

          接下來寫旋轉的方法,然后給元素綁定點擊事件就ok了

          <script>
          export default {
              methods: {
                  // 向左翻轉
              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)`
              },
              // 向右翻轉
              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圖片加上過渡效果 transition: transform 0.3s ease; ,當控制圖片操作的時候更平滑

          最后的效果如下

          組件代碼

          組件完整代碼/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數組
                type: Array,
                default: ()=> []
              },
              currentIndex: { // 當前圖片索引
                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動態增加style屬性,禁止背景內容的鼠標滾輪滾動
                handler(newVal) {
                  if(newVal) {
                    document.body.style.overflow="hidden";
                    this.initImgHandle() // 每次打開圖片初始化
                  } else {
                    document.body.style.overflow="";
                  }
                }
              },
            },
            methods: {
              // 鼠標滾輪
              handleScroll(event) {
                if (event.deltaY > 0) {
                  // 向下滾動事件
                  // console.log('向下滾動');
                  this.shrinkHandle()
                } else {
                  // 向上滾動事件
                  // console.log('向上滾動');
                  this.largeHandle()
                }
              },
              // 向左翻轉
              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)`
              },
              // 向右翻轉
              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)`
              },
              // 初始化還原圖片縮放旋轉控制
              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防止小數點精度不準
                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防止小數點精度不準
                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()
              },
              // 關閉預覽圖片組件
              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 { // 元素進入和離開時的動作
            transform: scale(0);
          }
          .zoom-enter-active, .zoom-leave-active { // 元素進入和離開時的過渡動畫定義
            transition: transform 0.3s;
          }
          
          .slide-enter, .slide-leave-to { // 元素進入和離開時的動作
            transform: translateX(100%);
          }
          .slide-enter-active, .slide-leave-active { // 元素進入和離開時的過渡動畫定義
            transition: transform 0.3s ease-in-out;
          }
          </style>  

          使用組件代碼

          下是一個簡單的示例代碼,用于實現鼠標停留時圖片放大的效果:


          /* 圖片樣式 */

          .image {

          width: 420px;

          height: 280px;

          transition: transform 0.2s;

          }


          /* 鼠標停留時的樣式 */

          .image:hover {

          transform: scale(2.5);

          }


          在上述代碼中,定義了一個 .image 類,用于設置圖片的初始樣式,包括寬度和高度。通過 transition 屬性設置了圖片在變形時的過渡效果,時長為 0.2 秒。

          然后,當鼠標懸停在圖片上時, .image:hover 類會將圖片進行放大,通過 transform: scale(2.5); 實現。其中, scale(2.5) 表示將圖片放大 2.5 倍。你可以根據實際需求調整放大的比例和過渡效果的時間。


          主站蜘蛛池模板: 福利一区福利二区| 成人免费一区二区无码视频| 中文字幕一区二区人妻| 成人精品一区二区三区中文字幕| 中文字幕一区二区三区免费视频 | 日韩一本之道一区中文字幕| 久久精品免费一区二区三区 | AV无码精品一区二区三区宅噜噜| 亚洲日韩激情无码一区| 中字幕一区二区三区乱码 | 久久一区二区精品| 人妻av综合天堂一区| 久久se精品一区二区影院| 91精品一区二区三区久久久久| 日韩福利视频一区| 日本一区二区不卡视频| 国产成人精品无码一区二区老年人| 国产色情一区二区三区在线播放 | 无码精品人妻一区二区三区漫画 | 国产Av一区二区精品久久| 成人免费区一区二区三区| 日本一区二区三区不卡视频| 国产午夜精品一区二区三区| 日本精品一区二区三区视频| 九九无码人妻一区二区三区| 国产精品一区二区久久精品无码| 亚洲香蕉久久一区二区| 本免费AV无码专区一区| 国产午夜精品一区二区三区极品 | 伊人色综合一区二区三区影院视频| 日本精品一区二区久久久| 亚洲AV无码一区二区三区牛牛| 中文字幕色AV一区二区三区| 午夜在线视频一区二区三区| 亚洲电影一区二区三区| 成人午夜视频精品一区| 国产婷婷色一区二区三区深爱网| 无码国产精品一区二区免费vr | 亚洲AV无一区二区三区久久| 一区二区三区91| 国产成人一区二区三区高清 |