壹 ❀ 引
angularjs開發中,組件件相互通信傳值是再普遍不過的操作了,比如我在父作用域中獲取了一個數據,想要傳遞給子組件使用,做簡單的做法就是通過scope傳遞,比如這樣:
<body ng-controller="myCtrl as vm"> <echo-demo data='vm.echo'></echo-demo> </body>
angular.module('myApp', []) .controller('myCtrl', function ($timeout) { let vm = this; vm.echo = { name: '聽風是風' }; }).directive('echoDemo', function () { return { restrict: 'EA', template: '<div>{{$ctrl.name.name}}</div>', replace: true, scope: { data: '<' }, controllerAs: '$ctrl', controller: function ($scope) { let self = this; self.$onInit = function () { self.name = $scope.data; }; } } });
拷貝,正常子組件會顯示 聽風是風。
我們將問題升級,假設父獲取的數據為異步操作,比如我們將上方代碼中父控制器的變量外層添加定時器模擬異步操作,其它不變:
$timeout(() => { vm.echo = { name: '聽風是風' }; }, 3000);
你會發現這樣子組件就拿不到數據了,因為異步的問題,子組件初始化會先執行,此時數據為undefined。那么怎么解決呢?
貳 ❀ 解決異步通信
第一種最常見,直接不用scope傳遞了,改用事件通信,父什么時候拿到值,就開始派發事件,子組件內響應監聽。
// 父作用域 利用定制器模擬異步請求 $timeout(() => { $scope.$broadcast('傳數據啦',data); }, 3000); // 子作用域 $scope.$on('傳數據啦', function (event, data) { // 拿到data了... });
有沒有更簡單的辦法,有,給組件名上添加一個ng-if就好了,像這樣:
<echo-demo data='vm.echo' ng-if="vm.echo"></echo-demo>
添加了ng-if后你會發現即便父作用域初始化數據外層有$timeout也沒關系,這是因為ng-if的本意就是,當ng-if后的數據什么時候不為false才加載dom,所以這里就成了什么時候父作用域拿到數據,組件才開始渲染加載。
真的是很巧妙的借用了ng-if的特性,解決了異步傳值的問題。大家如果對於angularjs事件通信有疑問可以閱讀 angularjs事件通信$on,$emit,$broadcast詳解 這篇文章。
那么本文結束。