mui開發app之cropper裁剪后上傳頭像的實現


應廣大讀者建議,已經將該項目源碼提交到地址: 
https://github.com/devilyouwei/dashen

 

在大多數app項目中,都需要對用戶頭像的上傳,之前做web開發的時候,我主要是通過input type=file的標簽實現的,上傳后,使用php對圖片進行裁剪,這種方式比較傳統簡單。

此次app開發中需要做到用戶選擇本地相冊或者進行拍照->對照片進行裁剪->最后同時更新本地頭像和服務器端的圖片。(app常見套路)

我將要結合:mui,cropper,jquery開發!

 

實現思路:

1.用戶點擊頭像,打開actionsheet

2.選擇圖片或者拍照后返回的圖片絕對地址傳入單獨的裁剪頁面,跳轉到裁剪頁面

3.裁剪頁面裁剪后選擇確認則將裁減后圖片保存到localstorage中(其實是把整個圖片保存到本地數據庫中)

4.觸發一個更新上一頁頭像的事件,返回上一頁

5.看到圖片已經更改

6.保存,圖片上傳到服務器(json)

7.服務器將圖片的base64保存到數據庫(text類型),實現數據庫保存圖片,當然可以使用后端語言的方法還原為圖片后保存在文件系統中(建議:小圖可保存在數據庫中,大圖保存在文件系統)

 

實現工具和插件,直接看代碼:

js

<script type="text/javascript" src="../js/jquery-1.11.2.min.js"></script>
<script src="../js/mui.min.js"></script>
<script type="text/javascript" src="../js/exif.js"></script>
<script src="../js/cropper.min.js"></script>
<script src="../js/fastclick.js"></script>

css

<link href="../css/mui.min.css" rel="stylesheet" />
<link href="../css/iconfont.css" rel="stylesheet" />
<link href="../css/cropper.css" rel="stylesheet" />

這里我們主要使用了一個cropper.js的插件,自行百度下載,目前比較好用的插件只有這個,大神的話自己寫一個吧

注意cropper必須使用jquery,而jquery比較臃腫,在其他mui中盡量不要引入,我也是迫不得已,使用jq並非我本意

fastclcik.js是加速點擊觸發,一般在手機端開發其實用不到,因為一般使用tap,這里我加了進去,似乎對裁剪圖片時手勢操作有幫助,(+_+)?,不加也沒有影響,測試過

iconfont是按鈕圖標

exif.js是可以檢測圖片拍攝時采用橫向還是縱向

這幾個請自行百度下載!

 

接下來可以開發了:

一共兩個頁面,

headinfo.html——編輯頁面

cropper.html——裁剪頁面

 

headinfo.html

<!doctype html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>我的資料</title>
        <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
        <link href="../css/mui.min.css" rel="stylesheet" />
        <link href="../css/style.css" rel="stylesheet" />
        <style type="text/css">
            .head {
                height: 40px;
            }
            
            #head {
                line-height: 40px;
            }
            
            .head-img {
                width: 40px;
                height: 40px;
            }
            
            #head-img1 {
                position: absolute;
                bottom: 10px;
                right: 40px;
                width: 40px;
                height: 40px;
            }
            
            .mui-fullscreen {
                position: fixed;
                z-index: 20;
                background-color: #000;
            }
            
            .mui-content {
                position: absolute;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
            }
        </style>
    </head>

    <body>
        <header class="mui-bar mui-bar-nav">
            <button type="button" id="finish" class="mui-left mui-btn mui-btn-link mui-btn-nav mui-pull-left">
                    <span class="mui-icon mui-icon-left-nav"></span>完成
            </button>
            <h1 class="mui-title">頭信息</h1>
        </header>
        <div class="mui-content">

            <ul class="mui-table-view">
                <li class="mui-table-view-cell">
                    <a id="head" class="mui-navigate-right">個人頭像
                        <span class="mui-pull-right head">
                            <img class="head-img mui-action-preview" id="head-img1" src=""/>
                        </span>
                    </a>
                </li>
            </ul>

            <div class="mui-input-row mui-margin-vertical">
                <h5 class="mui-margin-horizontal-xs">個人簽名:</h5>
                <input class="mui-padding-lg" id="signature" type="text" placeholder="個人簽名" />
            </div>
        </div>

        <script src="../js/mui.min.js"></script>
        <script src="../js/app.js"></script>
        <script type="text/javascript">
            (function($) {
                mui.init({
                    swipeBack: true
                });

                $.plusReady(function() {
                    //初始化頭像,和預覽圖
                    setTimeout(function() {
                        defaultInfo();
                        setTimeout(function() {
                            initImgPreview();
                        }, 200);
                    }, 0);

                    //彈出菜單
                    mui(".mui-table-view-cell").on("tap", "#head", function(e) {
                        if(mui.os.plus) {
                            var a = [{
                                title: "拍照"
                            }, {
                                title: "從手機相冊選擇"
                            }];
                            plus.nativeUI.actionSheet({
                                title: "修改頭像",
                                cancel: "取消",
                                buttons: a
                            }, function(b) {
                                switch(b.index) {
                                    case 0:
                                        break;
                                    case 1:
                                        getImage();
                                        break;
                                    case 2:
                                        galleryImg();
                                        break;
                                    default:
                                        break
                                }
                            })
                        }

                    });

                    //完成並返回
                    document.getElementById("finish").addEventListener("tap", function() {
                        var newSign = document.getElementById("signature").value;
                        var oldSign = app.getUserInfo().signature;
                        if(oldSign === newSign)
                            $.back();
                        else {
                            app.request("User", "updateSignature", {
                                'signature': newSign
                            }, function(res) {
                                if(res.login == 0) {
                                    mui.toast(res.info);
                                    app.clearToken();
                                    app.toLogin();
                                    return false;
                                }
                                if(res.status == 1) {
                                    app.setSignature(newSign);
                                    mui.toast(res.info);
                                    var view = plus.webview.getWebviewById("index");
                                    $.fire(view, "updateHeadInfo");
                                    $.back();
                                } else {
                                    mui.toast(res.info);
                                }
                            });
                        }

                    });

                });

                //拍照
                function getImage() {
                    var c = plus.camera.getCamera();
                    c.captureImage(function(e) {
                        //存儲到本地
                        plus.io.resolveLocalFileSystemURL(e, function(entry) {
                            cutImage(entry.toLocalURL());
                        }, function(e) {
                            console.log("讀取拍照文件錯誤:" + e.message);
                        });
                    }, function(s) {
                        console.log("error" + s);
                    }, {
                        filename: "_doc/head.jpg"
                    })
                }

                //相冊
                function galleryImg() {
                    plus.gallery.pick(function(a) {
                        plus.io.resolveLocalFileSystemURL(a, function(entry) { //entry為圖片原目錄(相冊)的句柄
                            cutImage(entry.toLocalURL());
                        }, function(e) {
                            console.log("讀取圖片錯誤:" + e.message);
                        });
                    }, function(a) {}, {
                        filter: "image"
                    })
                };

                //設置默認頭像
                function defaultInfo() {
                    var my_icon = app.getHeadImg(); //頭像
                    var signature = app.getUserInfo().signature; //簽名
                    if(my_icon && my_icon != "") {
                        document.getElementById("head-img1").src = my_icon;
                    } else {
                        document.getElementById("head-img1").src = '../images/my_icon.jpg';
                    }
                    if(signature && signature != "") {
                        document.getElementById("signature").value = signature;
                    } else {
                        document.getElementById("signature").value = "";
                    }
                }

                //預覽圖像
                document.getElementById("head-img1").addEventListener('tap', function(e) {
                    e.stopPropagation(); //阻止冒泡
                });

                function initImgPreview() {
                    var imgs = document.querySelectorAll("img.mui-action-preview");
                    imgs = mui.slice.call(imgs);
                    if(imgs && imgs.length > 0) {
                        var slider = document.createElement("div");
                        slider.setAttribute("id", "__mui-imageview__");
                        slider.classList.add("mui-slider");
                        slider.classList.add("mui-fullscreen");
                        slider.style.display = "none";
                        slider.addEventListener("tap", function() {
                            slider.style.display = "none";
                        });
                        slider.addEventListener("touchmove", function(event) {
                            event.preventDefault();
                        })
                        var slider_group = document.createElement("div");
                        slider_group.setAttribute("id", "__mui-imageview__group");
                        slider_group.classList.add("mui-slider-group");
                        imgs.forEach(function(value, index, array) {
                            //給圖片添加點擊事件,觸發預覽顯示;
                            value.addEventListener('tap', function() {
                                slider.style.display = "block";
                                _slider.refresh();
                                _slider.gotoItem(index, 0);
                            })
                            var item = document.createElement("div");
                            item.classList.add("mui-slider-item");
                            var a = document.createElement("a");
                            var img = document.createElement("img");
                            img.setAttribute("src", value.src);
                            a.appendChild(img)
                            item.appendChild(a);
                            slider_group.appendChild(item);
                        });
                        slider.appendChild(slider_group);
                        document.body.appendChild(slider);
                        var _slider = mui(slider).slider();
                    }
                }

                //裁剪圖片
                function cutImage(path) {
                    $.openWindow({
                        url: 'cropper.html',
                        id: 'cropper',
                        extras: {
                            path: path,
                        },
                        show: {
                            aniShow: 'zoom-fade-in',
                            duration: 800
                        },
                        waiting: {
                            autoShow: true
                        }
                    });
                }

                //更新用戶頭像
                function update_head_img(e) {
                    var my_icon = e.detail.img;
                    //先上傳
                    app.request("User", "saveHeadImg", {
                        'my_icon': my_icon
                    }, function(res) {
                        if(res.login == 0) {
                            mui.toast(res.info);
                            app.clearToken();
                            app.toLogin();
                            return false;
                        }

                        if(res.status == 1) {
                            app.setHeadImg(my_icon); //確認上傳成功后存儲到本地
                            if(my_icon == "")
                                my_icon = "../images/my_icon.jpg";
                            document.getElementById("head-img1").src = my_icon; //刷新小圖
                            document.querySelector("#__mui-imageview__group .mui-slider-item img").src = my_icon; //刷新預覽圖
                            //順帶觸發上一個頁面的updateHeadInfo
                            var view = plus.webview.getWebviewById("index");
                            $.fire(view, "updateHeadInfo");
                            mui.toast(res.info);
                        } else {
                            mui.toast(res.info);
                        }

                    });

                }
                window.addEventListener("updateHeadImg", update_head_img); //添加自定義事件,其他頁面調用
            })(mui);
        </script>
    </body>

</html>
View Code

 

cropper.html

 

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <title>裁剪頭像</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <link href="../css/mui.min.css" rel="stylesheet" />
        <link href="../css/cropper.css" rel="stylesheet" />
        <style type="text/css">
            body {
                background-color: #000000;
            }
            
            #cropper-example-1 {
                background-color: #000000;
                height: 93%;
                width: 100%;
                position: absolute;
            }
            
            .divbut {
                width: 100%;
                text-align: center;
                position: fixed;
                z-index: 2;
                bottom: 0px;
                background-color: #000000;
                height: 7.5%;
                line-height: 50px;
            }
            
            .divbut>div:first-child {
                float: left;
                width: 20%;
            }
            
            .divbut>div:last-child {
                float: right;
                width: 20%;
            }
            
            img#im {
                height: 100%;
                width: 100%;
            }
        </style>
    </head>

    <body>
        <div id="cropper-example-1" class="mui-hidden">
            <img id="im" alt="Picture" />
        </div>

        <div class="divbut">
            <div>
                <p id="quxiao" class="mui-icon mui-icon-closeempty"></p>
            </div>
            <div>
                <p id="xuanqu" class="mui-icon mui-icon-checkmarkempty"></p>
            </div>
        </div>
        <img src="" alt="" class="mui-hidden" id="im_exif" />

        <script type="text/javascript" src="../js/jquery-1.11.2.min.js"></script>
        <script src="../js/mui.min.js"></script>
        <script type="text/javascript" src="../js/exif.js"></script>
        <script src="../js/cropper.min.js"></script>
        <script src="../js/fastclick.js"></script>
        <script src="../js/app.js"></script>

        <script>
            $(function() {
                //盡量用一下fastclick
                FastClick.attach(document.body);
                ! function() {
                    var i = {
                        aspectRatio: 1 / 1
                    };
                }()
            });

            (function(c) {
                var Cro = function() {}
                c.extend(Cro.prototype, {
                    orientation: null,
                    urldata: null,
                    view: null,
                    num: 0,
                    sbx: null,
                    sby: null,
                    n: 0,
                    onReady: function() {
                        var that = this;
                        mui.init();
                        that.bindEvent();
                        that.view = plus.webview.currentWebview();

                        var img = document.getElementById("im_exif");
                        img.src = that.view.path;
                        img.addEventListener("load", function() {
                            //exif調整圖片的橫豎
                            EXIF.getData(this, function() {
                                var orientation = EXIF.getAllTags(this).Orientation;
                                $("#im").attr("src", that.loadcopyImg(img, orientation));
                                document.getElementById("cropper-example-1").classList.remove("mui-hidden"); //顯示裁剪區域
                                that.cropperImg();
                            });
                        })
                    },
                    cropperImg: function() {
                        var that = this;
                        $('#cropper-example-1 > img').cropper({
                            aspectRatio: 1 / 1,
                            autoCropArea: 1,
                            strict: true,
                            background: false,
                            guides: false,
                            highlight: false,
                            dragCrop: false,
                            movable: false,
                            resizable: false,
                            crop: function(data) {
                                that.urldata = that.base64(data);
                            }
                        });
                    },
                    loadcopyImg: function(img, opt) {
                        var that = this;
                        var canvas = document.createElement("canvas");
                        var square = 500;
                        var imageWidth, imageHeight;
                        if(img.width > img.height) {
                            imageHeight = square;
                            imageWidth = Math.round(square * img.width / img.height);
                        } else {
                            imageHeight = square; //this.width;
                            imageWidth = Math.round(square * img.width / img.height);
                        }
                        canvas.height = imageHeight;
                        canvas.width = imageWidth;
                        if(opt == 6) {
                            that.num = 90;
                        } else if(opt == 3) {
                            that.num = 180;
                        } else if(opt == 8) {
                            that.num = 270;
                        }
                        if(that.num == 360) {
                            that.num = 0;
                        }

                        var ctx = canvas.getContext("2d");
                        ctx.translate(imageWidth / 2, imageHeight / 2);
                        ctx.rotate(that.num * Math.PI / 180);
                        ctx.translate(-imageWidth / 2, -imageHeight / 2);
                        ctx.drawImage(img, 0, 0, imageWidth, imageHeight);
                        var dataURL = canvas.toDataURL("image/jpeg", 1);
                        return dataURL;
                    },
                    bindEvent: function() {
                        var that = this;
                        document.getElementById("quxiao").addEventListener("tap", function() {
                            mui.back(); //取消就直接返回
                        });
                        document.getElementById("xuanqu").addEventListener("tap", function() {
                            //觸發上一個頁面刷新圖片事件
                            var preView = plus.webview.getWebviewById('user/headinfo');
                            mui.fire(preView, 'updateHeadImg', {
                                'img': that.urldata
                            }); //不能保存圖片,需要判斷上傳性,所以選擇傳值的方式,傳遞圖片,格式為json
                            mui.back();
                        });
                    },
                    base64: function(data) {
                        var that = this;
                        var img = document.getElementById("im");

                        var canvas = document.createElement("canvas");
                        //像素
                        canvas.height = 400;
                        canvas.width = 400;
                        var bx = data.x;
                        var by = data.y;
                        var ctx = canvas.getContext("2d");
                        ctx.drawImage(img, bx, by, data.width, data.height, 0, 0, 400, 400);
                        var dataURL = canvas.toDataURL("image/jpeg", 0.5); //第二個參數是質量
                        return dataURL;
                    }
                });

                var cro = new Cro();

                c.plusReady(function() {
                    cro.onReady();
                })
            })(mui)
        </script>
    </body>

</html>
View Code

 

一開始對於headinfo.html我是打算先將拍照和相冊獲取的圖片使用plus的io保存到項目app的_doc目錄下再編輯裁剪,但是發現可以精簡,直接把圖片的絕對地址傳到cropper中,直接編輯后保存為base64,放在localstorage中,以后需要頭像的地方直接從localstorage中獲取即可!我在app.js(這是我寫的項目的公共js類庫,處處引用)

/* 
 *這只是其中一部分,在裁剪過程中需要用到的庫函數 
 *主要是方便,隨時可以獲取保存在localstorage中的頭像base64圖
*/

(function($, owner) {
    
     // 獲取用戶個人信息
    owner.getUserInfo = function() {
        var userText = localStorage.getItem('$user') || "{}";
        return JSON.parse(userText);
    }

     // 存儲用戶個人信息
    owner.setUserInfo = function(user) {
        user = user || {};
        localStorage.setItem('$user', JSON.stringify(user));
    }

    // 獲取用戶頭像
    owner.getHeadImg = function() {
        var headImg = owner.getUserInfo().my_icon || "";
        return headImg;
    }

    //設置用戶頭像
    owner.setHeadImg = function(baseData) {
        var userInfo = owner.getUserInfo();
        userInfo.my_icon = baseData; //只對my_icon這一項進行修改,其他不動
        owner.setUserInfo(userInfo);
    }
    

}(mui, window.app = {}));

 

base64的圖片格式是html5 canvas所使用的圖片格式,可以直接放入img的src中!

注:如果想使用js直接在手機端將base64轉換為圖片文件請看:mui開發app之js將base64轉圖片文件

效果圖:

               

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM