整合營銷服務商

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

          免費咨詢熱線:

          vue 封裝圖片預覽組件 圖片放大、縮小、旋轉

          裝步驟

          插入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>  

          使用組件代碼

          這樣一個需求,就是在一個DIV中包含有一個Image標簽,但是在Div標簽中包含有一張背景圖片,設計圖上的樣子是這張背景圖片是有一個透明度的,但是如果直接使用opacity屬性設置的的話就會連Div中的內容的透明度也會受到影響,那么我們如何在HTML中設置div背景圖片的透明度呢?,可以通過以下幾種方法實現。

          方法一:使用偽元素

          這是在日常開發中被推薦使用的方法,通過這種方式實現不會影響到div中的其他內容的透明度只會影響它自己背景的透明度,詳細實現如下。

          <!DOCTYPE html>
          <html>
          <head>
              <style>
                  .container {
                      position: relative;
                      width: 300px;
                      height: 200px;
                      overflow: hidden;
                  }
          
                  .container::before {
                      content: "";
                      background-image: url('your-image.jpg');
                      background-size: cover;
                      background-position: center;
                      position: absolute;
                      top: 0;
                      left: 0;
                      right: 0;
                      bottom: 0;
                      opacity: 0.5; /* 調整透明度 */
                      z-index: 1;
                  }
          
                  .content {
                      position: relative;
                      z-index: 2;
                      color: white;
                  }
              </style>
          </head>
          <body>
              <div class="container">
                  <div class="content">
                      這里是內容
                  </div>
              </div>
          </body>
          </html>

          方法二:使用RGBA顏色疊加

          這種方式比較適合那種需要給背景圖片上添加蒙版的情況,但是筆者嘗試的時候,結果實在是不盡人意。所以還是選擇了上面的推薦方法,不過這種方式要比上面的那種方式實現起來要簡單很多。如下所示。

          <!DOCTYPE html>
          <html>
          <head>
              <style>
                  .container {
                      width: 300px;
                      height: 200px;
                      background: rgba(255, 255, 255, 0.5) url('your-image.jpg') no-repeat center center;
                      background-size: cover;
                  }
              </style>
          </head>
          <body>
              <div class="container">
                  這里是內容
              </div>
          </body>
          </html>

          方法三:使用CSS濾鏡

          這種方式實現會影響到整個的div的樣式,也就是說頁面中的內容的透明度也會受到影響,并且這種影響不會被其他樣式所改變。如下所示。

          <!DOCTYPE html>
          <html>
          <head>
              <style>
                  .container {
                      width: 300px;
                      height: 200px;
                      background: url('your-image.jpg') no-repeat center center;
                      background-size: cover;
                      filter: opacity(0.5); /* 調整透明度 */
                  }
              </style>
          </head>
          <body>
              <div class="container">
                  這里是內容
              </div>
          </body>
          </html>

          以上就是實現如何調整div的背景透明度,在一些特殊場景中我們還可以通過JS的方式來實現。上面的方法中,推薦使用的是偽元素方法,因為它在修改了div背景透明度之后,并不會影響到其他的元素,RGBA色彩添加則是局限于一些色彩華麗的地方使用,而對于一些單色調的內容來講這種方式實現效果不是太好。通過CSS過濾樣式,雖然是最直接的方式,但是如果在div內部有內容的情況下會影響到整個組件體系的樣式。

          在實際開發中,我們可以選擇合適的方式來實現這個需求。當然還有其他的實現方式,有興趣的讀者可以留言我們一起討論。

          S方法:
          $("body").attr('style','overflow-y:hidden') //這個是解決豎狀滾動條
          //橫向 需要把
          overflow-y改成overflow-x即可
          CSS辦法:

          一、防止圖片撐破DIV方法一

          原始處理方法是將要展示的圖片進行處理。比如你的DIV寬度為500px像素,那你上傳的圖片或放入網頁的圖片寬度就要小于500px,也就是你圖片需要圖片軟件剪切、等比例縮小方法處理后再上傳、放入網頁中解決撐破撐開DIV問題。

          常見很多大型圖片站點、新聞站點都是將照片圖片進行處理適應網頁寬度情況下,進行圖片編輯處理的。

          二、防止圖片撐開DIV方法二

          如果不處理照片方法適應DIV有限寬度,那可以對DIV設置隱藏超出內容方法。只需要對DIV設置寬度后加入CSS樣式“overflow:hidden”即可解決隱藏圖片比DIV過寬部分解決撐破DIV問題

          三、解決方法三

          對圖片img標簽中只加入寬度即可解決。這樣可以等比例縮小圖片,不會影響圖片畫面質量。

          比如你的網頁DIV寬度為500px,那你上傳圖片后對img標簽設置width等于500以下即可。
          <img src="圖片路徑" width="小于你的DIV寬度" />即可解決圖片過寬導致DIV SPAN撐破,這樣好處可以等比例放大縮小圖片

          四、CSS解決撐破方法四

          這種方法使用CSS直接對div內的img進行寬度設置,這樣不好是如果圖片過小會影響網頁瀏覽圖片時候效果。

          Div結構:<div class="dc5"><img src="圖片路徑" /></div>
          對應CSS代碼:.dc5 img{寬度值+單位}

          五、CSS解決圖片撐破撐開DIV方法五

          使用max-width(最大寬度),比如你DIV寬度為500px,那你對應DIV樣式再加入最大寬度CSS樣式“max-width="500px"”即可解決,但是在IE6瀏覽器不兼容此屬性,謹慎使用。

          六、解決圖片撐破DIV層方法總結與推薦

          1)、最大寬度(max-width)+overflow:hidden。我們這樣設置可以讓IE6版本以上瀏覽器支持最大寬度樣式,也讓IE6下隱藏圖片超出寬度而撐開DIV得到解決,此方法比較方便和實用。

          2)、只使用overflow:hidden屬性,如方法二

          3)、圖片使用上傳時候軟件處理下,以適應DIV布局寬度,如方法一

          以上為推薦解決IMG圖片撐破有限DIV寬度方法,根據實際情況大家可以任意選擇適合自己解決網頁中圖片撐破DIV層方法。


          主站蜘蛛池模板: 激情内射日本一区二区三区| 日韩一区二区三区四区不卡| 亚洲第一区在线观看| 精品国产亚洲一区二区三区| 国产在线观看91精品一区| 亚洲第一区香蕉_国产a| 真实国产乱子伦精品一区二区三区 | 激情内射亚洲一区二区三区| 久久国产三级无码一区二区| 国产在线观看一区二区三区四区| 伊人久久精品无码麻豆一区| 91video国产一区| 亚洲AV日韩AV天堂一区二区三区| 精品一区二区三区高清免费观看 | 国产精品一区二区久久精品| 精品久久一区二区三区| 东京热人妻无码一区二区av| 亚洲片一区二区三区| 一区二区三区高清在线| 精品乱码一区二区三区在线| 国产伦精品一区二区三区四区| 国精产品一区一区三区MBA下载 | 精品一区二区三区高清免费观看| 人妻无码一区二区三区| 日本中文一区二区三区亚洲| 一区二区三区无码高清视频| 精品日韩在线视频一区二区三区 | 麻豆一区二区在我观看| 91一区二区在线观看精品| 国产成人亚洲综合一区| 久久精品无码一区二区三区不卡| 亚洲av无码片vr一区二区三区| 久久青青草原一区二区| 精品一区二区三区视频在线观看| 日韩精品一区二区三区视频| 中文字幕一区二区三| 久久久精品人妻一区二区三区| 制服丝袜一区在线| 国产精品成人一区二区三区| 一区二区高清在线| 亚洲一区二区在线视频|