NativeScript中{{ !isBusy }}绑定isEnabled属性失效问题排查
解决NativeScript 5.x中Mustache取反绑定isEnabled失效的问题
我之前在NativeScript升级到5.0后也碰到过一模一样的问题,原因是NativeScript 5.0开始对数据绑定的表达式语法做了限制,原来直接在Mustache模板里使用!逻辑取反的写法({{ !isBusy }})不再被支持了。这就导致你的按钮isEnabled属性实际上一直是默认的true状态,自然:disabled样式不会生效,而ActivityIndicator的绑定因为是直接使用布尔值,所以不受影响。
下面给你两种可行的解决方案:
方案1:在ViewModel中添加计算属性
最直接的方式是在你的pageData对象里添加一个计算属性,专门返回!isBusy的结果,这样XML里直接绑定这个属性即可:
修改后的JS代码
const observable = require("tns-core-modules/data/observable"); const ObservableArray = require("tns-core-modules/data/observable-array").ObservableArray; var someArray = new ObservableArray([]); var pageData = observable.fromObject({ listItems: someArray, isBusy: false, // 初始化isBusy为false,避免初始状态不确定 // 计算属性,返回isBusy的取反值 get enabled() { return !this.get("isBusy"); } }); exports.onLoad = function (args) { const page = args.object; page.bindingContext = pageData; doSomething(); } function doSomething () { pageData.set("isBusy", true); // 模拟耗时操作(替换成你实际的异步逻辑) setTimeout(() => { pageData.set("isBusy", false); }, 2000); }
修改后的XML代码
<Page loaded="onLoad"> <StackLayout> <Button class="btn" isEnabled="{{ enabled }}"/> <ActivityIndicator busy="{{ isBusy }}"/> </StackLayout> </Page>
方案2:使用绑定转换器
如果你希望在XML里直接处理布尔值的取反,可以创建一个绑定转换器,这样在多个地方需要取反绑定时都能复用:
定义并注册转换器(JS代码)
const observable = require("tns-core-modules/data/observable"); const ObservableArray = require("tns-core-modules/data/observable-array").ObservableArray; const binding = require("tns-core-modules/ui/binding"); // 定义取反转换器 const negateConverter = { toView: function(value) { return !value; } }; // 注册转换器,方便XML中使用 binding.registerConverter("negate", negateConverter); var someArray = new ObservableArray([]); var pageData = observable.fromObject({ listItems: someArray, isBusy: false // 初始化isBusy }); exports.onLoad = function (args) { const page = args.object; page.bindingContext = pageData; doSomething(); } function doSomething () { pageData.set("isBusy", true); setTimeout(() => { pageData.set("isBusy", false); }, 2000); }
修改后的XML代码
<Page loaded="onLoad"> <StackLayout> <Button class="btn" isEnabled="{{ isBusy | negate }}"/> <ActivityIndicator busy="{{ isBusy }}"/> </StackLayout> </Page>
额外提示
你原来的doSomething函数里直接连续设置isBusy为true和false,这样耗时操作还没执行就结束了,按钮的disabled状态可能根本看不出来。我在例子里用setTimeout模拟了异步耗时逻辑,你实际开发中要替换成真实的API请求、文件处理等异步操作。
内容的提问来源于stack exchange,提问作者phschimm
相关产品推荐
相关产品推荐

