图片走廊&放大镜

大魏军营中
关羽:你怎么平天下?
曹:灭袁绍,平北方。怀柔江东孙家,驻军西凉,可谓中原一统太平。休养生息,不出十年,南蜀自然俯首称臣。
曹操再三表意皇帝不可杀,否则各方诸侯都会以此为借口群起造反。届时乱世将难以终结,可惜谋事在人成事在天,最后历史还是如此的进行着,以至于到了三分天下
从最初的汉室垂危黄巾起义到最后天下归一,六十年,国号不为蜀,不为魏,更不为吴,而是晋。
生逢乱世,有人成为了一代名将,一代谋士,一代君王;有人看淡了成败,有人认清了现实,有人年少成名,有人大器晚成,有人含恨而终,有人英勇赴死。
而作为历史的见证者,我们看到的则是“滚滚长江东逝水,浪花淘尽英雄”

咳咳,回到2018

距离返校还有不到十天的时间,抓紧多练习一些JS方面的小组件,原来只是想着练习图片走廊,但后来发现图片走廊一般都是搭配放大镜功能出现的,便一并写了,过程不算平坦。

关于图片走廊和放大镜

  1. 这次练习中,使用了queryselector的方法抓取元素,就效率而言虽没有getElementby..函数高,但胜在方便。也更加深入学习了DOM与BOM中的getAttributesetAttribute,各种距离相关的属性clientX/clientYgetBoundingClientRect(),加深了元素与浏览器之间互动的编程理解。

  2. 保存过程中有一点十分有趣,前半部分图片走廊是利用循环加上闭包给元素绑定事件,而后半段放大镜则是利用addEventListener事件监听的功能进行事件绑定。面对多种多样的编程方式,都应多加涉猎与练习思考。

  3. 不断地练习组件,但还是把它们放在一起,不然徒有一堆部件而不成完品。就想测试中既有单元测试也有集成测试一样。我把之前的轮播图和这次的图片走廊&放大镜放在一起进行编写,发现变量的命名是个大问题。论坛社区中一直强调的代码规范性第一次实打实的出现在了眼前,还需多加练习。

4.完成组件如图


正题↓

HTML部分

  1. 一个主盒子content,包含着上部分pic,下部分list。上部分展示大图,下部分图片走廊。cover是选择放大区域,而display是展现放大区域。

    <div class="content">
        <div class="pic">
        <img src="img/clothes1.jpg" alt="11" class="Big">
        <div class="cover"></div>
    </div>
    <ul class="list">
        <li><img src="img/clothes1.jpg" alt=""></li>
        <li><img src="img/clothes2.jpg" alt=""></li>
        <li><img src="img/clothes3.jpg" alt=""></li>
        <li><img src="img/clothes4.jpg" alt=""></li>
        <li><img src="img/clothes5.jpg" alt=""></li>
    </ul>
    <div class="display"></div>
    </div>
    

    CSS部分

  2. css部分没有多少新东西,就是div+css常规写法,就是图片走廊部分list采用flex弹性盒模型,还有justify-content属性。让布局省力了些。

    *{
        margin: 0;
        padding: 0;
        text-decoration: none;
        list-style-type: none;
    }
    
    .content{
        position: relative;
        width: 400px;
        height: 480px;
        margin: 60px auto;
        border: 1px solid orangered;
    }
    
    .Big{
        width: 400px;
        height: 400px;
    }
    
    .list{
        display: flex;
        margin-top: 5px;
        align-items: center;
        justify-content: space-around;
        height: 80px;
    }
    
    .list img{
        width: 50px;
        height: 50px;
        display: block;
    }
    
    .list .active{
        border: solid royalblue;
    }
    
    .cover{
        position: absolute;
        top: 0;
        left: 0;
        opacity: 0.3;
        width: 100px;
        height: 100px;
        background: blue;
        display: none;
    }
    
    .display{
        position: absolute;
        top: 0;
        left: 400px;
        width: 400px;
        height: 400px;
        background-image: url(../img/clothes1.jpg);
        background-size: 400%;    //思考
        display: none;
    }
    

JS部分

ps:由于代码思路并不是完全自顶向下,譬如一些函数调用时写到第80行才回到第25行进行调用,所以我尽量注解,我认为阅读代码也是一项技能,像电路板一样,时而一鼓作气,时而峰回路转,哈哈。

  1. 抓取元素

    var list = document.querySelector('.list'),
        imgs = list.querySelectorAll('img'),
        Big = document.querySelector('.Big'),
        pic = document.querySelector('.pic'),
        cover = document.querySelector('.cover'),
        display = document.querySelector('.display'),
        index = 0;   //square()函数将用到
    
  2. 开始抓取小图的src,并把小图的src设置给大图

  3. showPic(whichPic)中的whichPic是小图中的某个,小图并不是单一个,而是一个数组,我们要假设一个形参

    function showPic(whichPic){
        var small = whichPic.getAttribute('src');
        Big.setAttribute('src',small);
        display.style.backgroundImage = 'url('+ small +')'; //这行代码的作用是在后面display放大区域的呈现
    }
    
  4. 开始实现鼠标放置在指定小图,指定的小图实现border(其实可以加的不止是border,你也可以参照自己的想法加很多属性)

    function square(){
        for(var i = 0;i<imgs.length;i++){
            if(imgs[i].className = 'active'){
            imgs[i].className = '';
        }
    } 
      imgs[index].className = 'active'; //注意此行代码的位置,不要写错.这里的index如何放置也值得思考。
    

    }

  5. 这里我们已经将两大函数功能完成,剩下的是进行事件绑定

  6. 这里使用了立即执行函数也就是闭包(很多时候我们不用闭包功能依旧能实现,但错误的数字循环会让以后的程序拓展性堵死,不可取。要养成习惯)

  7. 我们把其中i的值赋给了index,因为0 1 2 3 4这样的计时走法完美符合square()函数的规则。我们指到哪个哪个就添加active

  8. 这里的showPic(this),我们把指定的小图(this),传给showPic()

for(var i = 0;i<imgs.length;i++){
(function(i){
    imgs[i].onmouseover = function(){
    showPic(this);
    index = i;
    square();
    }
})(i);  //这里的括号若不熟悉需要多多观察
}

ps:到这里,前半部分的功能算是结束了,下半部分则是运用事件监听来让cover随着鼠标移动,随即让放大区域display跟着移动。这里我搜索了很多,没办法,很多BOM DOM都需要在实践中学习。

  1. 我们抓取pic,并给它进行事件监听,这里参数e也需要多多思考

  2. 我们选取了 client X ,clientY 这两个是鼠标距离浏览器左上角的top值和left值

  3. getBoundingClientRect().left/top则是选取了元素距离浏览器左上角的top值和left值

  4. 我们想要cover随着移动,无非就是让cover的top值和left值随着鼠标的移动而产生变化。而cover的top值和left值就需要一个减法来实现

  5. 而这个值就是clientX减去getBoundingClientRect().left

  6. 为什么要这样,为什么要还要减50,如图所示(其实这里还是画的不太严谨,B指向的应该是cover小块的左上角,A指向大图的左上角)

  7. 垂直的Y轴同理,操作一致。

  8. 我们还要让coverpic框内不出去,要设定四个if语句

    pic.addEventListener('mousemove',function(e){
        cover.style.display = 'block';   //放置即出现
        display.style.display = 'block'; //放置即出现    
        var x = e.clientX,
            y = e.clientY,
            cx = pic.getBoundingClientRect().left,
            cy = pic.getBoundingClientRect().top,
            tx = x - cx - 50,
            ty = y - cy - 50;       
            if(tx<0){
                tx = 0;
            }
            if(ty<0){
                ty = 0;
            }
            if(tx>300){
                tx = 300;
            }
            if(ty>300){
                ty = 300;
            }
            cover.style.left = tx + 'px';    //取值
            cover.style.top = ty + 'px';    //取值
            display.style.backgroundPosition = tx/300*100 + '%' + ty/300 *100 + '%'; //让display内的背景图放大,需要思考
        })
    
  9. 我们还需要让鼠标移出大图时coverdisplay消失

    pic.addEventListener('mouseout',function(){
        cover.style.display = 'none';
        display.style.display = 'none';
    })
    

好了,到这里整个部件就完成了,不多不少。

这两个月,快接近尾声,战友们都按故旧班的完成着自己的任务,甚是开心。让人越来越期待出去的日子了。

完整代码在此–>GITHUB