懒加载瀑布流相册联合viewerjs响应式图片弹出层

懒加载图片预览,响应式图片弹出层,360度旋转放大缩小,幻灯片式全屏播放图片

image description

懒加载瀑布流相册联合viewerjs响应式图片弹出层

因为想弄一个壁纸相册,但又不想一次将所有图片都加载,所以需要懒加载,并且预览的图片为小尺寸图,点击图片后,才会显示大尺寸图,而且效果还需要炫。

之前也做过几版,但最后都不满意,放弃了,直到最近才弄到满意的。

废话不多说,在开始前,先准备点东西,css及js文件。可以从本站抓取,但不一定适用你自己的网站,可能css需要修改;也可以从素材火网站下载 jQuery懒加载图片的瀑布流插件viewerjs强大的响应式图片弹出层360度旋转放大缩小 这两个模板插件; 当然你要是想自己通过这两个模板插件学习,搞懂后,那基本也可以无视本篇文章了【滑稽笑】。

话不多说,因为本人只对laravel熟悉,所以本篇以laravel为例

  • 在视图目录中,新建一个album.blade.php文件;

    首先引入对应的css及js文件,如下:


    <link rel="stylesheet" href="{{asset('css/album.css')}}">
    <link rel="stylesheet" href="{{asset('css/viewer.min.css')}}">
    
    <script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/layer/3.0.3/layer.min.js"></script>
    <script src="{{asset('js/viewer-jquery.min.js')}}"></script>
  • 文件引入后,开始主内容,先写前端内容,如下:
    
    <div id="wrap">
        @foreach($albums as $album)
            <div class="box">
                <div class="info">
                    <div class="pic"><img data_original="{{page_image_size($album->name,1500,'albums')}}" src="{{page_image_size($album->name,300,'albums')}}"></div>
                </div>
            </div>
        @endforeach
    </div>

上述代码中,page_image_size()函数主要为我自己封装的一个处理图片链接的一个方法,你可以换成自己的,这个函数主要目的就是用来应该显示什么尺寸的图片,我会文章末尾处贴出来,仅供参考。

继续,下面为js的处理方法,如下:


    window.onload = function() {
        //运行瀑布流主函数
        PBL('wrap', 'box');
        //初始化图片弹出层
        $("#wrap").viewer({
            url: 'data_original'
        });
        //设置滚动加载
        //此处懒加载时,我做了点修改,原作者是用一段固定的json数据来处理的,我这边将其修改为通过ajax来获取后面的图片,代码在下面
        var page = 1;
        var u = "{{url('/album/get_more')}}";
        window.onscroll = function() {
            //校验数据请求
            if (getCheck()) {
                page++;
                $.ajax({
                    url:u,
                    type:"POST",
                    headers: {
                            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                    },
                    data: { album_page:page },
                    success:function(mag){
                        if(mag.status == 'success' && mag.content != ''){
                            var data = mag.content;
                            var wrap = document.getElementById('wrap');
                            for (i in data) {
                                //创建box
                                var box = document.createElement('div');
                                box.className = 'box';
                                wrap.appendChild(box);
                                //创建info
                                var info = document.createElement('div');
                                info.className = 'info';
                                box.appendChild(info);
                                //创建pic
                                var pic = document.createElement('div');
                                pic.className = 'pic';
                                info.appendChild(pic);
                                //创建img
                                var img = document.createElement('img');
                                img.src = data[i].src;
                                img.setAttribute('data_original',data[i].data_original);
                                img.alt = data[i].alt;
                                img.style.height = 'auto';
                                pic.appendChild(img);
                            }
                            PBL('wrap', 'box');
                            layer.msg(mag.message);
                        }else{
                            page--;
                            layer.msg(mag.message);
                        }
                    }
                });
                $("#wrap").viewer('update');
            }
        }
    }
    /**
     * 瀑布流主函数
     * @param  wrap [Str] 外层元素的ID
     * @param  box  [Str] 每一个box的类名
     */
    function PBL(wrap, box) {
        //  1.获得外层以及每一个box
        var wrap = document.getElementById(wrap);
        var boxs = getClass(wrap, box);
        //  2.获得屏幕可显示的列数
        var boxW = boxs[0].offsetWidth;
        var colsNum = Math.floor(document.documentElement.clientWidth / boxW);
        wrap.style.width = boxW * colsNum + 'px'; //为外层赋值宽度
        //  3.循环出所有的box并按照瀑布流排列
        var everyH = []; //定义一个数组存储每一列的高度
        for (var i = 0; i < boxs.length; i++) {
            if (i < colsNum) {
                everyH[i] = boxs[i].offsetHeight;
            } else {
                var minH = Math.min.apply(null, everyH); //获得最小的列的高度
                var minIndex = getIndex(minH, everyH); //获得最小列的索引
                getStyle(boxs[i], minH, boxs[minIndex].offsetLeft, i);
                everyH[minIndex] += boxs[i].offsetHeight; //更新最小列的高度
            }
        }
    }
    /**
     * 获取类元素
     * @param  warp     [Obj] 外层
     * @param  className    [Str] 类名
     */
    function getClass(wrap, className) {
        var obj = wrap.getElementsByTagName('*');
        var arr = [];
        for (var i = 0; i < obj.length; i++) {
            if (obj[i].className == className) {
                arr.push(obj[i]);
            }
        }
        return arr;
    }
    /**
     * 获取最小列的索引
     * @param  minH  [Num] 最小高度
     * @param  everyH [Arr] 所有列高度的数组
     */
    function getIndex(minH, everyH) {
        for (index in everyH) {
            if (everyH[index] == minH)
                return index;
        }
    }
    /**
     * 数据请求检验
     */
    function getCheck() {
        var documentH = document.documentElement.clientHeight;
        var scrollH = document.documentElement.scrollTop || document.body.scrollTop;
        return documentH + scrollH >= getLastH() ? true : false;
    }
    /**
     * 获得最后一个box所在列的高度
     */
    function getLastH() {
        //var wrap = document.getElementById('wrap');
        //var boxs = getClass(wrap, 'box');
        //return boxs[boxs.length - 1].offsetTop + boxs[boxs.length - 1].offsetHeight;
        return document.documentElement.scrollHeight;
    }
    /**
     * 设置加载样式
     * @param  box  [obj] 设置的Box
     * @param  top  [Num] box的top值
     * @param  left     [Num] box的left值
     * @param  index [Num] box的第几个
     */
    var getStartNum = 0; //设置请求加载的条数的位置
    function getStyle(box, top, left, index) {
        if (getStartNum >= index)
            return;
        $(box).css({
            'position': 'absolute',
            'top': top,
            "left": left,
            "opacity": "0"
        });
        $(box).stop().animate({
            "opacity": "1"
        }, 999);
        getStartNum = index; //更新请求数据的条数位置
    }
  • OK,前端代码已经完成,下面我们来看看后端代码,如下:

先添加两个路由


    Route::get('/album','AlbumController@index');
    Route::post('/album/get_more','AlbumController@getMoreAlbum');

逻辑处理

    
    /**
     * 相册首页
     * @return [type] [description]
     */
    public function index(){
        //对结果进行缓存
        $data = Cache::remember(getCacheRememberKey(), config('blog.cache_time.extra'), function () {
            $album = Album::orderBy('updated_at','desc')->limit(30)->get();
            return [
                'title' => config('blog.title').'|相册壁纸',
                'meta_description' => config('blog.description'),
                'albums' => $album,
            ];
        });
        return view('blogs.album',$data);
    }

    /**
     * 获取更多的图片
     * @param  Request $request [description]
     * @return [type]           [description]
     */
    public function getMoreAlbum(Request $request){
        $page = (int)$request->get('album_page');
        if($page <= 1){
            return response()->json(['status'=>'error','message'=>'已经到底了,请不要再刷新了!','content'=>'']);
        }
        $star = ($page-2)*10+30;
        $album = Album::orderBy('updated_at','desc')->offset($star)->limit(10)->get();
        if($album->isEmpty()){
            return response()->json(['status'=>'error','message'=>'已经到底了,请不要再刷新了!','content'=>'']);
        }
        $new_album = [];
        foreach ($album as $v) {
            $new_album[] = [
                'data_original' => page_image_size($v->name,1500,'albums'),
                'src' => page_image_size($v->name,300,'albums'),
                'alt' => $v->name,
            ];
        }
        $data = [
            'status'=>'success',
            'message' => '图片刷新成功!',
            'content' => $new_album,
        ];
        return response()->json($data);
    }

最终效果如图,当鼠标向下滑动时,会自动从后端获取数据:

description

补充

    
    /**
     * 通用尺寸图地址处理
     * @param  [type] $img  [description]
     * @param  [type] $size [description]
     * @return [type]       [description]
     */
    function page_image_size($img, $size, $model)
    {
        $img         = is_array($img) && isset($img[0]) ? $img[0] : $img;
        $new_img_url = config('img_upload.base_size_path') . $model . '/' . $size . 'x' . $size . '/' . $img;

        return asset($new_img_url);
    }

    END