AngularJS 1.5.8中scope.$eval未执行,自定义按键指令问题排查
嘿,我来帮你排查这个问题!你遇到的情况是指令内部的调试弹窗能正常弹出,但通过$eval执行的目标弹窗没出来,大概率是$eval的作用域上下文、表达式绑定或者事件触发环节出了问题,咱们一步步来捋:
先确认事件回调是否真的执行到了$eval那一步
先在指令的按键事件回调里,$eval代码前加个console.log('按键事件触发了'),看看按键时控制台有没有输出。如果连这个都没输出,那问题出在事件绑定上——检查是不是用了正确的事件名(比如keypress/keydown/keyup有没有写错),或者元素是不是正确绑定了事件(比如是不是动态生成的元素?如果是,可能需要用事件委托)。检查$eval的作用域上下文是否正确
如果你给指令用了隔离作用域(比如scope: {}),那直接调用scope.$eval(attrs.xxx)会在隔离作用域里执行表达式,而你在指令目标上写的表达式大概率是在父作用域里定义的。这时候别用$eval,改用$parse服务来解析并绑定父作用域执行:angular.module('yourModule').directive('myKeypress', function($parse) { return { link: function(scope, element, attrs) { // 先解析表达式,拿到可执行的函数 var keyPressFn = $parse(attrs.myKeypress); element.on('keypress', function(event) { // 在父作用域执行表达式,还能传$event参数给外部 keyPressFn(scope, { $event: event }); // 指令内部的调试弹窗 alert('指令内部弹窗'); }); } }; });试试用$apply包裹$eval(如果事件在Angular上下文外触发)
虽然Angular 1.5的element.on会自动触发digest循环,但偶尔如果事件是在Angular之外的环境触发的(比如第三方插件的事件),可能需要手动调用$apply来让表达式生效:element.on('keypress', function(event) { alert('指令内部弹窗'); scope.$apply(function() { scope.$eval(attrs.myKeypress); }); });排查表达式本身的写法问题
检查你在指令目标上写的表达式是不是正确——比如是不是漏了括号(比如应该写showAlert()而不是showAlert),或者表达式里的变量/函数在当前作用域不存在。可以先在指令里打印console.log(attrs.myKeypress),确认表达式内容和你预期的一致,然后在控制台手动调用scope.$eval('你的表达式'),看能不能触发弹窗。如果是隔离作用域,也可以通过绑定表达式的方式传递
给指令的隔离作用域定义一个表达式绑定:angular.module('yourModule').directive('myKeypress', function() { return { scope: { myKeypress: '&' // 用&绑定表达式 }, link: function(scope, element) { element.on('keypress', function() { alert('指令内部弹窗'); scope.myKeypress(); // 直接调用绑定的表达式 }); } }; });然后在DOM里这样用:
<input my-keypress="showAlert()">
按上面的步骤排查,应该能解决你遇到的$eval弹窗不出现的问题~
内容的提问来源于stack exchange,提问作者Frank Adrian

