創建一個組件插入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;
}
效果如下
效果實現了,接下來還可以加入更多的功能
在圖片底部加一個控制工具欄,例如對預覽圖片的控制,放大、縮小、翻轉等。在封裝組件實現功能的時候我們應當先實現基礎功能,再深入開發細節功能
想要實現元素的放大縮小,翻轉,可以直接利用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>
這種方式比較適合那種需要給背景圖片上添加蒙版的情況,但是筆者嘗試的時候,結果實在是不盡人意。所以還是選擇了上面的推薦方法,不過這種方式要比上面的那種方式實現起來要簡單很多。如下所示。
<!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>
這種方式實現會影響到整個的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寬度為500px(像素),那你上傳的圖片或放入網頁的圖片寬度就要小于500px,也就是你圖片需要圖片軟件剪切、等比例縮小方法處理后再上傳、放入網頁中解決撐破撐開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層方法。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。