【jQuery插件】使用cropper實現簡單的頭像裁剪並上傳

来源:http://www.cnblogs.com/baka-sky/archive/2017/12/08/8001577.html
-Advertisement-
Play Games

插件介紹 這是一個我在寫以前的項目的途中發現的一個國人寫的jQuery圖像裁剪插件,當時想實現用戶資料的頭像上傳功能,並且能夠預覽圖片,和對圖片進行簡單的裁剪、旋轉,花了不少時間才看到了這個插件,感覺功能挺全面,代碼實現起來也挺簡單,再加上用的是Bootstrap,對移動端操作也有適配,於是就用了。 ...


插件介紹

這是一個我在寫以前的項目的途中發現的一個國人寫的jQuery圖像裁剪插件,當時想實現用戶資料的頭像上傳功能,並且能夠預覽圖片,和對圖片進行簡單的裁剪、旋轉,花了不少時間才看到了這個插件,感覺功能挺全面,代碼實現起來也挺簡單,再加上用的是Bootstrap,對移動端操作也有適配,於是就用了。現在稍微有點時間就記錄一下,方便以後再用的時候查閱。另外也有對應的js版本。

官方文檔(英文)

相容性

相容所有支持了Canvas的瀏覽器(IE9+),一小部分功能例外,具體請查看官方文檔。

參數

viewMode

  • Type: Number
  • Default: 0
  • Options: 0,1,2,3

這個具體每個值對應的效果我也不是很清楚,推薦在上面的官方示例里都試一試,我都是比較喜歡2。

dragMode

  • Type: String
  • Default: 'crop'
  • Options:
    • 'crop': 在裁剪框外拖動滑鼠會生成一個新的裁剪框。
    • 'move': 在裁剪框外拖動滑鼠會移動原圖。
    • 'none': 在裁剪框外拖動滑鼠則什麼也不做。

aspectRatio

  • Type: Number
  • Default: NaN

這個是裁剪框的縱橫比,預設是不限制的。例如1:1的頭像就寫1,16:9可寫成16 / 9

data

  • Type: Object
  • Default: null

The previous cropped data if you had stored, will be passed to setData method automatically.

(沒怎麼用過,都是直接用setData方法)

preview

  • Type: String (jQuery selector)
  • Default: ''

預覽圖的位置,用jQuery選擇器表示。

responsive

  • Type: Boolean
  • Default: true

在更改視窗大小後是否重新渲染cropper。

restore

  • Type: Boolean
  • Default: true

在更改視窗大小後是否恢復裁剪區域。

checkCrossOrigin

  • Type: Boolean
  • Default: true

檢查圖像是否是跨域圖像。(具體查看官方文檔)

checkOrientation

  • Type: Boolean
  • Default: true

(具體查看官方文檔)

  • Type: Boolean
  • Default: true

非裁剪區域是否用黑罩遮蓋。

guides

  • Type: Boolean
  • Default: true

裁剪區域是否顯示虛線。

center

  • Type: Boolean
  • Default: true

裁剪區域正中央是否顯示+號。

highlight

  • Type: Boolean
  • Default: true

裁剪區域是否高亮顯示。

background

  • Type: Boolean
  • Default: true

是否顯示背景的黑白方格(類似PS里透明圖層的顯示方式)。

autoCrop

  • Type: Boolean
  • Default: true

cropper初始化完成後是否自動顯示裁剪框

autoCropArea

  • Type: Number
  • Default: 0.8 (80% of the image)

自動顯示的裁剪框的大小。因此,數字應當在0~1之間。

movable

  • Type: Boolean
  • Default: true

是否允許移動原圖。(如果這裡填false那麼儘管dragMode的值是move,在裁剪框外拖動也不會移動原圖)

rotatable

  • Type: Boolean
  • Default: true

是否可以旋轉原圖。

scalable

  • Type: Boolean
  • Default: true

是否可以對原圖進行縱橫拉伸。

例如把原圖寬度拉長為原來的2倍或者拉長為原來的-1倍(即水平翻轉)。

zoomable

  • Type: Boolean
  • Default: true

是否可以對原圖進行縮小放大。

zoomOnTouch

  • Type: Boolean
  • Default: true

是否允許在移動端上使用雙指觸摸縮放原圖。

zoomOnWheel

  • Type: Boolean
  • Default: true

是否允許使用滑鼠滾輪縮放原圖。

wheelZoomRatio

  • Type: Number
  • Default: 0.1

當使用滑鼠滾輪縮放時的比例。

cropBoxMovable

  • Type: Boolean
  • Default: true

是否允許移動裁剪框。

cropBoxResizable

  • Type: Boolean
  • Default: true

是否允許通過拖動裁剪框的邊框來調整裁剪框的大小。

toggleDragModeOnDblclick

  • Type: Boolean
  • Default: true

是否允許通過雙擊來在cropmove之間切換dragMode

minContainerWidth

  • Type: Number
  • Default: 200

容器寬度最小值。

minContainerHeight

  • Type: Number
  • Default: 100

容器高度最小值。

minCanvasWidth

  • Type: Number
  • Default: 0

canvas(原圖)寬度最小值。

minCanvasHeight

  • Type: Number
  • Default: 0

canvas(原圖)高度最小值。

minCropBoxWidth

  • Type: Number
  • Default: 0

剪切框寬度最小值。

Note: This size is relative to the page, not the image.

minCropBoxHeight

  • Type: Number
  • Default: 0

剪切框高度最小值。

Note: This size is relative to the page, not the image.

ready

  • Type: Function
  • Default: null

A shortcut of the "ready" event.

cropstart

  • Type: Function
  • Default: null

A shortcut of the "cropstart" event.

cropmove

  • Type: Function
  • Default: null

A shortcut of the "cropmove" event.

cropend

  • Type: Function
  • Default: null

A shortcut of the "cropend" event.

crop

  • Type: Function
  • Default: null

A shortcut of the "crop" event.

zoom

  • Type: Function
  • Default: null

A shortcut of the "zoom" event.

常用方法

除了"setAspectRatio","replace"和"destroy"以外,所有的方法都要在ready後才能使用。這裡只介紹幾個常用的方法,全部的方法請到官方文檔查閱。

方法的使用格式為

$().cropper('method',arg0,arg1,arg2,...);

crop()

手動顯示裁剪框。

$().cropper({
  autoCrop: false,
  ready: function () {
    // Do something here
    // ...

    // And then
    $(this).cropper('crop');
  }
});

reset()

恢復全部到初始狀態。

replace(url[, onlyColorChanged])

  • url:
  • Type: String
  • A new image url.

  • onlyColorChanged (optional):
  • Type: Boolean
  • If only change the color, not the size, then the cropper only need to change the srcs of all related images, not need to rebuild the cropper. This can be used for applying filters.
  • If not present, its default value is false.

替換cropper中的圖像文件,通常第二個參數不管。

destroy()

銷毀cropper,並且會移除img標簽的src屬性的值。

getCroppedCanvas([options])

  • options (optional):
    • Type: Object
    • Properties:
      • width: the destination width of the output canvas.
      • height: the destination height of the output canvas.
      • minWidth: the minimum destination width of the output canvas, the default value is 0.
      • minHeight: the minimum destination height of the output canvas, the default value is 0.
      • maxWidth: the maximum destination width of the output canvas, the default value is Infinity.
      • maxHeight: the maximum destination height of the output canvas, the default value is Infinity.
      • fillColor: a color to fill any alpha values in the output canvas, the default value is transparent.
      • imageSmoothingEnabled: set to change if images are smoothed (true, default) or not (false).
      • imageSmoothingQuality: set the quality of image smoothing, one of "low" (default), "medium", or "high".
  • (return value):
    • Type: HTMLCanvasElement
    • A canvas drawn the cropped image.
  • Notes:
    • 輸出的canvas的縱橫比會自動適應於裁剪框的縱橫比.
    • 如果打算得到JPEG圖像,那麼應該先設置fillColor參數,否則裁剪後的透明部分預設會由黑色填充。
  • Browser support:

得到裁剪到的圖像的canvas,如果沒有裁剪,那麼就返回的是整個原圖圖像的canvas。

這是最重要的一個方法,通過這個方法就可以得到裁剪後的圖像,再使用toDataURL()得到base64 dataURL(不指定格式的話會是png格式)或者toBlob()得到Blob,然後就可以很輕鬆地將圖片上傳至伺服器上或者顯示在某個img標簽中了。例如:

// 轉換為png格式的dataURL
var dataURL = $().cropper('getCroppedCanvas', {
    width:100,
    height:100
}).toDataURL('image/png');

// 轉換為Blob後顯示在img標簽中
var URL = window.URL || window.webkitURL;
$().cropper('getCroppedCanvas', {
    width:100,
    height:100
}).toBlob(function (blob) {
    $().attr('src',URL.createObjectURL(blob));
});

簡單實例

在頁面直接使用cropper

接下來只是實現一個簡單的功能:網頁中可以上傳圖片,然後對圖片進行裁剪,點擊確定後會顯示出裁剪後的圖片。

代碼如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>裁剪圖片</title>
<link href="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style>
        .row{
            margin-bottom: 5px;
        }
        #photo {
            max-width: 100%;
        }
        .img-preview {
            width: 100px;
            height: 100px;
            overflow: hidden;
        }
        button {
            margin-top:10px;
        }
        #result {
            width: 150px;
            height: 150px;
        }
</style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-sm-12 text-center">
            <label for="input" class="btn btn-danger" id="">
            <span>選擇圖片</span>
            <input type="file" id="input" class="sr-only">
            </label>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-6 col-sm-offset-2">
            <img src="" id="photo">
        </div>
        <div class="col-sm-2">
            <div>
                <p>
                    預覽(100*100):
                </p>
                <div class="img-preview">
                </div>
            </div>
            <button class="btn btn-primary" onclick="crop()">裁剪圖片</button>
            <div>
                <br/>
                <p>
                    結果:
                </p>
                <img src="" alt="裁剪結果" id="result">
            </div>
        </div>
    </div>
</div>
<!-- Scripts -->
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script>
        // 修改自官方demo的js
        var initCropper = function (img, input){
            var $image = img;
            var options = {
                aspectRatio: 1, // 縱橫比
                viewMode: 2,
                preview: '.img-preview' // 預覽圖的class名
            };
            $image.cropper(options);
            var $inputImage = input;
            var uploadedImageURL;
            if (URL) {
                // 給input添加監聽
                $inputImage.change(function () {
                    var files = this.files;
                    var file;
                    if (!$image.data('cropper')) {
                        return;
                    }
                    if (files && files.length) {
                        file = files[0];
                        // 判斷是否是圖像文件
                        if (/^image\/\w+$/.test(file.type)) {
                            // 如果URL已存在就先釋放
                            if (uploadedImageURL) {
                                URL.revokeObjectURL(uploadedImageURL);
                            }
                            uploadedImageURL = URL.createObjectURL(file);
                            // 銷毀cropper後更改src屬性再重新創建cropper
                            $image.cropper('destroy').attr('src', uploadedImageURL).cropper(options);
                            $inputImage.val('');
                        } else {
                          window.alert('請選擇一個圖像文件!');
                      }
                  }
              });
            } else {
                $inputImage.prop('disabled', true).addClass('disabled');
            }
        }
        var crop = function(){
            var $image = $('#photo');
            var $target = $('#result');
            $image.cropper('getCroppedCanvas',{
                width:300, // 裁剪後的長寬
                height:300
            }).toBlob(function(blob){
                // 裁剪後將圖片放到指定標簽
                $target.attr('src', URL.createObjectURL(blob));
            });
        }
        $(function(){
            initCropper($('#photo'),$('#input'));
        });
    </script>
</body>
</html>

剪切圖片

在bootstrap模態框中使用cropper

雖然在模態框中可以像上面一樣使用cropper,甚至我以前寫的項目也是跟上面一樣,但是這次整理的時候突然發現了一個bug:當隱藏模態框後調整瀏覽器大小(甚至按f12),再打開模態框後cropper的容器會改變,導致難以使用。於是,我在GitHub中翻找了issue,在官方的example中找到了對應的解決方法。但其實這個解決方法也是一種暴力解法,即模態框隱藏後銷毀cropper,打開後重新創建cropper,可能會有別的方法,因為不確定會不會有別的bug,所以暫時還是用官方的方法比較好。

代碼如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>上傳頭像</title>
<link href="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<style type="text/css">
    body{
        text-align: center;
    }
    #user-photo {
        width:300px;
        height:300px;
        margin-top: 10px;
    }
    #photo {
        max-width:100%;
        max-height:350px;
    }
    .img-preview-box {
        text-align: center;
    }
    .img-preview-box > div {
        display: inline-block;;
        margin-right: 10px;
    }
    .img-preview {
        overflow: hidden;
    }
    .img-preview-box .img-preview-lg {
        width: 150px;
        height: 150px;
    }
    .img-preview-box .img-preview-md {
        width: 100px;
        height: 100px;
    }
    .img-preview-box .img-preview-sm {
        width: 50px;
        height: 50px;
        border-radius: 50%;
    }
</style>
</head>
<body>
<button class="btn btn-primary" data-target="#changeModal" data-toggle="modal">打開</button><br/>
<div class="user-photo-box">
    <img id="user-photo" src="">
</div>
</div>
<div class="modal fade" id="changeModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title text-primary">
            <i class="fa fa-pencil"></i>
                        更換頭像
            </h4>
        </div>
        <div class="modal-body">
            <p class="tip-info text-center">
                未選擇圖片
            </p>
            <div class="img-container hidden">
                <img src="" alt="" id="photo">
            </div>
            <div class="img-preview-box hidden">
                <hr>
                <span>150*150:</span>
                <div class="img-preview img-preview-lg">
                </div>
                <span>100*100:</span>
                <div class="img-preview img-preview-md">
                </div>
                <span>30*30:</span>
                <div class="img-preview img-preview-sm">
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <label class="btn btn-danger pull-left" for="photoInput">
            <input type="file" class="sr-only" id="photoInput" accept="image/*">
            <span>打開圖片</span>
            </label>
            <button class="btn btn-primary disabled" disabled="true" onclick="sendPhoto();">提交</button>
            <button class="btn btn-close" aria-hidden="true" data-dismiss="modal">取消</button>
        </div>
    </div>
</div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/cropper/3.1.3/cropper.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
        var initCropperInModal = function(img, input, modal){
            var $image = img;
            var $inputImage = input;
            var $modal = modal;
            var options = {
                aspectRatio: 1, // 縱橫比
                viewMode: 2,
                preview: '.img-preview' // 預覽圖的class名
            };
            // 模態框隱藏後需要保存的數據對象
            var saveData = {};
            var URL = window.URL || window.webkitURL;
            var blobURL;
            $modal.on('show.bs.modal',function () {
                // 如果打開模態框時沒有選擇文件就點擊“打開圖片”按鈕
                if(!$inputImage.val()){
                    $inputImage.click();
                }
            }).on('shown.bs.modal', function () {
                // 重新創建
                $image.cropper( $.extend(options, {
                    ready: function () {
                        // 當剪切界面就緒後,恢複數據
                        if(saveData.canvasData){
                            $image.cropper('setCanvasData', saveData.canvasData);
                            $image.cropper('setCropBoxData', saveData.cropBoxData);
                        }
                    }
                }));
            }).on('hidden.bs.modal', function () {
                // 保存相關數據
                saveData.cropBoxData = $image.cropper('getCropBoxData');
                saveData.canvasData = $image.cropper('getCanvasData');
                // 銷毀並將圖片保存在img標簽
                $image.cropper('destroy').attr('src',blobURL);
            });
            if (URL) {
                $inputImage.change(function() {
                    var files = this.files;
                    var file;
                    if (!$image.data('cropper')) {
                        return;
                    }
                    if (files && files.length) {
                        file = files[0];
                        if (/^image\/\w+$/.test(file.type)) {

                            if(blobURL) {
                                URL.revokeObjectURL(blobURL);
                            }
                            blobURL = URL.createObjectURL(file);

                            // 重置cropper,將圖像替換
                            $image.cropper('reset').cropper('replace', blobURL);

                            // 選擇文件後,顯示和隱藏相關內容
                            $('.img-container').removeClass('hidden');
                            $('.img-preview-box').removeClass('hidden');
                            $('#changeModal .disabled').removeAttr('disabled').removeClass('disabled');
                            $('#changeModal .tip-info').addClass('hidden');

                        } else {
                            window.alert('請選擇一個圖像文件!');
                        }
                    }
                });
            } else {
                $inputImage.prop('disabled', true).addClass('disabled');
            }
        }
    }

    var sendPhoto = function(){
        $('#photo').cropper('getCroppedCanvas',{
            width:300,
            height:300
        }).toBlob(function(blob){
            // 轉化為blob後更改src屬性,隱藏模態框
            $('#user-photo').attr('src',URL.createObjectURL(blob));
            $('#changeModal').modal('hide');
        });
    }

    $(function(){
        initCropperInModal($('#photo'),$('#photoInput'),$('#changeModal'));
    });
</script>
</body>
</html>

打開模態框

打開圖片

使用cropper來上傳圖片到伺服器

由於cropper可以得到兩種裁剪後圖片的數據(即blob和dataURL),所以對應的上傳到後臺也會有兩種方法,在這裡我只寫一種使用ajax上傳base64 dataURL的,另一種方法如果有興趣,可以自己嘗試。

頁面中,將上面的sendPhoto方法改為:

var sendPhoto = function () {
    // 得到PNG格式的dataURL
    var photo = $('#photo').cropper('getCroppedCanvas', {
        width: 300,
        height: 300
    }).toDataURL('image/png');

    $.ajax({
        url: '上傳地址', // 要上傳的地址
        type: 'post',
        data: {
            'imgData': photo
        },
        dataType: 'json',
        success: function (data) {
            if (data.status == 0) {
                // 將上傳的頭像的地址填入,為保證不載入緩存加個隨機數
                $('.user-photo').attr('src', '頭像地址?t=' + Math.random());
                $('#changeModal').modal('hide');
            } else {
                alert(data.info);
            }
        }
    });
}

後臺中,Java的主要代碼如下:(使用了jdk8的Base64,,如果是低版本請自行替換)

    /**
     * 將Base64位編碼的圖片進行解碼,並保存到指定目錄
     */
    public static void decodeBase64DataURLToImage(String dataURL, String path, String imgName) throws IOException {
        // 將dataURL開頭的非base64字元刪除
        String base64 = dataURL.substring(dataURL.indexOf(",") + 1);
        FileOutputStream write = new FileOutputStream(new File(path + imgName));
        byte[] decoderBytes = Base64.getDecoder().decode(base64);
        write.write(decoderBytes);
        write.close();
    }

小結

cropper能做到的事情還很多,這裡只是簡單使用了一下,更多功能可以在有想法的再研究下。

這是針對以前項目用的cropper的一個整理,結果因為當初沒有看官方例子,途中發現了在模態框中使用的一個bug,以後會註意這方面。另外,整理這部分資料時也參考了不少的網路資料,在這裡就不一一記錄了。

最後,由於本人能力有限,若發現錯誤希望能指出,本人會及時改正,非常感謝。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這幾天又遇到要調節列表分割線位置,就想起很久以前剛做時的做法:把自帶的分割線隱藏,然後自己加一條UIView,哈哈,不過這一兩年不那麼幹了,把這個方法貼出來; 在 Tableview 的代理方法中,實現下麵的代理方法: UIEdgeInsetsMake(上,左,下,右)自己可以調節,UIEdgeIn ...
  • Xcode9之前 設置狀態欄顏色首先在info.plist文件中,加入UIViewControllerBasedStatusBarAppearance = false; 讓後在delegate didFinishLaunchingWithOptions 方法中加入下麵的代碼就可以了; Xcode9之 ...
  • 最近寫了個下拉控制項,和幾個下拉的頭部樣式,下拉控制項可以連續添加疊加幾個頭部視圖 下麵是沒有添加任何頭部尾部的視圖下拉效果 一步一步來介紹,先介紹這個下拉效果,在介紹自定義的頭部 首先在使用上,和普通的控制項沒有兩樣,拿recyclerview來做例子,因為recyclerview使用比較多,而且可以替 ...
  • <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>fixed解決方案</title> <script src="../jsDemo/jquery-1.8.2.min.js?3393"></script> <styl ...
  • 小程式獲取用戶的頭像昵稱openid之類 第一種使用wx.getUserInfo直接獲取微信頭像,昵稱 ? 1 2 3 4 5 6 7 8 wx.getUserInfo({ success:function(res) { that.setData({ nickName: res.userInfo.n ...
  • 最近開始搞安卓,使用AS啟動項目時老是報各種錯誤,而網上這方面的資料很多都解決不了。只能邊實驗邊做。 定位到avd manager或sdk manager無法打開,網上找了很多資料,都不能解決,知道看見下麵一篇文章。 sdk manager打不開閃退問題完美解決2017年最新方法 當看到博主辛辛苦苦 ...
  • 近日,在開發過程中 遇到了 Layout 代碼中設置 Background 後,padding失效的問題,只是在Android 4.4.4 和 4.4.2 的手機上遇到了。 網上搜索了下,說是 4.4 系統里的一個bug,解決方法就是 在動態設置 Background 後,重新設置 padding。 ...
  • weex旨在“一次撰寫,多端使用”,意思是,用weex寫的頁面,不論是Android還是iOS甚至web端都可以使用,這樣的話就可以極大的降低開發成本, weex其實就是寫的一個類似於h5的頁面(js編寫),寫完之後將vue文件編譯、部署到Nginx伺服器上(Nginx伺服器後面會講到),這時候在... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...