老样子,先上效果图:
这个是在浏览器中使用的效果:
这个两个是在华为畅玩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赋给imgUrl,imgUrl改变时也将值赋给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,所以真机模式下,只能通过修改这个input的type属性,摧毁这个元素节点*/ 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: '您的设备不支持文件预览!',}); } /*选择文件之后,把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, 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://www.jb51.cc/article/p-wutuatrp-bro.html;一个是input type=file获取图片之后,怎么加载到img元素中,以及在java后台如何处理这个可以解析为二进制流的图片数据字符串:http://www.jb51.cc/article/p-gcarqavs-brn.html;
原文链接:https://www.f2er.com/angularjs/145358.html