AngularJS指令开发:如何用controllerAs vm替代$scope(遵循John Papa风格)
解决AngularJS指令中使用controllerAs vm语法的属性绑定问题
你遇到的问题根源在于:当你使用unordered-list="vm.products"时,scope[attrs["unorderedList"]]尝试直接访问scope["vm.products"]这个属性,但实际上vm是当前作用域上的一个对象,products是vm的属性,这种直接通过属性名索引的方式无法解析嵌套的属性路径。
下面给你两种可行的解决方案:
方案1:使用$parse服务解析表达式
AngularJS的$parse服务可以帮你把字符串形式的表达式(比如vm.products)解析成可执行的函数,从而正确获取对应的值。修改你的指令代码如下:
angular.module("myApp") .directive("unorderedList", function ($parse) { // 注入$parse服务 return { link: function (scope, element, attrs) { // 解析unordered-list属性的表达式 var dataGetter = $parse(attrs.unorderedList); // 在当前作用域上执行表达式,获取数据 scope.data = dataGetter(scope); // 可选:如果需要监听数据变化,添加$watch实现响应式更新 scope.$watch(attrs.unorderedList, function(newVal) { scope.data = newVal; }); }, restrict: "A", template: "<ul><li ng-repeat='item in data'>{{item.price | currency}}</li></ul>", replace: true }; });
修改后,unordered-list="vm.products"就能正常工作了——$parse会正确解析vm.products这个嵌套路径,从scope上的vm对象中取出products数组。
方案2:使用隔离作用域的双向绑定
另一种更简洁的方式是给指令定义隔离作用域,通过=绑定自动处理属性表达式,这种方式更符合AngularJS指令的最佳实践:
angular.module("myApp") .directive("unorderedList", function () { return { scope: { // 用data属性绑定unordered-list的值,自动处理表达式解析 data: "=unorderedList" }, restrict: "A", template: "<ul><li ng-repeat='item in data'>{{item.price | currency}}</li></ul>", replace: true }; });
这种方式下,AngularJS会自动帮你解析vm.products表达式,把对应的数据传递到指令的隔离作用域中,无需手动处理解析逻辑,代码更简洁易维护。
额外优化:利用list-property实现动态显示
你还定义了list-property="price | currency"属性,但当前模板硬编码了item.price | currency,可以让指令支持动态显示指定内容,提升复用性:
修改后的指令(结合隔离作用域方案):
angular.module("myApp") .directive("unorderedList", function ($interpolate) { return { scope: { data: "=unorderedList", listProperty: "@" // 用@绑定字符串形式的属性表达式 }, restrict: "A", link: function(scope) { // 解析list-property的表达式 var interpolateFn = $interpolate("{{item." + scope.listProperty + "}}"); scope.getItemDisplay = function(item) { return interpolateFn({item: item}); }; }, template: "<ul><li ng-repeat='item in data'>{{getItemDisplay(item)}}</li></ul>", replace: true }; });
现在你可以通过list-property动态指定显示内容,比如:
<div unordered-list="vm.products" list-property="price | currency"></div> <div unordered-list="vm.products" list-property="name"></div>
内容的提问来源于stack exchange,提问作者Bryan Dellinger
相关产品推荐
相关产品推荐

