Angular简易分页设计(二):封装成指令

(首先声明本文来自博客园本人原创,转载请说明出处。欢迎关注:http://www.cnblogs.com/mazhaokeng/)

  之前我们讲过,Angular分页代码确实不难实现,但是由于在多个路由页码上使用到了分页,要一版一版地进行复制粘贴确实麻烦。倘若代码需要修改,那就满世界乱跑一处处修改。

  幸好我们有Angular directive(自定义指令)!Angularjs中内置了很多指令,常用的如ng-repeat、ng-class等等,我们也可以自己定义指令,而且在项目中是非常普遍的。具体是啥这里不多说明,推荐一篇文章 https://github.com/zhengweikeng/blog/issues/6 ,上面说的非常清楚。

  

  下面我们详细说说directive的封装。首先我们需要把html做成语义化标签,并把我们需要的变量暴露出来:

 <pagination page="page" max-page="maxPage" ng-click="pageTo()"></pagination>

  我们需要当前页和最大页数。pageTo()是父控制器绑定的函数,用于执行其余代码,不属于分页指令内部函数。然后我们就对directive的各个属性进行设置

app.directive('pagination', function() {
return {     
    //
html
        template:
            '<div class="pagination">' +
                '<ul class="pager">' +
                    '<li><a href="javascript:void(0)" ng-click="pageGo(1)">首页</a></li>' +
                    '<li><a href="javascript:void(0)" ng-click="pagePre()">上一页</a></li>' +
                '</ul>' +
                '<ul>' +
                    '<li ng-repeat="num in pageShowList" ng-class="{active: clickPage == num}">' +
                    '<a href="javascript:void(0)" ng-click="pageGo(num)">{{num}}</a>' +
                    '</li>' +
                '</ul>' +
                '<ul class="pager">' +
                    '<li><a href="javascript:void(0)" ng-click="pageNext()">下一页</a></li>' +
                    '<li><a href="javascript:void(0)" ng-click="pageGo(maxPage)">尾页:{{maxPage}}</a></li>' +
                '</ul>' +
            '</div>',
        //替换
        replace: true,

  首先,html标签名字pagination必须要和js代码一致,而返回的属性template是我们的html代码,需要用字符串的方式拼接起来,replace属性为true,表示代码运行时需要把标签替换成template内的html代码。这样需要用到分页的页码只要引入pagination标签就可以了。

  然后是我们的js代码。由于各个功能函数基本是与父控制器隔离的(模块化),我们需要把代码写在link函数内而不是controller内。controller函数一般用于指令之间可复用代码的编写。详细分页功能实现的代码在前一篇文章中有说明,这里不多说。我们就说说为什么需要对最大页数maxPage进行监听。

            /*  监听最大页数,如果页数变化,重新生成页数数组
            * */
            var watch = $scope.$watch('maxPage', function (newValue, oldValue, scope) {
                pageList = [];
                for (var i = 1; i <= newValue; i++) {   //一个个压入页码
                    pageList.push(i);
                }
                resetPageOrder($scope.page);
            });

  一开始设计时,我希望能够调用一个函数来对页码数量和页码数组进行初始化,因为在进行数据表搜索时,后台返回不同的表格,那么总页数也要跟着变化,所以初始化总页数和其数组是需要多次执行的。但是directive并没有能够把一个函数直接向父控制器暴露的方式,要强行暴露的话只能把函数封装服务。这样父控制器代码就会混乱了,一方面我需要指令的变量,另一方面又要注入此指令定义的服务,耦合度令人发指。

  我也试过把函数当成变量向外暴露,但是这个方式在本地测试时没问题,在测试服务器上就各种错误。明显这种非官方的小聪明是不能被Angular.js接受的。

  指令内部的变量对外暴露是最简单的,那么只要能让变量触发函数就没问题了。还好我们有Angular提供的$watch服务,只要设置总页数maxPage一旦变化,那么页码数组也重新生成不就得了吗!这样整个指令只需要把当前页page和最大页数maxPage对外暴露就行了,代码的耦合度回到了我们的预期。

  最后我们设置这两个变量的作用域,增加属性scope。

        //作用域
        scope:{
            page: '=',  //等号是双向绑定
            maxPage: '@'  
        },

  scope默认是false,表示一切变量对外暴露。html代码中的属性max-page中的值就与指令中的maxPage绑定了,注意html属性不支持驼峰法命名,所以用“-”分割单词。这里说明下:

(1)使用@符号进行单向绑定,类似于将父作用域中的变量拷贝一份到指令的独立作用域中。

(2)使用=符号表示变量是双向绑定的,page是向父作用域暴露的所以不使用@。

  具体项目我放在了Github上: https://github.com/makeng/Angular-pagination-/tree/master,欢迎大家指教。

 

posted @ 2017-05-02 12:42  Mazhaokeng  阅读(1369)  评论(0编辑  收藏  举报