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>