1. 程式人生 > >layer 彈框 cropper 裁剪上傳圖片,thinkphp 3 使用 CropAvatar.class.php

layer 彈框 cropper 裁剪上傳圖片,thinkphp 3 使用 CropAvatar.class.php

最近要做一個上傳裁剪圖片功能,但是網上收出來的東西,知識點都是對的。但是就是沒說清楚,也無法連續起來用。

經過自己整理出來的一套程式碼,親測可用!

不用多說,直接上菜。

PS:搜尋引擎收錄的還是很垃圾......

呼叫頁面,簡單程式碼(可複用)

<img src="{$info.cover}" id="crop_img" width="150">
<input id="crop_img_value" type="hidden" name="cover" value="{$info.cover}" />
<a href="javascript:void();" class="btn btn-default" id="layer_upload">上傳封面</a>
$("#layer_upload").on("click",function(){
    layer.open({
	type: 2,
	title: '上傳圖片',
	shadeClose: true,
	shade: 0.8,
	area: ['95%', '95%'],
	content: '/common/uploadimg'
    }); 
});

layer 彈框頁面  uploadimg.tpl

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>上傳圖片</title>
    <link href="__STATIC__/cropavatar/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="__STATIC__/cropavatar/css/cropper.min.css" rel="stylesheet"/>
    <link href="__STATIC__/cropavatar/css/main.css" rel="stylesheet"/>
</head>
<body>
<div class="" id="crop-avatar">
 <div id="avatar-modal" >
<form class="avatar-form" id="avatar-form" enctype="multipart/form-data" method="post">
    <div class="modal-header">
        <h4 style="text-align: center;" class="modal-title" id="avatar-modal-label">上傳圖片</h4>
    </div>
    <div class="modal-body">
        <div class="avatar-body">

            <!-- Upload image and data -->
            <div class="avatar-upload">
                <input class="options" id="options" name="options" type="hidden" value="cope"/>
                <input class="avatar-src" id="avatar_src" name="avatar_src" type="hidden" value=""/>
                <input class="avatar-data" id="avatar_data" name="avatar_data" type="hidden" value=""/>
                <label for="avatarInput" style="display:none;">圖片上傳</label>
                <input class="avatar-input" id="avatarInput" name="tmp_name" type="file"/>
            </div>

            <!-- Crop and preview -->
            <div class="row">
                <div class="col-md-9">
                    <div class="avatar-wrapper"></div>
                </div>
                <div class="col-md-3">
                    <div class="avatar-preview preview-lg"></div>
                    <div class="avatar-preview preview-md"></div>
                    <div class="avatar-preview preview-sm"></div>
                </div>
            </div>

            <div class="row avatar-btns">
                <div class="col-md-9">
                    <div class="btn-group">
                        <button class="btn btn-primary" data-method="rotate" data-option="-90" type="button" title="旋轉-90°">向左旋轉</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="-15" type="button">-15°</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="-30" type="button">-30°</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="-45" type="button">-45°</button>
                    </div>
                    <div class="btn-group">
                        <button class="btn btn-primary" data-method="rotate" data-option="90" type="button" title="旋轉90°">向右旋轉</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="15" type="button">15°</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="30" type="button">30°</button>
                        <button class="btn btn-primary" data-method="rotate" data-option="45" type="button">45°</button>
                    </div>
                    <div class="btn-group" style="display:none;">
                        <label class="btn btn-primary" for="crop_caijian">裁剪</label>
                        <input style="display:none;" id="crop_caijian" type="radio" name="options" value="cope" checked/>
                        <label class="btn btn-primary" for="crop_yuantu">原圖</label>
                        <input style="display:none;" id="crop_yuantu" type="radio" name="options" value="not_cut" />
                    </div>
                </div>
                <div class="col-md-3">
                    <button class="btn btn-primary btn-block avatar-save" type="button" onclick="sendPhoto()">確定上傳</button>
                </div>
            </div>
        </div>
    </div>
</form>
<img style="display:none;" id="viewpic" src="__STATIC__/cropavatar/images/picture.jpg" alt=""/>
</div>
</div>
        <script src="__STATIC__/cropavatar/js/jquery.min.js"></script>
        <script src="__STATIC__/cropavatar/js/bootstrap.min.js"></script>
        <script src="__STATIC__/cropavatar/js/cropper.min.js"></script>
        <script src="__STATIC__/tqkwap/layer/layer.js"></script>

<script type="text/javascript">
    (function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node / CommonJS
        factory(require('jquery'));
    } else {
        factory(jQuery);
    }
    })(function ($) {

    'use strict';

    var console = window.console || { log: function () {} };

    function CropAvatar($element) {
        this.$container = $element;

        this.$avatar = this.$container.find('#viewpic');
        this.$avatarModal = this.$container.find('#avatar-modal');
        //this.$loading = this.$container.find('.loading');

        this.$avatarForm = this.$avatarModal.find('.avatar-form');
        this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
        this.$avatarSrc = this.$avatarForm.find('.avatar-src');
        this.$avatarData = this.$avatarForm.find('.avatar-data');
        this.$avatarInput = this.$avatarForm.find('.avatar-input');
        this.$avatarSave = this.$avatarForm.find('.avatar-save');
        this.$avatarBtns = this.$avatarForm.find('.avatar-btns');

        this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
        this.$avatarPreview = this.$avatarModal.find('.avatar-preview');

        this.init();
        console.log(this);
    }

    CropAvatar.prototype = {
        constructor: CropAvatar,

            support: {
            fileList: !!$('<input type="file">').prop('files'),
            blobURLs: !!window.URL && URL.createObjectURL,
            formData: !!window.FormData
            },

            init: function () {
            this.support.datauri = this.support.fileList && this.support.blobURLs;

            if (!this.support.formData) {
                this.initIframe();
            }

            this.initTooltip();
            this.initModal();
            this.addListener();
        },

        addListener: function () {
            this.$avatarInput.on('change', $.proxy(this.change, this));
            this.$avatarForm.on('submit', $.proxy(this.submit, this));
            this.$avatarBtns.on('click', $.proxy(this.rotate, this));
        },

        initTooltip: function () {
        
        },

        initModal: function () {
        this.$avatarModal.modal({
            show: false
        });
        },

        initPreview: function () {
        var url = this.$avatar.attr('src');

        this.$avatarPreview.empty().html('<img src="' + url + '">');
        },

        initIframe: function () {
        var target = 'upload-iframe-' + (new Date()).getTime(),
            $iframe = $('<iframe>').attr({
                name: target,
                src: ''
            }),
            _this = this;

        // Ready ifrmae
        $iframe.one('load', function () {

            // respond response
            $iframe.on('load', function () {
            var data;

            try {
                data = $(this).contents().find('body').text();
            } catch (e) {
                console.log(e.message);
            }

            if (data) {
                try {
                data = $.parseJSON(data);
                } catch (e) {
                console.log(e.message);
                }

                _this.submitDone(data);
            } else {
                _this.submitFail('Image upload failed!');
            }

            _this.submitEnd();

            });
        });

        this.$iframe = $iframe;
        this.$avatarForm.attr('target', target).after($iframe.hide());
        },

        click: function () {
        this.$avatarModal.modal('show');
        this.initPreview();
        },

        change: function () {
        var files,
            file;

        if (this.support.datauri) {
            files = this.$avatarInput.prop('files');

            if (files.length > 0) {
            file = files[0];

            if (this.isImageFile(file)) {
                if (this.url) {
                URL.revokeObjectURL(this.url); // Revoke the old one
                }

                this.url = URL.createObjectURL(file);
                this.startCropper();
            }
            }
        } else {
            file = this.$avatarInput.val();

            if (this.isImageFile(file)) {
            this.syncUpload();
            }
        }
        },

        submit: function () {
        if (!this.$avatarSrc.val() && !this.$avatarInput.val()) {
            return false;
        }

        if (this.support.formData) {
            this.ajaxUpload();
            return false;
        }
        },

        rotate: function (e) {
        var data;

        if (this.active) {
            data = $(e.target).data();

            if (data.method) {
            this.$img.cropper(data.method, data.option);
            }
        }
        },

        isImageFile: function (file) {
        if (file.type) {
            return /^image\/\w+$/.test(file.type);
        } else {
            return /\.(jpg|jpeg|png|gif)$/.test(file);
        }
        },

        startCropper: function () {
        var _this = this;

        if (this.active) {
            this.$img.cropper('replace', this.url);
        } else {
            this.$img = $('<img src="' + this.url + '">');
            this.$avatarWrapper.empty().html(this.$img);
            this.$img.cropper({
                aspectRatio: NaN,
                preview: this.$avatarPreview.selector,
                strict: false,
                viewMode: 2,
                crop: function (data) {
                    var json = [
                        '{"x":' + data.x,
                        '"y":' + data.y,
                        '"height":' + data.height,
                        '"width":' + data.width,
                        '"rotate":' + data.rotate + '}'
                        ].join();

                    _this.$avatarData.val(json);
                }
            });

            this.active = true;
        }
        },

        stopCropper: function () {
        if (this.active) {
            this.$img.cropper('destroy');
            this.$img.remove();
            this.active = false;
        }
        },

        ajaxUpload: function () {
        var url = this.$avatarForm.attr('action'),
            data = new FormData(this.$avatarForm[0]),
            _this = this;

        $.ajax(url, {
            type: 'post',
            data: data,
            dataType: 'json',
            processData: false,
            contentType: false,

            beforeSend: function () {
            _this.submitStart();
            },

            success: function (data) {
            _this.submitDone(data);
            },

            error: function (XMLHttpRequest, textStatus, errorThrown) {
            _this.submitFail(textStatus || errorThrown);
            },

            complete: function () {
            _this.submitEnd();
            }
        });
        },

        syncUpload: function () {
        this.$avatarSave.click();
        },

        submitStart: function () {
        //this.$loading.fadeIn();
        },

        submitDone: function (data) {
        console.log(data);

        if ($.isPlainObject(data) && data.state === 200) {
            if (data.result) {
            this.url = data.result;

            if (this.support.datauri || this.uploaded) {
                this.uploaded = false;
                this.cropDone();
            } else {
                this.uploaded = true;
                this.$avatarSrc.val(this.url);
                this.startCropper();
            }

            this.$avatarInput.val('');
            } else if (data.message) {
            this.alert(data.message);
            }
        } else {
            this.alert('Failed to response');
        }
        },

        submitFail: function (msg) {
        this.alert(msg);
        },

        submitEnd: function () {
        //this.$loading.fadeOut();
        },

        cropDone: function () {
        this.$avatarForm.get(0).reset();
        this.$avatar.attr('src', this.url);
        this.stopCropper();
        this.$avatarModal.modal('hide');
        },

        alert: function (msg) {
        var $alert = [
                '<div class="alert alert-danger avater-alert">',
                '<button type="button" class="close" data-dismiss="alert">×</button>',
                msg,
                '</div>'
            ].join('');

        this.$avatarUpload.after($alert);
        }
    };

    $(function () {
        return new CropAvatar($('#crop-avatar'));
    });


    });


var sendPhoto = function () {
    var data=$("#avatar_data").val();
    var file=$("#avatarInput").val();
    if(data=="" || file==""){
        layer.msg('請選擇圖片,再提交!', {
            time: 5000, 
            btn: ['確定']
        });
        return false;
    }
    var formData = new FormData($('#avatar-form')[0]);

    $.ajax({
        url: '{:u('common/cropPicture')}', // 要上傳的地址
        type: 'post',
        data: formData,
        dataType: 'json',
        cache: false,
        processData: false,
        contentType: false
    }).success(function (data) {
        if(data.state=="200" && data.result!=null){
            $("#viewpic").attr("src",data.result);

            window.parent.$("#crop_img").attr("src",data.result);  //回寫父級頁面
            window.parent.$("#crop_img_value").attr("value",data.result);
            var index = parent.layer.getFrameIndex(window.name);  
            parent.layer.close(index);
        }
    }).error(function(){
        layer.msg("網路錯誤,稍後重試!");
    });
}
</script>
</body>
</html>

layer 彈出框 Action  :commonAction.class.php

public function uploadimg(){
        $this->display();
    }
    //裁剪圖片
    public function cropPicture()
    {
        if (IS_POST) {
             import('@.ORG.CropAvatar');                
            if ($_FILES['tmp_name']['error'] !== 0) {
                $response = array('state' => 200,'message' => '檔案過大或格式不對');
            } else {
                $options = isset($_POST['options']) ? $_POST['options'] : 'cope';
                if ($options == 'cope') {
                    $crop = new CropAvatar(
                        isset($_POST['avatar_src']) ? $_POST['avatar_src'] : null,
                        isset($_POST['avatar_data']) ? $_POST['avatar_data'] : null,
                        isset($_FILES['tmp_name']) ? $_FILES['tmp_name'] : null,
                        '/data/upload/crop/'. date('Ymd') . '/'.'caijian/',
                        '/data/upload/crop/'. date('Ymd') . '/'.'yuantu/'
                    );
                    $response = array(
                        'state'  => 200,
                        'message' => $crop -> getMsg(),
                        'result' => $crop -> getResult()
                    );
                } elseif ($options == 'not_cut') {

                    if($_FILES['tmp_name']){
                        $file = $this->_upload($_FILES['tmp_name'], 'crop/picture/');
                       
                        if ($file['error']) {
                            $msg=$file['info'];
                        } else {
                            $file['info'][0]['savename'] = str_replace('.','.',$file['info'][0]['savename']);
                            $data['tmp_name'] = "/" . C("yh_attach_path") . 'crop/picture/' . $file['info'][0]['savename'];  
                        }
                        
                        $response = array(
                            'state'  => 200,
                            'message' => $msg,
                            'result' => $data['tmp_name']
                        );
                    }

                }
            }
            echo json_encode($response);
        } else {
            return json_encode('No data found!');
        } 
    }


如果你看到此處之後,還不能成功,說明你的裁剪類,不一致! 

CropAvatar.class.php

這個類我也除錯了好久,一直提示上傳成功,但是目錄始終沒有儲存到圖片!

原因:在類中儲存圖片沒有使用磁碟全路徑。我是這個問題,如果你不是請繞道!

執行截圖

此功能的全部程式碼,在此下載;不過你也可以直接敲。
點選下載  https://download.csdn.net/download/ybb350680013/10522658