老规矩,先上效果图:


首先说一下本文的重点:

1、父指令如何调用子指令中的方法;2、子指令如何调用父指令中的方法;(都不是通过广播的方式)

如果有同学还不知道父指令如何通过=@&给子指令传递参数,或者一些其他自定义指令的属性(scope、complie、link……)的话,请查阅官网文档发或者其他文档博客。

前言:

在自学了一段时间VUE之后,被VUE简洁的代码以及强大的解耦能力深深折服,所有的界面元素都是组件,组件有聪明组件和笨组件之分,聪明组件就是业务组件,负责复杂的业务逻辑,而笨组件则负责一些基本的数据获取功能,界面显示等等,比如日期选择插件、轮播图显示等等,在开发的时候往往需要大量的笨组件。无奈公司标准产品的开发使用的是angularJs,一下子就有一种一夜回到解放前的感觉,这就跟从IntelliJIDEA回到eclipse的感觉是一样一样的。由于自学了一段时间VUE,搞的我现在使用angularJs也是使用VUE的思想,想方设法拜托angularJs中凌乱的代码,统统用指令解耦。

在angularJs中编写自定义指令没有VUE中编写组件那么方便,父子组件之间的通信,作用域的互相引用等等,在angularJs中并没有VUE中那么清晰,所以在编写自定义指令的时候需要特别注意一些问题。

这个demo是基于onsenui写的,主要用了了里面的ons-carousel轮播插件以及ons-icon图片两个自定义指令,不过这个对本次总结没有任何影响。

首先说一下界面结构,这个界面中有三个指令,第一个是page-tab,就是标题状态栏下面可以左右滑动的page1、2、3……的那一行,然后是下面白色区域的页面page-content,最后是page-tabbar,page-tabbar包含了page-tab以及page-content,首先看一下主页面的代码:

<ons-page class="hg-agency-item" ng-controller="hgAgencyItemController">
    <ons-toolbar>
        <div class="left">
            <ons-back-button></ons-back-button>
        </div>
        <div class="center">
            <span ng-bind="'这个是标题'"></span>
        </div>
        <div class="right">
            <ons-toolbar-button>
                <ons-icon icon="ion-search"></ons-icon>
            </ons-toolbar-button>
        </div>
    </ons-toolbar>
    <ons-page class="c-p">
        <page-tabbar data="tabItems" tab-num="4"></page-tabbar>
    </ons-page>
</ons-page>

很简单,就是在内容界面直接引用了page-tabbar指令,传入两个参数,data是数据,tab-num是page-tab显示的tab的个数,然后看一下controller:

由于部分数据不方便显示,所以打个码:

name就是tab的显示值,icon就是图标。数据很简单,用起来很简单,这就是编写自定义指令的目的。










name就是tab的显示值,icon就是图标。数据很简单,用起来很简单,这就是编写自定义指令的目的。

首先来看page-tabbar的html代码:

<ons-page>
    <page-tab data="data" item-num="{{tabNum}}" on-click="pageContent.setActiveIndex(index)" var="pageTab"></page-tab>
    <page-content data="data" var="pageContent" postchange="pageTab.setActiveIndex(index)"></page-content>
</ons-page>

也是很简单:

app.directive('pageTabbar', function () {
    return {
        restrict: 'E',
        replace: false,
        templateUrl: 'js/directives/page-tabbar/page.tabbar.template.html',
        scope: {
            data: '=data',
            tabNum:'@tabNum'
        },
        controller: [
            '$scope', '$element', '$attrs', '$transclude',
            function ($scope, $element, $attrs, $transclude) {
                angular.element(document).ready(function () {
                    console.log('pageTabbar ready');
                });
            }
        ],
        link: function (scope,element,attrs) {
        }
    }
});

这个指令的作用只是负责传递数据以及,当page-tab或者page-content改变时,通知另一个改变(调用指令中暴露的方法),这个是在html代码中写的,指令声明代码中没有显示调用子指令方法的代码,很简便。

在<page-tab>中属性var的值表示会在当前page-tabbat的作用域中创建一个pageTab对象,通过$scope.pageTab可以调用page-tab指令中暴露的方法;

接下来看page-tab指令:

html代码:

<div>
    <ons-carousel var="pageTabCarousel" ons-postchange="console.log('Changed to ' + $event.activeIndex)" overscrollable
                  style="height: 64px"
                  swipeable auto-scroll item-width="{{itemWidth}}">
        <ons-carousel-item style="background:transparent" ng-repeat="item in list" class="page-tab-carousel-item"
                           ng-click="onClickItem($index)">
            <div class="page-tab" ng-class="{true:'emphasize',false:'normal'}[currentIndex == $index]" ng-click="onClick({index:$index,item:item})">
                <div class="page-tab page-tab-content">
                    <ons-icon icon="{{item.icon}}"></ons-icon>
                    <span ng-bind="item.name"></span>
                </div>
            </div>
        </ons-carousel-item>
    </ons-carousel>
</div>

js声明指令代码:

app.directive('pageTab', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'js/directives/page-tab/page.tab.template.html',
        scope: {
            list: '=data',
            onClick: '&onClick',
            itemNum: '@'
        },
        controller: [
            '$scope', '$element', '$attrs', '$transclude',
            function ($scope, $element, $attrs, $transclude) {
                angular.element(document).ready(function () {
                    pageTabCarousel.setActiveIndex($scope.currentIndex);
                });

                $scope.onClickItem = function (n) {
                    $scope.currentIndex = n;
                    n >= 1 && n--;
                    pageTabCarousel.setActiveIndex(n);
                };
                $scope.currentIndex = 0;

                $scope.$parent.$parent[$attrs.var] = {
                    setActiveIndex: function (index) {
                        $scope.onClickItem(index);
                    }
                };

            }
        ],
        link: function (scope, element, attrs) {
            var num = attrs.itemNum - 0;
            scope.itemWidth = (100/num).toFixed(0)+"%";
        }
    }
});

这里只讲重点,在这个page-tab子指令中,通过这一段代码:

$scope.$parent.$parent[$attrs.var] = {
    setActiveIndex: function (index) {
        $scope.onClickItem(index);
    }
};

向父指令提供了一个对象,对象中的方法以及属性就是子指令暴露的方法,父指令可以通过调用这个对象的方法通知子指令做出相应的改变;

同理,page-content也是一样:

<ons-page
        style="
        position: absolute;
        bottom: 0;
        top: 64px;
        left: 0;
        right: 0px;
">
    <ons-carousel
            var="pageContentCarousel"
            ons-postchange="onCarouselChange()"
            fullscreen
            swipeable
            auto-scroll
            overscrollable>
        <ons-carousel-item ng-repeat="item in list">
            <ng-include src="item.url"></ng-include>
        </ons-carousel-item>
    </ons-carousel>
</ons-page>
app.directive('pageContent', function () {
    return {
        restrict: 'E',
        replace: false,
        templateUrl: 'js/directives/page-content/page-content.template.html',
        scope: {
            list: '=data',
            postchange:'&postchange'
        },
        controller: [
            '$scope', '$element', '$attrs', '$transclude',
            function ($scope, $element, $attrs, $transclude) {
                angular.element(document).ready(function () {
                    console.log('pageContent ready');
                });
                $scope.onCarouselChange = function () {
                    $scope.postchange({
                        index:pageContentCarousel.getActiveIndex()
                    });
                };

                $scope.$parent.$parent[$attrs.var] = {
                    setActiveIndex:function (index) {
                        pageContentCarousel.setActiveIndex(index);
                    }
                };
            }
        ],
        link: function (scope,element,attrs) {
        }
    }
});

在子指令中通知父指令做出变化的方法是,通过scope的@(对父作用域方法的引用)的方式,直接调用父指令传递的方法,调用方法的时候如果要传递参数,需要显示传递参数的key以及value,比如代码中的

$scope.onCarouselChange = function () {
    $scope.postchange({
        index:pageContentCarousel.getActiveIndex()
    });
};

index就是需要传递的参数,在父指令方法中获取参数的也是一样,参数要一致:



Logo

前往低代码交流专区

更多推荐