angularJs自定义指令:图片选择指令

 老样子,先上效果图:

  这个是在浏览器中使用的效果:

 

  这个两个是在华为畅玩X7中测试的效果,由于录制的视频不知道为什么是横屏,导致导出来的gif图也是横屏,同学们就将就看看把:



  在使用混合式开发app的时候,有一些需要调用手机硬件的功能往往做起来比较繁琐,比如拍照上传图片的功能,而且这个是属于比较比较常见的需求,做到这样的功能时,同学们开发这个功能的过程可能是,在浏览器中写好调用插件的代码,然后打包编译安装测试,测试发现问题,好,修改代码重新打包编译安装测试,这个过程非常繁琐,有的业务需求必须要有图片的时候,那就更麻烦,即使这个调用摄像头插件的代码没问题,这个业务功能每次正式测试都得在真机上测试,一系列的问题导致,像拍照上传这一类的功能开发起来得特别小心,一点错误的代码,需要花费非常多的时间才能找到问题。

  

  基于上面描述的问题,我写了一个图片选择指令,在浏览器下开发的时候,调用的是浏览器文件选择的功能(就是触发input type=file元素的点击事件),当真机运行的时候,调用插件获取图片(cordova-plugin-camera),最后把得到的图片返回给开发者处理,我这个指令获取完图片数据之后是自动把图片加载到img节点中,就是一个预览的功能:

  这个获取的数据是双向绑定的,如果调用该指令的作用域中声明了img-src属性,图片选择指令会把图片数据自动绑定到这个声明的变量中。

  本次总结环境:angularJs、jquery、onsenui2

指令的html模板代码:

<label style="
    width: 64px;
    height: 64px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: solid 1px #ddd;
    border-radius: 6px;
    position: relative;
" ng-click="selectPicture()">
    <ons-list-item style="
    display: flex;
    padding: 0px;
    align-items: center;
    justify-content: center;
    height: calc(100% + 2px);
    position: relative;
    top: -1px;
" class="list-item-center" ripple>
        <ons-icon icon="ion-ios-cloud-upload" style="color: #469ce7;font-size: 24px" ng-if="!imgUrl"></ons-icon>
        <img style="width: 100%;height: 100%;" ng-src="{{imgUrl}}" ref="img" ng-show="imgUrl">
        <input type="file" style="position: absolute;left: 0;bottom: 0;top: 0;right: 0;width: 100%;height: 100%;opacity: 0" ref="fileInput" ng-show="!isDevice">
    </ons-list-item>
</label>
指令声明代码:

app.directive('imagePick', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'js/directives/image-pick/image-pick.template.html',
        scope: {
            imgSrc: '='
        },
        controller: [
            '$scope', '$element', '$attrs', '$transclude',
            function ($scope, $element, $attrs, $transclude) {
                /*$scope.imgSrc与父作用域绑定,因为初始化的时候可能没有,所以实际上img元素的src绑定需要一个临时变量imgUrl,如果传入的imgSrc不是未定义,则将imgSrc赋给imgUrlimgUrl改变时也将值赋给imgSrc,实现双向绑定*/
                $scope.imgUrl = '';
                $scope.imgSrc && ($scope.imgSrc != '') && ($scope.imgUrl = $scope.imgSrc);
                const refs = getRefs($element);

                /*--------------------------用于开发调试,模拟浏览器开发模式还是真机模式--------------------------------*/
                // navigator.camera = 'camera';
                /*------------------------------------------------------------------------------------------------*/

                /*判断当前是浏览器开发模式还是真机模式*/
                if (navigator.camera) {
                    console.log('camera is ready, use cordova camera plugin...');
                    $scope.isDevice = true;
                    /*因为在真机模式下发现input type=file节点元素死活不会消失,又不能用ng-if指令(ng-if会导致无法触发change事件,不知道为什么),只能用ng-show或者ng-hide,所以真机模式下,只能通过修改这个inputtype属性,摧毁这个元素节点*/
                    console.log(refs.fileInput);
                    $(refs.fileInput).attr('type','');
                } else {
                    console.log('browser file input is ready');
                    $scope.isDevice = false;
                }

                /*修改图片*/
                function changeImg(img) {
                    $scope.imgUrl = img;
                    if ($scope.imgSrc) $scope.imgSrc = $scope.imgUrl;
                    /*因为修改图片数据之后,无论是使用ng-src动态绑定还是使用img.src=***手动修改图片都不会立即生效,每次修改图片都是上一次选择的图片,第一次选择得到的是一个错误的咩有的图片,这里通过动态绑定,然后修改之后通过$apply()方法可以暂时修复这个问题*/
                    $scope.$apply();
                }

                /*如果template html中存在input type=file元素(当开发模式下,才会存在),设置change事件,图片预览*/
                if (refs.fileInput && !$scope.isDevice) {
                    $(refs.fileInput).change(function () {
                        console.log('img chang');
                        if (window.FileReader) {
                            var file = ($(refs.fileInput).prop('files'))[0];
                            if (!/image\/\w+/.test(file.type)) {
                                ons.notification.alert({cancelable: true, message: '请选择图片文件!', animation: 'none',});
                                return;
                            }
                            var fr = new FileReader();
                            fr.onloadend = function (e) {
                                changeImg(e.target.result);
                                fr = null;
                            };
                            fr.readAsDataURL(file);
                        } else {
                            ons.notification.alert({cancelable: true, message: '您的设备不支持文件预览!', animation: 'none',});
                        }
                        /*选择文件之后,把input的值置空,不然选择同一个文件是不会触发change事件的*/
                        $(refs.fileInput).val(null);
                    });
                }


                /*如果是真机模式下,调用手机摄像头或者打开相册,选择图片文件*/
                /*很奇怪的是,在android模式下,这个点击一次会触发两次,所以得用一个计数器,只能触发一次*/
                var count = 1;
                $scope.selectPicture = function () {
                    if (count>0){
                        count--;
                        if (!$scope.isDevice) {
                            console.log('current environment is not a device, refuse to use cordova camera plugin..');
                        } else {
                            console.log('select picture');
                            ons.openActionSheet({
                                cancelable: true,
                                buttons: [
                                    '摄像头拍照',
                                    '从相册中选择图片',
                                    '取消',
                                ]
                            }).then(function (index) {
                                count++;
                                switch (index) {
                                    case 0:
                                        CameraUtils.takeFromCamera(function (imgUri) {changeImg(imgUri)});
                                        break;
                                    case 1:
                                        CameraUtils.takeFromAlbum(function (imgUri) {changeImg(imgUri)});
                                        break;
                                    default:
                                        console.log('no action...');
                                        break;
                                }
                            })
                        }
                    }else {
                        console.log('count is empty, exist...');
                    }
                }
            }
        ]
    }
});
指令中使用的一些函数代码,这个包括插件调用的代码:

/*
*   在指令中,获取作用域范围内的所有用了ref属性标记的节点,如果ref值相同,通过  getRefs(element).别名   结果是一个数组,如果ref值只有一个,测获取的就是一个对象
*   element:在指令中,$element对象,也就是指令本身对象
*/
function getRefs(element) {
    var refs = ($(element).find("[ref]"));
    var result = {};
    for (var i = 0; i < refs.length; i++) {
        var item = $(refs[i]);
        var refName = item.attr('ref');
        if (!(refName in result)) result[refName] = [];
        result[refName].push(item[0]);
    }
    for (var key in result) {
        if (result[key].length == 1) result[key] = result[key][0];
    }
    return result;
}

/*
*   封装使用cordova-plugin-camera插件代码的工具类
*/
var CameraUtils = {
    takeFromCamera: function (success) {
        console.log('打开摄像头..........');
        var srcType = Camera.PictureSourceType.CAMERA;
        var options = CameraUtils.getDefaultOptions(srcType);
        navigator.camera.getPicture(
            function (imageUri) {
                success && success("data:image/jpeg;base64,"+imageUri);
            },
            function (error) {
                console.error("Unable to obtain picture: " + error, "app");
            }, options);
    },
    takeFromAlbum: function (success) {
        console.log('打开相册........');
        var srcType = Camera.PictureSourceType.SAVEDPHOTOALBUM;
        var options = CameraUtils.getDefaultOptions(srcType);
        navigator.camera.getPicture(
            function (imageUri) {
                success && success("data:image/jpeg;base64,"+imageUri);
            },
            function (error) {
                console.error("Unable to obtain picture: " + error, "app");
            }, options);
    },
    getDefaultOptions: function (srcType) {
        return {
            // Some common settings are 20, 50, and 100
            quality: 80,
            destinationType: Camera.DestinationType.DATA_URL,
            // In this app, dynamically set the picture source, Camera or photo gallery
            sourceType: srcType,
            encodingType: Camera.EncodingType.JPEG,
            mediaType: Camera.MediaType.PICTURE,
            allowEdit: true,
            correctOrientation: true  //Corrects Android orientation quirks
        };
    }
};
调用图片选择指令的页面代码:

<ons-page ng-controller="devController">
    <ons-toolbar>
        <div class="left">
            <ons-toolbar-button ng-click="LnkMenu()">
                <ons-icon icon="ion-navicon-round"></ons-icon>
            </ons-toolbar-button>
        </div>
        <div class="center">
            <span ng-bind="'门店拜访'"></span>
        </div>
    </ons-toolbar>
    <ons-page class="c-p">
        <image-pick></image-pick>
        <image-pick img-src="ir"></image-pick>
        {{ir}}
    </ons-page>
</ons-page>
页面controller:

app.controller('devController', function ($scope, $rootScope, pageService) {
    $scope.ir = 'img/1.png';
});

  我觉得代码注释得已经非常详细了,这里我就不再讲解其中的原理,我这里还涵盖了其他两个知识点,一个是使用angularJs给节点元素取别名,相关说明博客地址:http://blog.csdn.net/mate_ge/article/details/78941679;一个是input type=file获取图片之后,怎么加载到img元素中,以及在java后台如何处理这个可以解析为二进制流的图片数据字符串:http://blog.csdn.net/mate_ge/article/details/78848269


猜你喜欢

转载自blog.csdn.net/mate_ge/article/details/78941850