Javascript 如何保持相互依赖的knockout.js同步可见
我有3个相互关联的敲除观测值。是的 零售价、售价、折扣 当用户更改一个值时,其他观察值将更新。 比如说,Javascript 如何保持相互依赖的knockout.js同步可见,javascript,knockout.js,Javascript,Knockout.js,我有3个相互关联的敲除观测值。是的 零售价、售价、折扣 当用户更改一个值时,其他观察值将更新。 比如说, 如果用户将售价输入为1000,则零售价设置为1000,折扣设置为0 按照上面的示例,现在如果用户将零售价格编辑为2000,折扣将更新为50 现在,如果我没有afterkeydown事件,所有这些工作都很好。因此,当用户输入任何值并移动到下一个框时,就可以了 问题是,当我保持afterkeydown时,只要我开始键入,就会根据第一个字符计算其他值。现在,当我输入第二个整数时,值被弄乱了 比
- 如果用户将售价输入为1000,则零售价设置为1000,折扣设置为0李>
- 按照上面的示例,现在如果用户将零售价格编辑为2000,折扣将更新为50
- 从零售开始:销售设置为零售,折扣=0
- 从销售开始:零售设置为销售,折扣=0
- 从折扣开始。下一步可以添加零售或销售
零售价:
售价:
折扣:
Javascript:
函数hasOwnProperty(对象、属性){
var proto=obj.uu proto_u124; | obj.constructor.prototype;
返回(对象中的道具)&(!(对象中的道具)| |对象[道具]!==对象[道具];
}
函数轮号(值、精度、flt){
var精度=精度| | 0,
负=值<0,
功率=数学功率(10,精度),
数值=数学四舍五入(数值*幂),
整数=字符串((neg?Math.ceil:Math.floor)(值/幂)),
分数=字符串((负?-value:value)%power),
padding=新数组(Math.max(precision-fraction.length,0)+1);
如果(flt==真){
积分=浮点(积分);
}
返回精度?整数+'。+填充+分数:整数;
}
var util={};
util.format=函数(值,前缀){
var pr=前缀| |'';
toks=轮号(值,2)。替换('-','')。拆分('.');
var display=pr+$.map(toks[0]。拆分(“”).reverse(),函数(elm,i){
返回[(i%3===0&&i>0?',':'',elm];
}).reverse().join(“”)+.+toks[1];
返回值<0?'-'+显示:显示;
};
ko.subscribable.fn.formatted=函数(选项){
var目标=此;
var_options=(options==未定义)?{}:选项;
var _prefix=hasOwnProperty(_options,'prefix')?_options.prefix:“”;
var _precision=hasOwnProperty(_options,'precision')?_options.precision:2;
var_type=hasOwnProperty(_options,'type')?_options.type:2;
变量格式=函数(值){
开关(U型){
案例1:
return util.format(roundNumber(值,_精度),_前缀);//带符号的货币
案例2:
返回roundNumber(值,_精度);//reg float
违约:
抛出新错误(“非法类型”);
}
};
var聚焦=可观察(假);
var writeTarget=函数(值){
var=价值;
如果(isNaN(值)){
stripped=字符串(值)。替换(/[^0-9.-]/g');
}
//目标(浮动(剥离));
值=浮动(剥离);
聚焦()?目标(!isFinite(value)?0:value):目标(!isFinite(value)?0:roundNumber(value,_precision));//写入底层存储
};
var结果=ko.computed({
读:函数(){
返回目标();
},
write:writeTarget
});
result.formatted=ko.computed({
读:函数(){
if(focused()){
return(isNaN(target())?“”:target());//写入底层存储
}
返回格式(target());
},
write:writeTarget
});
result.isNegative=ko.computed(函数(){
返回目标()<0;
});
result.isFocused=ko.computed({
读:函数(){
返回聚焦();
},
写入:函数(值){
专注(价值);
}
});
返回结果;
};
var ViewModel=函数(){
var self=这个;
self.retail_price=ko.可观察(0).扩展({
油门:100
}).格式化({
类型:1
});
自售价格=ko.可观察(0).扩展({
油门:100
}).格式化({
类型:1
});
自贴现=可观测的ko(0);
//只要零售价格发生变化,就改变珠宝的销售价格
self.retail\u price.subscribe(函数(){
if(parseFloat(self.salling_price())!==0){
self.updateDiscovery();
返回;
}
if(self.retail\u price.isFocused()){
self.changeSellingPrice();
}
});
//只要折扣改变,就改变售价
self.discount.subscribe(函数(){
self.changeSellingPrice();
});
自售价格订阅(功能五){
if(self.self\u price.isFocused()){
if(parseFloat(self.retail_price())!==0){
self.updateDiscovery();
返回;
}
var-retPrice=(v*100)/(100-self.discount());
自零售价(伊斯南(retPrice)?0:整数(retPrice,2));
}
});
self.updateDiscovery=函数(){
var retPr=parseFloat(self.retail_price());
弗吉尼亚州
<code>
<div>retail_price:
<input type="text" data-bind="value: retail_price.formatted, hasfocus: retail_price.isFocused, valueUpdate: 'afterkeydown'" />
</div>
<div>selling_price:
<input type="text" data-bind="value: selling_price.formatted, hasfocus: selling_price.isFocused, valueUpdate: 'afterkeydown'" />
</div>
<div>discount:
<input type="text" data-bind="value: discount, hasfocus: discount.isFocused, valueUpdate: 'afterkeydown'" />
</div>
</code>
function hasOwnProperty(obj, prop) {
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in obj) && (!(prop in proto) || proto[prop] !== obj[prop]);
}
function roundNumber(value, precision, flt) {
var precision = precision || 0,
neg = value < 0,
power = Math.pow(10, precision),
value = Math.round(value * power),
integral = String((neg ? Math.ceil : Math.floor)(value / power)),
fraction = String((neg ? -value : value) % power),
padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
if (flt === true) {
integral = parseFloat(integral);
}
return precision ? integral + '.' + padding + fraction : integral;
}
var util = {};
util.format = function (value, prefix) {
var pr = prefix || '';
toks = roundNumber(value, 2).replace('-', '').split('.');
var display = pr + $.map(toks[0].split('').reverse(), function (elm, i) {
return [(i % 3 === 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];
return value < 0 ? '-' + display : display;
};
ko.subscribable.fn.formatted = function (options) {
var target = this;
var _options = (options === undefined) ? {} : options;
var _prefix = hasOwnProperty(_options, 'prefix') ? _options.prefix : '';
var _precision = hasOwnProperty(_options, 'precision') ? _options.precision : 2;
var _type = hasOwnProperty(_options, 'type') ? _options.type : 2;
var format = function (value) {
switch (_type) {
case 1:
return util.format(roundNumber(value, _precision), _prefix); //currency w/ symbol
case 2:
return roundNumber(value, _precision); //reg float
default:
throw new Error('illegal type');
}
};
var focused = ko.observable(false);
var writeTarget = function (value) {
var stripped = value;
if (isNaN(value)) {
stripped = String(value).replace(/[^0-9.-]/g, '');
}
//target(parseFloat(stripped));
value = parseFloat(stripped);
focused() ? target(!isFinite(value) ? 0 : value) : target(!isFinite(value) ? 0 : roundNumber(value, _precision)); // Write to underlying storage
};
var result = ko.computed({
read: function () {
return target();
},
write: writeTarget
});
result.formatted = ko.computed({
read: function () {
if (focused()) {
return (isNaN(target()) ? '' : target()); // Write to underlying storage
}
return format(target());
},
write: writeTarget
});
result.isNegative = ko.computed(function () {
return target() < 0;
});
result.isFocused = ko.computed({
read: function () {
return focused();
},
write: function (value) {
focused(value);
}
});
return result;
};
var ViewModel = function () {
var self = this;
self.retail_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.selling_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.discount = ko.observable(0);
// Whenever the retail price changes, change the selling price for jewelry
self.retail_price.subscribe(function () {
if (parseFloat(self.selling_price()) !== 0) {
self.updateDiscount();
return;
}
if (self.retail_price.isFocused()) {
self.changeSellingPrice();
}
});
// Whenever the discount changes, change the selling price
self.discount.subscribe(function () {
self.changeSellingPrice();
});
self.selling_price.subscribe(function (v) {
if (self.selling_price.isFocused()) {
if (parseFloat(self.retail_price()) !== 0) {
self.updateDiscount();
return;
}
var retPrice = (v * 100) / (100 - self.discount());
self.retail_price(isNaN(retPrice) ? 0 : roundNumber(retPrice, 2));
}
});
self.updateDiscount = function () {
var retPr = parseFloat(self.retail_price());
var askPr = parseFloat(self.selling_price());
var discount = 100 * (retPr - askPr) / retPr;
self.discount(!isFinite(discount) ? 0 : roundNumber(discount, 2));
};
self.changeSellingPrice = function () {
var sellingPrice = self.retail_price() - (self.retail_price() * self.discount()) / 100;
self.selling_price(isNaN(sellingPrice) ? 0 : roundNumber(sellingPrice, 2));
};
};
ko.applyBindings(new ViewModel());
var discount = ko.computed(function() {
var discount;
// your calculation goes here
// discount = retail_price() - selling_price() …
return discount > 0 ? discount : 0;
});
<div>retail_price:
<input type="text" data-bind="value: retail_price.formatted, hasfocus: retail_price.isFocused" />
</div>
<div>selling_price:
<input type="text" data-bind="value: selling_price.formatted, hasfocus: selling_price.isFocused" />
</div>
<div>discount:
<input type="text" data-bind="value: discount, hasfocus: discount.isFocused" />
</div>
function hasOwnProperty(obj, prop) {
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in obj) && (!(prop in proto) || proto[prop] !== obj[prop]);
}
function roundNumber(value, precision, flt) {
var precision = precision || 0,
neg = value < 0,
power = Math.pow(10, precision),
value = Math.round(value * power),
integral = String((neg ? Math.ceil : Math.floor)(value / power)),
fraction = String((neg ? -value : value) % power),
padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');
if (flt === true) {
integral = parseFloat(integral);
}
return precision ? integral + '.' + padding + fraction : integral;
}
var util = {};
util.format = function (value, prefix) {
var pr = prefix || '';
toks = roundNumber(value, 2).replace('-', '').split('.');
var display = pr + $.map(toks[0].split('').reverse(), function (elm, i) {
return [(i % 3 === 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];
return value < 0 ? '-' + display : display;
};
ko.subscribable.fn.formatted = function (options) {
var target = this;
var _options = (options === undefined) ? {} : options;
var _prefix = hasOwnProperty(_options, 'prefix') ? _options.prefix : '';
var _precision = hasOwnProperty(_options, 'precision') ? _options.precision : 2;
var _type = hasOwnProperty(_options, 'type') ? _options.type : 2;
var format = function (value) {
switch (_type) {
case 1:
return util.format(roundNumber(value, _precision), _prefix); //currency w/ symbol
case 2:
return roundNumber(value, _precision); //reg float
default:
throw new Error('illegal type');
}
};
var focused = ko.observable(false);
var writeTarget = function (value) {
var stripped = value;
if (isNaN(value)) {
stripped = String(value).replace(/[^0-9.-]/g, '');
}
//target(parseFloat(stripped));
value = parseFloat(stripped);
focused() ? target(!isFinite(value) ? 0 : value) : target(!isFinite(value) ? 0 : roundNumber(value, _precision)); // Write to underlying storage
};
var result = ko.computed({
read: function () {
return target();
},
write: writeTarget
});
result.formatted = ko.computed({
read: function () {
if (focused()) {
return (isNaN(target()) ? '' : target()); // Write to underlying storage
}
return format(target());
},
write: writeTarget
});
result.isNegative = ko.computed(function () {
return target() < 0;
});
result.isFocused = ko.computed({
read: function () {
return focused();
},
write: function (value) {
focused(value);
}
});
return result;
};
var ViewModel = function () {
var self = this;
self.retail_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.selling_price = ko.observable(0).extend({
throttle: 100
}).formatted({
type: 1
});
self.discount = ko.observable(0);
// Whenever the retail price changes, change the selling price for jewelry
self.retail_price.subscribe(function () {
if (parseFloat(self.selling_price()) !== 0) {
self.updateDiscount();
return;
}
if (self.retail_price.isFocused()) {
self.changeSellingPrice();
}
});
// Whenever the discount changes, change the selling price
self.discount.subscribe(function () {
self.changeSellingPrice();
});
self.selling_price.subscribe(function (v) {
var retPrice = (v * 100) / (100 - self.discount());
self.retail_price(isNaN(retPrice) ? 0 : roundNumber(retPrice, 2));
if (parseFloat(self.retail_price()) !== 0) {
self.updateDiscount();
}
});
self.updateDiscount = function () {
var retPr = parseFloat(self.retail_price());
var askPr = parseFloat(self.selling_price());
var discount = 100 * (retPr - askPr) / retPr;
self.discount(!isFinite(discount) ? 0 : roundNumber(discount, 2));
};
self.changeSellingPrice = function () {
var sellingPrice = self.retail_price() - (self.retail_price() * self.discount()) / 100;
self.selling_price(isNaN(sellingPrice) ? 0 : roundNumber(sellingPrice, 2));
};
};
ko.applyBindings(new ViewModel());