AngularJs 第一個自定義指令編寫

    公司在作一個OA系統, 包括移動端(從微信企業號進入OA系統),電腦端。 javascript

    電腦端仍是用的傳統的easyui作界面,asp.net mvc做爲服務端。這個技術已經很成熟了配合權限框架很快就能開發出來。可是手機端以前團隊也沒有什麼經驗,我以前作過一個jqureymobile的項目,可是這個框架實在是太卡了,直接pass掉。剛好以前有自學一點點angularjs 因此我就推薦手機端的項目使用angularjs來開發,一來團隊能夠學習一些新技術跟上潮流,二來單頁程序很適合咱們目前的這個小項目,三是咱們之後打算用phonegap直接打包webapp。好吧優勢這麼多那就開工吧(咱們用的是1.5版本,2.0國內還比較少)。html

    因爲團隊以前沒有接觸過這個框架,因此大概花了3天時間來學習(正常開發任務仍是有,相對減小),可想而知以angularjs學習曲線咱們的成果不會好到哪裏去,項目不等人,前端

angularjs確實很不錯給前端帶來不少新的概念:mvc 模塊化 單頁 依賴注入 指令 等。首先咱們遇到的問題是怎麼團隊開發,不可能你們都讀寫一個js文件吧,因而採用第三方的oclazyload.js來動態加載js和模板,路由採用angular-ui-router,其次咱們須要一款手機端的ui來配合angularjs,咱們選用了淘寶的sui。一切準備好了,那就開始吧!java

    進入正題,個人第一個angularjs的指令設計,需求以下:angularjs

     1.OA填完單以後,須要選擇審覈人。(這個比較次了,正規的OA是不須要本身選擇審覈人的,可是咱們是簡單版的,何況大名鼎鼎的阿里巴巴 釘釘OA也是這麼設計的)。web

     2.作成通用組件。微信

    需求就這些了,那麼直接上結果看看:mvc

    1.主頁面app

    

  2.審批頁面框架

3.用車申請

4.選人指令

 

 

  以上順便介紹了一下個人OA系統,那麼下邊再看看最終作出來的選審覈人的指令:

1.

  

2.

 

3.

5.

好吧這個功能基本是釘釘的翻版。那麼我如何來設計這個指令的呢,首先,彈出框這些ui都是來自於sui的ui插件,我作的事情就是用angularjs的指令來封裝ui和一些邏輯,最終達到的通用的目標。上代碼:

  1 /*
  2 *用於選擇部門及用戶
  3 *劉功葵 2016-4-9
  4 *
  5 */
  6 var departUser = angular.module("ktfOA");
//第一個指令,彈出部門和人員選擇框
7 departUser.directive("departpopup", function ($http) { 8 return { 9 restrict: 'AECM',//<!-- departpopup --> 10 //replace: true, 11 transclude: true, 12 scope: { 13 pop: '@',//部門彈出框的id,爲了讓同一個頁面多吃使用指令時,不出現重複ID 14 peng: '@',//人員彈出框id 15 selects: '=', //經過=綁定最終的選擇結果,並傳遞到外層的controller 16 users: '=', 17 dowork: "&" //在選擇用戶時執行的方法 18 }, 19 20 templateUrl: '/Areas/Phone/Directive/DepartUser/DepartUser.html', 21 controller: function ($scope) { 22 this.open = function () { 23 $.popup('#' + $scope.pop); 24 } 25 26 }, 27 link: function (scope) { 28 scope.pop = scope.pop || "pop"; 29 scope.peng = scope.peng || "peng"; 30 scope.$emit('ngPageFinished'); //$emit 給父scope返回一個值 父scope能夠監控這個值 而後執行一些代碼 至關於事件傳播 31 $http.post("/Phone/BusinessTravel/GetApiDepartList").success(function (msg) { 32 scope.departList = msg; 33 }) 34 /*選擇部門事件*/ 35 scope.selectDepart = function (departId) { 36 $.popup('#' + scope.peng); 37 scope.formJson = { 'departId': departId } 38 $http.post("/Phone/BusinessTravel/GetAipAdminUserList", scope.formJson).success(function (msg) { 39 scope.adminUserList = msg; 40 }) 41 } 42 scope.selects = []; 43 /*選擇用戶事件*/ 44 scope.selectUser = function () { 45 46 scope.noPic = true; 47 if (this.itemUsr.AbsoluteImgSrc == "" || this.itemUsr.AbsoluteImgSrc == undefined) { 48 49 this.itemUsr.AbsoluteImgSrc = "/Images/UserHeadPic/default.jpg"; 50 } 51 for (var i = 0; i < scope.selects.length; i++) { 52 if (scope.selects[i].UserNo == this.itemUsr.UserNo) { 53 $.alert('用戶已選過,不能重複!'); 54 return; 55 } 56 } 57 scope.selects.push(this.itemUsr); 58 scope.users += this.itemUsr.UserNo + ","; 59 $.closeModal('#' + scope.peng); 60 $.closeModal('#' + scope.pop); 61 62 if (scope.dowork != undefined) { 63 scope.dowork(); 64 } 65 66 } 67 } 68 69 }; 70 71 72 }) 73 74 75 76 //第二個指令,依賴於第一個指令,用於顯示最終的選擇結果。 77 departUser.directive("userselect", function ($http) { 78 return { 79 restrict: 'AECM',//<!-- departpopup --> 80 replace: true, 81 require: '^?departpopup', //此處是指依賴上面一個指令 82 scope: { 83 selects: "=", 84 users: "=" 85 }, 86 template: ' <div> <div ng-click="delUser()" style="float:left;position:relative" ng-repeat="user in selects"><img style="border-radius:50%; height:56px;width:56px; overflow:hidden;" src="{{user.AbsoluteImgSrc}}" /><span style="position:absolute;left:7px;top:19px;font-size:small;color:white;text-align:center;width:40px;height:20px;" >{{user.UserName}}</span><span style="float:right;margin-top:8px;">...</span></div> <div style="float:left;margin-top:8px;"><a ng-click="Open()" class="open-about"><i class="fa fa-plus-circle fa-2x" style="color:#bab7b7"></i></a></div></div>', 87 link: function (scope, element, attrs, departpopupController) { 88 //$(".datetime-pickerStart").datetimePicker({}); 89 //$(".datetime-pickerEnd").datetimePicker({}); 90 scope.Open = function () { 91 departpopupController.open(); 92 93 } 94 95 //刪除選擇的用戶 96 scope.delUser = function () { 97 98 var userNo = this.user.UserNo; 99 100 for (var i = 0; i < scope.selects.length; i++) { 101 if (scope.selects[i].UserNo == userNo) { 102 scope.selects.splice(i, 1); 103 break; 104 } 105 } 106 scope.users = ""; 107 for (var i = 0; i < scope.selects.length; i++) { 108 scope.users += scope.selects[i].UserNo + ","; 109 } 110 111 } 112 } 113 114 }; 115 116 117 })

2.模版頁面

<div> 
    <div class="popup" id="{{pop}}">
        <header  class="bar bar-nav">
            <a class="icon icon-left pull-left close-popup"></a>
        </header>
        <div class="bar bar-header-secondary" style="position:relative">
            <div class="searchbar">
                <a ng-click="abc()" class="searchbar-cancel">取消</a>
                <div class="search-input">
                    <label class="icon icon-search" for="search"></label>
                    <input type="search"  id='search' placeholder='輸入關鍵字...' />
                </div>
            </div>
        </div>
        <div class="list-block contacts-block">
            <div class="list-group">
                <ul>
                    <li ng-repeat="item in departList track by $index" class="open-services" ng-click="selectDepart(item.DepartID)" departid="{{item.DepartID}}">
                        <div class="item-content item-link">
                            <div class="item-inner">
                                <div class="item-title">
                                    <span style="color:#c6c4c4">{{item.TreeText}}</span>&nbsp;&nbsp;{{item.DepartName}}
                                </div>
                            </div>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
        <div class="popup" id="{{peng}}">
            <header class="bar bar-nav">
                <a class="icon icon-left pull-left close-popup"></a>
            </header>
            <div class="bar bar-header-secondary" style="position:relative">
                <div class="searchbar">
                    <a class="searchbar-cancel">取消</a>
                    <div class="search-input">
                        <label class="icon icon-search" for="search"></label>
                        <input type="search" id='search' placeholder='輸入關鍵字...' />
                    </div>
                </div>
            </div>
            <div class="list-block contacts-block">
                <div class="list-group">
                    <ul ng-repeat="itemUsr in adminUserList track by $index">
                        <li ng-click="selectUser()" userno="{{itemUsr.UserNo}}" username="{{itemUsr.UserName}}">
                            <div class="item-content">
                                <div class="item-inner">
                                    <div class="item-title">
                                        <span style="color:#c6c4c4">{{itemUsr.UserNo}}</span>&nbsp;&nbsp;{{itemUsr.UserName}}
                                    </div>
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
        </div>

    <div ng-transclude></div>
    </div>

 
DepartUser.html

3.在車輛申請頁面的使用

<!--
/************************************************************************/
/*
 * 建立人:向高
 * 建立日期:2016-04-01
 * 文件描述:車輛申請表單頁面
 */
/************************************************************************/
-->
<div ng-controller="CarApply">

    <header class="bar bar-nav">
        <a class="button button-link button-nav pull-left" ui-sref="Index">
            <span class="icon icon-left"></span>
            返回
        </a>
        <h1 class='title'>用車申請</h1>
    </header>
    <departpopup selects="selects" users="users" pop="pop" peng="peng1">

        <div class="content" style="top:0.9rem">

            <div class="list-block">
                <ng-form name="CarForm" novalidate>
                    <!--ng-submit="save(CarForm.$valid)"-->
                    <ul>
                        <!-- Text inputs -->
                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-name"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">用車事由</div>
                                    <div class="item-input">
                                        <textarea required name="AskReason" ng-model='Apply.AskReason' style="font-size:14px;" placeholder="請輸入(必填)"></textarea>
                                        <!--<input type="text">-->
                                    </div>
                                </div>
                            </div>
                        </li>
                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-email"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">始發地點</div>
                                    <div class="item-input">
                                        <input type="text" required  name="LevelPlace" ng-model="Apply.LevelPlace" style="font-size:14px;" placeholder="請輸入(必填)">
                                    </div>
                                </div>
                            </div>
                        </li>
                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">返回地點</div>
                                    <div class="item-input">
                                        <input type="text" required name="EndPlace" ng-model="Apply.EndPlace" style="font-size:14px;" placeholder="請輸入(必填)">
                                    </div>
                                </div>
                            </div>
                        </li>
                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">用車時間</div>
                                    <div class="item-input">
                                        <input type="text" name="LeaveTimeFrom" required ng-model="Apply.LeaveTimeFrom" id="datetime-pickerStart" style="font-size:14px;" placeholder="請輸入(必填)">
                                    </div>
                                </div>
                            </div>
                        </li>

                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">返程時間</div>
                                    <div class="item-input">
                                        <input type="text" name="LeaveTimeTo" required ng-model="Apply.LeaveTimeTo" id="datetime-pickerEnd" style="font-size:14px;" placeholder="請輸入(必填)">
                                    </div>
                                </div>
                            </div>
                        </li>

                        <li ng-repeat="cars in cars" on-finish-render-filters>
                            <div class="item-content" style="top:0.7rem;padding-left:20px;background:#f3f2f2;line-height:55px;font-size:14px;height:40px">
                                <div style="width:85px;float:left"> <span>車輛明細({{$index+1}})</span></div>
                                <div style="width:70px;float:right;padding-right:15px;" ng-if="$index+1>1"><span><a href="javascript:void(0)" ng-click="deleteCar()">刪除</a></span></div>
                            </div>
                            <!--<div class="content-block-title xingcheng" style="margin-left:30px;font-size:small">車輛明細({{$index+1}})</div>-->
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">車輛選擇</div>
                                    <div class="item-input">
                                        <input type="text" class='picker' required name="BusInfo" ng-model="cars.BusInfo" style="font-size:14px;" placeholder="請選擇(必選)">
                                    </div>
                                </div>
                            </div>

                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">數量</div>
                                    <div class="item-input">
                                        <input type="text" ng-change="getCarNum()" required name="AskNum" ng-model="cars.AskNum" required style="font-size:14px;" placeholder="請輸入(必填)">
                                    </div>
                                </div>
                            </div>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">其餘要求</div>
                                    <div class="item-input">
                                        <input type="text" name="Remark" ng-model="cars.Remark" style="font-size:14px;" placeholder="請輸入">
                                    </div>
                                </div>
                            </div>
                        </li>

                        <li><div class="content-block-title xingcheng" style="margin-left:30px;font-size:small">如需多種車型,請點擊「添加車輛」</div></li>
                        <li style="text-align:center;"><a style="cursor:pointer" ng-click="AddMore()"><i class="fa fa-plus" style="color:blue"></i>添加車輛</a></li>
                        <li><div class="item-title label inputSize" style="margin-left:30px;">總數量(輛):{{carnum}}</div></li>
                        <li>
                            <div class="item-content">
                                <div class="item-media"><i class="icon icon-form-gender"></i></div>
                                <div class="item-inner">
                                    <div class="item-title label inputSize">備註</div>
                                    <div class="item-input">
                                        <textarea  name="Remark" ng-model='Apply.Remark' style="font-size:14px;" placeholder="請輸入"></textarea>

                                    </div>
                                </div>
                            </div>
                        </li>

                        <li style="padding-left:30px; height:110px;">
                            <div><span>審批人</span><span style="font-size:small;color:#999999">(點擊頭像可刪除)</span></div>
                            <userselect selects="selects" users="users"></userselect>
                        </li>
                    </ul>
                </ng-form>
            </div>
            <div class="content-block">
                <div class="row">
                    <div class="col-50"><a href="#" class="button button-big button-fill button-danger">取消</a></div>
                    <div class="col-50"><a ng-class="{true:'button button-big button-fill button-success',false:'button button-big button-fill button-success disabled'}[CarForm.$valid]" ng-click="save(CarForm.$valid)" >提交</a></div>
                    <!--<a ng-class="{true:'button button-big button-fill button-success',false:'button button-big button-fill button-success disabled'}[CarForm.$valid]"  ng-click="save(CarForm.$valid)" class="button button-big button-fill button-success">提交</a>-->
                </div>
            </div>
        </div>
    </departpopup>
</div>
CarApply.html

4.車輛申請頁面的Controller

//var CarApplyModule = angular.module("CarApplyModule", ['ngAnimate']);

/************************************************************************/
/*
 * 建立人:向高
 * 建立日期:2016-04-01
 * 文件描述:車輛申請控制器
 */
/************************************************************************/

 
var CarApplyModule = angular.module("ktfOA");
CarApplyModule.controller("CarApply", function ($scope, $http, CalcService, $state, $stateParams) {
    
    var selectCars = []; //保存根據用車時間 獲取可選車輛
    $scope.cars = [{ BusInfo: "", AskNum: 1, Remark: "" }]; //用於初始化repeater
    $scope.carnum = parseInt($scope.cars[0].AskNum);
    $scope.users = "";//審覈人
    $scope.selects = []; //選人控件 傳回來的選擇用戶集合
    //$scope.selectCars = []; //保存根據用車時間 獲取可選車輛
    $scope.Apply = {
        AskReason: "", LevelPlace: "", EndPlace: "",
        LeaveTimeFrom: "", LeaveTimeTo: "", Remark: "",
        Detail: $scope.cars, users: ""

    };


    $scope.getCarNum = function () {
        var num = 0;
        for (var i = 0; i < $scope.cars.length; i++) {

            if ($scope.cars[i].AskNum != undefined) {
                num += parseInt($scope.cars[i].AskNum);
            }
        }
        $scope.carnum = num;
    }


    //提交表單數據
    $scope.save = function () {
        if ($scope.selects.length <= 0)
        {
            $.alert("請選擇審覈人!");
            return;
        }
        //獲取審覈人
        var users = "";
        for (var i = 0; i < $scope.selects.length; i++) {
            users += $scope.selects[i].UserNo + ",";
        }
       
        $scope.Apply.users = users;
        $http({ method: 'POST', url: '/phone/CarApply/SaveCarApply', data: JSON.stringify($scope.Apply) }).
         success(function (response) {
             if (response.status == 2) {

                 $.alert(response.msg);
             }
             else if (response.status == 1) {
                 $.alert(response.msg, function () { $state.go("AuditHome"); }); 
             }
         });
    }

    //添加車輛
    $scope.AddMore = function () {
        $scope.cars.push({ BusInfo: "", AskNum: "", Remark: "" });
    }

    //刪除車
    $scope.deleteCar = function () {
        var index = this.$index;
        $scope.cars.splice(index,1);
    }

    //選取用車時間時 獲取車輛信息
    $scope.GetCars = function () {

        if ($scope.Apply.LeaveTimeFrom != "") {
            $http({ method: 'POST', url: '/phone/CarApply/GetCars', data: { Stime: $scope.Apply.LeaveTimeFrom } }).success(function (data) {

                //var selects = [];
                if (selectCars.length > 0) {
                    selectCars.splice(0, selectCars.length);
                }
                for (var i = 0; i < data.length; i++) {
                    selectCars.push(data[i].BusName + data[i].BusType + "(" + data[i].BusSiteCount + "座)" + "  可用數量" + data[i].CarNum);
                }

                $(".picker").picker("setValue", selectCars);

            })
        }
    }

    $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {

        //初始化sui的選擇器控件
        $(".picker").picker({
            toolbarTemplate: '<header class="bar bar-nav">\<button class="button button-link pull-left">按鈕</button>\<button class="button button-link pull-right close-picker">肯定</button>\<h1 class="title">車輛信息</h1>\</header>',
            cols: [
              {
                  textAlign: 'center',
                  values: selectCars
                  //values: ['奧迪A6L(5座)', '豐田商務車(7座)', '豐田卡羅拉(5座)', '大衆帕薩特(5座)', '宇通大巴(47座)', '宇通中巴(24座)', 'iPad 2', 'iPad Retina', 'iPad Air', 'iPad mini', 'iPad mini 2', 'iPad mini 3']
              }
            ]

        });

    });

    $scope.$on('ngPageFinished', function (ngPageFinishedEvent) {
        $("#datetime-pickerStart").datetimePicker({
            onClose: function () {
                $scope.GetCars();
            }
        });
        $("#datetime-pickerEnd").datetimePicker({});
    })


    $scope.getNum = function () {
        var num = 0;
        for (var i = 0; i < $scope.cars.length; i++) {
            num += $scope.cars[i].AskNum;
        }
        return num;
    }


})


CarApplyModule.directive('onFinishRenderFilters', function ($timeout) {
    return {
        restrict: 'A', //匹配模式:A(屬性方式)E(元素)M(註釋  <!-- directive:xx -->)C(class方式 class = xx),angular 默認使用A
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                });
            }
        }
    };
});
CarApplyController

簡單的使用方式:

    <departpopup selects="selects" users="users" pop="pop" peng="peng1">

    <userselect selects="selects" users="users"></userselect>

    </departpopup>

  注意兩個指令是嵌套的關係。selects和users等就是外部controller和指令之間的綁定,用於傳遞數據。

 以上就是個人第一個angularjs指令。下邊談談遇到的坑:

  首先我只用一個指令來搞定,可是不行,由於sui必須將彈出框放在body元素裏邊,不能放在li元素,不然就彈不出來。我想到這是樣式的問題,因而手動來更改sui彈出框的定位樣式,可是這不是一個好辦法,電腦上還能夠,可是手機上會出現兼容問題。最後我想到能夠用兩個指令來寫這個插件,外層的<departpopup>負責彈出框(放在body標籤裏邊),內部的<userselect>用於顯示最終的結果。這會有涉及兩個指令之間的數據傳遞,和相互調用。

   大概就這些,我也是剛開始學習,路過的大牛們請不惜賜教。感謝!

相關文章
相關標籤/搜索