老规矩,先上效果图:


首先说一下本文的重点:

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',        replace: true,        templateUrl: 'js/directives/page-tab/page.tab.template.html',        scope: {
            list: '=data',            onClick: '&onClick',            itemNum: '@'
        },$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);
                    }
                };

            }
        ],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',        templateUrl: 'js/directives/page-content/page-content.template.html',            postchange:'&postchange'
        },$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);
                    }
                };
            }
        ],attrs) {
        }
    }
});

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

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

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

angularJs自定义指令父子指令通信的更多相关文章

  1. 详解html5 postMessage解决跨域通信的问题

    这篇文章主要介绍了详解html5 postMessage解决跨域通信的问题的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. 详解使用postMessage解决iframe跨域通信问题

    这篇文章主要介绍了详解使用postMessage解决iframe跨域通信问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5调用手机发短信和打电话功能

    这篇文章主要介绍了HTML5调用手机发短信和打电话功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. 真正的iOS设备和Watch Simulator可以进行通信以进行测试

    我想为现有的iOS应用创建一个手表应用.但我处于一种情况,我没有苹果手表,我现有的iOS应用程序只能在不在模拟器上的真实设备上运行.是否可以在iPhone设备上运行应用程序并在手表模拟器中测试我的手表应用程序?解决方法至少在目前,不可能配对真正的iPhone和Watch模拟器.我得出这个结论有三个原因:>Watch模拟器在安装过程中自动与iPhone模拟器配对.>根本无法从界面取消配对Watch模拟器.>在模拟器上无法访问蓝牙以与真实设备进行通信.这是一个proof.

  5. ios – 之前的分裂字符串:和之前?

    我有一个像这样的长字符串:我想在之后拆分字符串:之前?.所以我想进入数组:我知道我可以这样做:但这还不够.我该怎么办?任何帮助将不胜感激!

  6. ios – 如何使用iphone使用蓝牙或wifi与OBD II进行通信

    我想为iOS创建一个简单的应用程序,它通过ODBIIWifi/蓝牙设备从汽车读取数据并在iPhone屏幕上显示.但我不知道从哪里开始.请有人帮我实现以下结果.我有蓝牙和wifi加密狗.第1步:配对蓝牙或Wifi加密狗和iPhone.第2步:通过加密狗阅读详细信息请参阅我能够轻松理解的任何教程或示例代码.我想深入了解这些过程,并希望自己编写代码.所以请帮忙.提前致谢.解决方法正如David所说,在i

  7. ios – Arduino和iPhone与蓝牙3.0的连接

    我想构建一个需要蓝牙连接的应用程序.蓝牙HC05模块连接到Arduino.我想知道构建可连接到此蓝牙模块的应用程序所需的框架.仍然不知道如何开始.有人可以帮忙吗?

  8. 可以通过iOS中的蓝牙PAN与系留设备进行通信

    我有一个设备,我通过蓝牙从iOS设备分享我的连接.我想知道是否可以访问在PAN网络上的iPhone上创建服务器并从设备访问它或在设备上创建服务器并从iPhone访问它.有没有人有这种经历?

  9. ios – 与容器视图通信的最佳实践是什么?

    我最近经常使用容器VC,我一直想知道主Vc和容器VC之间的最佳通信方式是什么.现在我正在使用通知,但我宁愿使用更好的东西.如何获取指向容器VC的指针,以便至少可以使用委托?

  10. ios – ViewModel和Controller之间通信的最佳方式

    我是开发新手,最近练习MVVM设计模式.在viewmodel&控制器我正在使用Closure.我知道我也可以使用Delegate.但是有什么惯例或理由我应该遵循什么样的沟通方式.我有点困惑.任何帮助将不胜感激.解决方法我也在寻找这个答案,我发现了这个,将UI层(UIL)中的闭包传递到业务逻辑层(BLL)会破坏关注点(SOC).您准备的数据驻留在BLL中,所以基本上您会说“嘿BLL为我执行此UIL逻

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部