怎么将图片上传封装成指令?

一、背景介绍

如果我们想实现图片上传功能,其中需要包含以下功能
*点击按钮上传图片
*图片能在本地预览
*显示图片信息,显示上传进度
*点击上传按钮上传到服务器
*点击删除按钮,删除。
*上传按钮只能按一次
现在我们需要把它用directive自定义指令封装起来。
为什么要封装呢?这个图片上传插件如果需要多次运用的话,用自定义指令封装后能减少大量代码。

二、知识剖析

关于指令,网上有很多资料,这里就简单说一下。
angular指令本质上就是AngularJs扩展具有自定义功能的html元素的途径。
angular指令本质上就是AngularJs扩展具有自定义功能的html元素的途径。
内置指令,打包在AngularJs内部的指令,所有内部指令的命名空间 都使用ng作为前缀,所以在写自定义指令的时候,避免用ng作为指令命名的前缀。
创建指令的方式有四种,在指令里用 restrict属性控制:
*E:元素
*A:属性
*C:css类
*M:注释
向指令中传递数据,用template属性
directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互:
*@ 绑定一个局部 scope 属性到当前 dom 节点的属性值。结果总是一个字符串,因为 dom 属性是字符串。
*= 通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定。
*& 提供一种方式执行一个表达式在父 scope 的上下文中。如果没有指定 attr 名称,则属性名称为相同的本地名称。(其实说白了,就是可以使用在父scope中定义的函数。)
replace:是否用模板替换当前元素。
true : 将指令标签替换成temple中定义的内容,页面上不会再有标签;
false :则append(追加)在当前元素上,即模板的内容包在标签内部。默认false。

三、常见问题

如何实现封装?

四、解决方案

见代码

五、编码实战

//template
<form name="myForm" class="col-lg-10">
    <div class="row">
        <div class="col-lg-10 col-sm-12">
            <div class="row">
                <label class="col-md-2 col-sm-12 titles">{{labelName}}</label>
                <div class="col-lg-12" ng-if="uploader">
                    <label class="btn-pic" for="{{imgId}}" style="float:left;">
                        选择文件
                    </label>
                    <input type="file" accept="image/*"
                           name="file" id="{{imgId}}"
                           style="display: none;"
                           nv-file-select=""
                           uploader="uploader"
                           multiple="">
                    <label style="line-height:.3rem;">(图片最大为1m)</label>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-12">
                    <!--图片预览-->
                    <img style="max-width: 100%;" ng-src="{{imageUrl}}">
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-lg-10">
            <!-----上传图片插件----->
            <table class="table">
                <thead>
                <tr>
                    <th>图片名</th>
                    <th>文件大小</th>
                    <th>进度</th>
                    <th>状态</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                <tr ng-repeat="item in uploader.queue">
                    <td style="word-break:break-all">
                        <strong>{{ item.file.name }}</strong>
                    </td>
                    <td nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
                    <td>
                        <div class="progress" style="margin-bottom: 0;">
                            <div class="progress-bar" role="progressbar"
                                 ng-style="{ 'width': item.progress + '%' }"></div>
                        </div>
                    </td>
                    <td class="text-center">
                        <span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
                        <span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
                        <span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
                    </td>
                    <td>
                        <button type="button" class="btn btn-success btn-xs" ng-click="item.upload()"
                                ng-disabled="item.isReady || item.isUploading || item.isSuccess">
                            <span class="glyphicon glyphicon-upload"></span> Upload
                        </button>
                        <button type="button" class="btn btn-warning btn-xs" ng-click="item.cancel()"
                                ng-disabled="!item.isUploading">
                            <span class="glyphicon glyphicon-ban-circle"></span> Cancel
                        </button>
                        <button type="button" class="btn btn-danger btn-xs" ng-click="item.remove()">
                            <span class="glyphicon glyphicon-trash"></span> Remove
                        </button>
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
    </div>
</form>
//directive
angular.module("myApp")
    .directive("uploadFile", function (FileUploader) {
        return {
            restrict: "EA",
            templateUrl: "html/fileUpload.html",
            scope: {
                labelName:"@",
                imageUrl:"=ngModel",
                imgId:"@"
            },
            replace: true,
            link: function (scope,ele,attrs) {
                // 上传图片插件
                scope.uploader = new FileUploader({
                    url: "/carrots-admin-ajax/a/u/img/task",
                    queueLimit: 1
                });
                scope.uploader.onSuccessItem = function (fileItem, response,status,headers) {
                    scope.imageUrl = response.data.url;
                };
            }
            //link或者controller都可以达到效果
            // controller:function ($scope) {
            //     // 上传图片插件
            //     $scope.uploader = new FileUploader({
            //         url: "/carrots-admin-ajax/a/u/img/task",
            //         queueLimit: 1
            //     });
            //     $scope.uploader.onSuccessItem = function (fileItem, response,status,headers) {
            //         $scope.imageUrl = response.data.url;
            //     };
            // }
        }
    });
//html
<upload-file ng-model="params.img" img-id="img" label-name="article图片"></upload-file>

六、扩展思考

指令中controller跟link的区别?当我们每次想要扩展个自定义指令时,应该用哪个?
简单来说,优先使用link。事实上,这两个都可以获取到作用域,元素,属性等引用,也都会执行一次。
控制器可以暴露一个API,而link可以通过require与其他的指令控制器交互。
所以如果要开放出一个API给其他指令用就写在controller中,否则写在link中。

七、更多讨论

讨论点一、去掉template页中第7行的「ng-if="uploader"」,使用link就会报错,使用controller则正常,这是为什么?
讨论点二、如何上传多张图片?
讨论点三、&方法该如何应用?

八、参考文献

参考一:angular自定义指令详解

参考二:Angular File Upload

参考三:angular-file-upload 中文API

参考四:ng指令中controller与link的区别

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342