Vue练习五十七_07_02_带Loading效果的图片切换
(太多使用了$refs来直接操作dom,有待更正)
需求:
1. 鼠标移至/离开左侧/右侧,显示/隐藏向左/向右切换图片按钮
2. 加载时添加Loading.gif,加载完成后消失(根据网速)
3. 图片标题/文字动态显示
4. 向左/向右切换至第一张/最末一张图片后,再次点击,弹出提示无更多图片
解析:
1. Html结构:1个大的div(id为big),包含5个子div:masks_L, masks_R, btn_L, btn_R, title。从id可知其用途,前2个为蒙版(其用途是当mouseover其上时,分别显示向左/向右按钮,离开则隐藏),后2个为左/右侧按钮,第5个为标题div,内含一个span元素。
2. 根据id获取各div引用,获取 span元素的引用
3. 设置data数据,为一个数组对象,由imgSrc和title2个属性组成,分别表示图片路径和标题文字
4. 给masks_L, masks_R,btn_L, btn_R添加mouseover/mouseout事件,调用startMove辅助函数,传入左右按钮,属性及数值。
5. startMove()辅助函数接受4个参数,obj对象,attr属性,属性数值及回调函数fnEnd。给obj添加计时器setinterval,调用doMove()并传递所有参数,每30毫秒执行一次。
6. doMove()辅助函数,接受4个参数,先根据对象及属性,调用辅助函数getStyle获取当前属性值。如属性为透明度opacity,则值需乘以100进行换算。接下给obj设置属性值。
7. 给btnL和btnR添加click事件处理器。先判断是否已无更多图片,(此处根据iNow计数器进行判断)如是,则return,如否,调用loadImg(),加载对应图片。
8. loadImg(),加载图片函数。给big(最外层容器div)添加loading类,加载Loading gif图片。设置标题div高度为0,设置span透明度为0。获取img元素的引用,如存在则先删除(调用removeChild)。创建一个img元素及new一个Image实例。给实例添加onload事件处理器,当加载成功后,先清除掉big(最外层div)的类,给Img元素添加src属性,设置其宽度(最大不超过800)和高度。给span元素添加文字(标题)调用startMove()先设置title(外层div)的高度,再设置span的透明度(由0到100),从完全透明到完全不透明。
以上为对原生js写就的程序的粗浅分析。
在使用vue改写时,需要考虑的最主要的地方是:以数据来驱动,而尽量不要直接操作dom.
1 在给maskL,maskR,btnL,btnR添加mouseover/mouseout处理器时,尝试以vue中的transition组件来操作元素的显示/隐藏,既将btnL,btnR包裹在transition组件中,同时给mask/btn添加over/out事件处理器,添加bollean数据show,当over时,为真时显示,out则为false,隐藏。说白了,Mask相当于2个大型的按钮
<template>
<div id="big" :class="{loading:isBigActive}" ref="myBig">
<div id="masks_L" @mouseover="handleLeftOver" @mouseout="handleLeftOut"></div>
<div id="masks_R" @mouseover="hanldeRightOver" @mouseout="handleRightOut"></div>
<div ref="btnL" id="btn_L" @mouseover="handleLeftOver" @mouseout="handleLeftOut" @click="handleLeftClick"></div>
<div ref="btnR" id="btn_R" @mouseover="hanldeRightOver" @mouseout="handleRightOut" @click="handleRightClick"></div>
<div id="title" ref="myTitle"><span ref="mySpan"></span></div>
</div>
</template>
<script>
function getStyle(obj,attr){return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj,null)[attr]}
export default {
data(){
return{
iNow:0,
isbtnLShow:false,
isbtnRShow:false,
isBigActive:false,
imgdata:[
{'imgSrc':'http://img1.gtimg.com/news/pics/hv1/106/238/825/53706421.jpg','title':'7月26日,吊车将事故现场的车头残片吊至大型运输车辆上。'},
{'imgSrc':'http://img1.gtimg.com/news/pics/hv1/105/238/825/53706420.jpg','title':'7月26日,一辆大卡车准备驶离事故现场。'},
{'imgSrc':'http://img1.gtimg.com/news/pics/hv1/101/238/825/53706416.jpg','title':'7月26日,工人在给最后一节车厢盖上彩条布,准备运离现场。'},
{'imgSrc':'http://img1.gtimg.com/news/pics/hv1/99/238/825/53706414.jpg','title':'7月26日,一名工人在事故现场最后一节车厢上作业。'},
{'imgSrc':'http://img1.gtimg.com/news/pics/hv1/100/238/825/53706415.jpg','title':'7月26日,工人在给最后一节车厢盖上彩条布,准备运离现场。'}
]
}
},
methods:{
handleLeftOver(){
this.startMOve(this.$refs.btnL,'opacity',100);
//this.isbtnLShow=true;
},
handleLeftOut(){
this.startMOve(this.$refs.btnL,'opacity',0);
//this.isbtnLShow=false;
},
hanldeRightOver(){
this.startMOve(this.$refs.btnR,'opacity',100);
//this.isbtnRShow=true;
},
handleRightOut(){
this.startMOve(this.$refs.btnR,'opacity',0);
//this.isbtnRShow=false;
},
startMOve(obj,attr,iTarget,fnEnd){
var _this=this;
clearInterval(obj.timer);
obj.timer=setInterval(() => {
_this.doMove(obj,attr,iTarget,fnEnd);
}, 20);
},
doMove(obj,attr,iTarget,fnEnd){
var iCur = parseFloat(getStyle(obj, attr));
if (attr == "opacity") {
iCur = parseInt(iCur * 100)
}
var iSpeed = (iTarget - iCur) / 5;
iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
if (iTarget == iCur) {
clearInterval(obj.timer);
fnEnd && fnEnd();
}
else {
if (attr == "opacity") {
obj.style.filter = "alpha(opacity = " + (iCur + iSpeed) + ")";
obj.style.opacity = (iCur + iSpeed) / 100;
}
else {
obj.style[attr] = iCur + iSpeed + "px";
}
}
},
handleLeftClick(){
if(this.iNow <= 0){
alert('前面没有图片了!');
return;
}
this.iNow--;
this.loadImg();
},
handleRightClick(){
if(this.iNow >= this.imgdata.length -1){
alert('这是最后一张图片了!');
return;
}
this.iNow++;
this.loadImg();
},
loadImg(){
var _this =this;
this.isBigActive=true;
var myBig=this.$refs.myBig;
var myTitle=this.$refs.myTitle;
var mySpan=this.$refs.mySpan;
mySpan.style.opacity=myTitle.style.height=0;
var oImg=myBig.getElementsByTagName('img');
oImg[0] && myBig.removeChild(oImg[0]);
var oTemp = document.createElement('img');
var oNewImg=new Image();
oNewImg.onload=function(){
_this.isBigActive=false;
oTemp.src=oNewImg.src;
myBig.appendChild(oTemp);
oTemp.style.width = (oTemp.offsetWidth > 800 ? 800 : oTemp.offsetWidth) + 'px';
myBig.style.height = oTemp.style.height = oTemp.offsetHeight * oTemp.offsetWidth / oTemp.offsetWidth + 'px';
//console.log(_this.imgdata);
mySpan.innerHTML=_this.imgdata[_this.iNow].title;
_this.startMOve(myTitle,'height',50,function(){
_this.startMOve(myTitle.childNodes[0],'opacity',100);
})
};
oNewImg.src=this.imgdata[this.iNow].imgSrc;
}
},
mounted(){
this.loadImg();
}
}
</script>
<style>
body, div, ul, li{
margin: 0;
padding: 0;
}
li{
list-style: none;
}
body{
font: 12px/1.5 \5fae\8f6f\96c5\9ed1;
background:#000;
}
#big{
position: relative;
width: 800px;
height: auto !important;
height: 400px;
min-width: 400px;
margin: 20px auto;
text-align: center;
}
#title{
position: absolute;
top:0;
left: 0;
width: 100%;
background: #000;
color: #fff;
opacity: 0.7;
filter: alpha(opacity=70);
font-size: 20px;
height: 50px;
}
#title span{
padding: 0 50px;
line-height: 50px;
display: block;
}
#big.loading{
background: url(./assets/lesson7/loading.gif) 50% 50% no-repeat;
}
#masks_L, #masks_R{
position: absolute;
top:0;
width: 400px;
height: 100%;
cursor: pointer;
background: #f0f0f0;
opacity: 0;
filter: alpha(opacity=0);
}
#masks_L{
left: 0;
}
#masks_R{
right: 0;
}
#btn_L, #btn_R{
position: absolute;
top:50%;
margin-top: -40px;
width: 39px;
height: 80px;
overflow: hidden;
cursor: pointer;
text-indent: -9999px;
background:url(./assets/lesson7/btn.png) no-repeat;
opacity: 0;
filter: alpha(opacity=0);
}
#btn_L{
left: 10px;
background-position: 0 0;
}
#btn_R{
right: 10px;
background-position: -39px 0;
}
</style>

浙公网安备 33010602011771号