Angular 根据 service 的状态更新 directive

 更新时间:2016年4月6日 10:01  点击:2499

Angular JS (Angular.JS) 是一组用来开发Web页面的框架、模板以及数据绑定和丰富UI组件。它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作。

AngularJS是为了克服HTML在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了。这里AngularJS就应运而生,弥补了HTML的天然缺陷,用于构件Web应用等。

TL;DR

这篇文章讲解了三种根据 service 的状态更新 directive 的做法。分别是 $watch 表达式,事件传递,和 controller 的计算属性。

问题

我有一个 readerService ,其中包含一些状态信息(比如连接状态和电量)。现在我需要做一个 directive 去展示这些状态。因为它只需要从 readerService 中获取数据,不需要任何外部传值,所以我直接把 service 注入进去。但如何更新就成了一个问题。

service 的代码如下。

const STATUS = {
DETACH: 'DETACH',
ATTACH: 'ATTACH',
READY: 'READY'
}
class ReaderService {
constructor() {
this.STATUS = STATUS
// The status will be changed by some callbacks
this.status = STATUS.DETACH
}
}
angular.module('app').service('readerService', readerService)

directive 代码如下:

angular.module('app').directive('readerIndicator', (readerService) => {
const STATUS = readerService.STATUS
const STATUS_DISPLAY = {
[STATUS.DETACH]: 'Disconnected',
[STATUS.ATTACH]: 'Connecting...',
[STATUS.READY]: 'Connected',
}
return {
restrict: 'E',
scope: {},
template: `
<div class="status">
{{statusDisplay}}
</div>
`,
link(scope) {
// Set and change scope.statusDisplay here
}
}
})

我尝试过以下几种办法,下面一一介绍。

方法一:$watch

第一个想到的方法就是在 directive 中用 $watch 去监视 readerService.status 。因为它不是 directive scope 的属性,所以我们需要用一个函数来包裹它。Angular 会在 dirty-checking 时计算和比较新旧值,只有状态真的发生了改变才会触发回调。

// In directive
link(scope) {
scope.$watch(() => readerService.status, (status) => {
scope.statusDisplay = STATUS_DISPLAY[status]
})
}

这个做法足够简单高效,只要涉及 readerService.status 改变的代码会触发 dirty-checking ,directive 就会自动更新。service 不需要修改任何代码。

但如果有多个 directive 的属性都受 service status 的影响,那 $watch 代码就看得比较晦涩了。尤其是 $watch 修改的值会影响其他的值的时候。比如:

// In directive
link(scope) {
scope.$watch(() => readerService.status, (status) => {
scope.statusDisplay = STATUS_DISPLAY[status]
scope.showBattery = status !== STATUS.DETACH
})
scope.$watch('showBattery', () => {
// some other things depend on showBattery
})
}

这种时候声明式的编程风格会更容易看懂,比如 Ember 或 Vue 里面的 computed property 。这个待会讨论。

方法二:$broadcast/$emit + $on

这种思路是 service 每次状态改变都发送一个事件,然后 directive 监听事件来改变状态。因为 directive 渲染的时候也许 status 已经更新了。所以我们需要在 link 中计算一个初始值。

我最开始是用 $broadcast 去做的。代码如下:

// In service
setStatus(value) {
this.status = value
// Need to inject $rootScope
this.$rootScope.$broadcast('reader.statusChanged', this.status)
}
// In directive
link(scope) {
scope.statusDisplay = STATUS_DISPLAY[nfcReaderService.status]
scope.$on('reader.statusChanged', (event, status) => {
scope.statusDisplay = STATUS_DISPLAY[status]
})
}

但马上发现 $broadcast 之后 UI 更新总要等 1 秒多(不过 $on 回调倒是很快)。Google 一番后知道原因是 $broadcast 是向下层所有 scope 广播,广播完成后再 dirty-checking 。一个更好的做法是使用 $emit ,它只会向上传递事件,不过不管发送事件还是监听事件都得用 $rootScope 。

修改后的代码如下:

// In service
setStatus(value) {
this.status = value
// Use $emit instead of $broadcast
this.$rootScope.$emit('reader.statusChanged', this.status)
}
// In directive
link(scope) {
scope.statusDisplay = STATUS_DISPLAY[nfcReaderService.status]
// Use $rootScope instead of scope
$rootScope.$on('reader.statusChanged', (event, status) => {
scope.statusDisplay = STATUS_DISPLAY[status]
})
}

如果因为某些原因不得不用 $broadcast 的话,你可以在 $on 回调最后用 $digest 或 $apply 强制触发 dirty-checking ,这也可以达到快速更新 UI 的目的。

方法三:controller + property

我个人觉得前两个方法能解决问题,但代码维护性都不太好。 $watch 在属性相互关联的情况下非常难看懂, $emit/$on 需要把一些逻辑写两次(初始化 directive 时和回调执行时)。方法一中我提到了有些时候声明式的属性比 $watch 更容易看懂。这个方法就是使用 controller 。directive 可以设置自己的 controller 作为数据来源(或者说 view model),我们可以把那些需要计算的属性作为 controller 的属性。这样 dirty-checking 时它们就会自动计算。

// In directive
class ReaderController {
constructor($scope, readerService) {
this.readerService = readerService
}
get statusDisplay() {
return STATUS_DISPLAY[this.readerService.status]
}
}
return {
// ...
controller: ReaderController,
controllerAs: 'vm',
template: `
<div class="status">
{{vm.statusDisplay}}
</div>
}

这样一来,大部分逻辑都可以挪到 controller 中。如果没有 DOM 操作我们甚至可以不写 link 方法。也没必要加入额外的 $watch 和 $on 。只是因为 dirty-checking 的特性,绑定到 template 的属性往往会多计算几次。所以属性必须非常简单。大部分情况下这不会有什么问题。

以上内容是小编给大家介绍的Angular 根据 service 的状态更新 directive,希望对大家有所帮助!

[!--infotagslink--]

相关文章

  • 浅析AngularJS Filter用法

    系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点,这篇文章给大家介绍angularjs filter用法详解,感兴趣的朋友一起学习吧...2015-12-29
  • AngularJS 实现按需异步加载实例代码

    AngularJS 通过路由支持多视图应用, 可以根据路由动态加载所需的视图, 在 AngularJS 的文档中有详细的介绍, 网上也有不少教程, 就不用介绍了!随着视图的不断增加,js文件会越来越多,而 AngularJS 默认需要把全部的js都一次性...2015-10-21
  • AngularJS实现分页显示数据库信息

    这篇文章主要为大家详细介绍了AngularJS实现分页显示数据库信息效果的相关资料,感兴趣的小伙伴们可以参考一下...2016-07-06
  • angularjs $http实现form表单提交示例

    这篇文章主要介绍了angularjs $http实现form表单提交示例,非常具有实用价值,需要的朋友可以参考下 ...2017-06-15
  • AngularJS实现Model缓存的方式

    这篇文章主要介绍了AngularJS实现Model缓存的方式,分享了多种AngularJS实现Model缓存的方法,感兴趣的小伙伴们可以参考一下...2016-02-05
  • AngularJS自定义指令之复制指令实现方法

    这篇文章主要介绍了AngularJS自定义指令之复制指令实现方法,结合完整实例形式分析了AngularJS自定义指令实现复制功能的相关操作技巧,需要的朋友可以参考下...2017-05-22
  • AngularJS 视图详解及示例代码

    本文主要介绍AngularJS 视图,这里整理了相关知识,并附代码示例和实现效果图,有兴趣的小伙伴可以参考下...2016-08-27
  • AngularJS 依赖注入详解及示例代码

    本文主要介绍AngularJS 依赖注入的知识,这里整理了相关的基础知识,并附示例代码和实现效果图,有兴趣的小伙伴可以参考下...2016-08-24
  • 浅谈AngularJs指令之scope属性详解

    下面小编就为大家带来一篇浅谈AngularJs指令之scope属性详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
  • AngularJs中route的使用方法和配置

    angular是Google开发的一个单页面应用框架,是现在比较主流的单页面应用框架之一,下面通过本文给大家介绍AngularJs中route的使用方法和配置,感兴趣的朋友一起学习吧...2016-02-09
  • 快速学习AngularJs HTTP响应拦截器

    任何时候,如果我们想要为请求添加全局功能,例如身份认证、错误处理等,在请求发送给服务器之前或服务器返回时对其进行拦截,是比较好的实现手段...2016-01-05
  • Angularjs中如何使用filterFilter函数过滤

    这篇文章主要介绍了Angularjs中如何使用filterFilter函数过滤的相关资料,需要的朋友可以参考下...2016-02-12
  • AngularJS内建服务$location及其功能详解

    这篇文章主要为大家详细介绍了AngularJS内建服务$location及$location功能,感兴趣的小伙伴们可以参考一下...2016-07-06
  • AngularJS使用ngOption实现下拉列表的实例代码

    这篇文章主要介绍了AngularJS使用ngOption实现下拉列表的实例代码的相关资料,需要的朋友可以参考下...2016-01-25
  • Angularjs---项目搭建图文教程

    下面小编就为大家带来一篇Angularjs---项目搭建图文教程。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-07-25
  • AngularJS中的指令实践开发指南(二)

    这篇文章主要介绍了AngularJS中的指令实践指南(二)的相关资料,需要的朋友可以参考下...2016-03-22
  • angularjs循环对象属性实现动态列的思路详解

    这篇文章主要介绍了angularjs循环对象属性实现动态列的思路详解,本文给大家分享一个demo代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-11-02
  • AngularJS 让人爱不释手的八种功能

    AngularJS 让人爱不释手的八种功能,想知道AngularJS哪八种功能让人喜欢就快点看下本文吧...2016-03-28
  • Nginx反向代理proxy_cache_path directive is not allowed错误解决方法

    这篇文章主要介绍了Nginx反向代理proxy_cache_path directive is not allowed错误解决方法,需要的朋友可以参考下...2016-01-27
  • angularJS 指令封装回到顶部示例详解

    本篇文章主要介绍了angularJS 指令封装回到顶部示例详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 ...2017-01-26