Javascript 动态Healthbars-动态观察值和依赖项

Javascript 动态Healthbars-动态观察值和依赖项,javascript,json,knockout.js,Javascript,Json,Knockout.js,这个问题会有点具体,所以请随意用更宽泛的术语回答,或者为我指出正确的方向 几天前我学习了Knockout.js,因为它解决了我之前在应用程序中遇到的一个问题,尽管如此,对于一个库来说如此之新往往会产生更多的问题 我正在尝试为GM(游戏大师)应用程序制作一个简单的PC(可玩角色)管理器。我从一个json对象数组(稍后从db)加载所有PC信息,并将它们放在一个引导选项卡面板中,以便于维护 我想创建的第一件事是为每个玩家创建一个健康栏,旁边有一个用于增加和减少hp的控件,以及一个X/Y简单文本视图。这

这个问题会有点具体,所以请随意用更宽泛的术语回答,或者为我指出正确的方向

几天前我学习了Knockout.js,因为它解决了我之前在应用程序中遇到的一个问题,尽管如此,对于一个库来说如此之新往往会产生更多的问题

我正在尝试为GM(游戏大师)应用程序制作一个简单的PC(可玩角色)管理器。我从一个json对象数组(稍后从db)加载所有PC信息,并将它们放在一个引导选项卡面板中,以便于维护

我想创建的第一件事是为每个玩家创建一个健康栏,旁边有一个用于增加和减少hp的控件,以及一个X/Y简单文本视图。这些组件中的每一个都应该独立于其他玩家的组件,并且都应该在提交的输入框中的值时动态更新

我遇到的问题是从淘汰的角度考虑,而不是从简单的javascript角度考虑。我稍后会解释

这是我的密码:

~JSON数组,包含数据:

    var initialData = [
    {
        id: 0,
        pcName: "Player 1",
        hp: 12,
        curHp: 12,
        name: "Dudebro One",
        playerClass: "Ranger",
        level: 1,
        background: "",
        race: "Elf - Wood",
        Alignment: "",
        exp: 700,
        inspiration: 0,
        proficiencyBonus: 0
    },
    {
        id: 1,
        pcName: "Player 2",
        hp: 10,
        curHp: 10,
        name: "Brodude Two",
        playerClass: "Fighter",
        level: 1,
        background: "Soldier",
        race: "Gnome",
        Alignment: "",
        exp: 700,
        inspiration: 0,
        proficiencyBonus: 0
    }
];
(注意:出于可读性目的,数据不完整。同时假设
n
玩家数量,而不是2名)

~淘汰码(远未完成):

上述所有代码都会产生以下效果:

(不要担心ulgy按钮,它只是用于测试的)。理想情况下,最终用户将能够单击红色的减号按钮,并在该按钮和绿色的加号之间切换,以识别健康池中的加号或减号。单击Go按钮应该可以更新所有内容

虽然我最终可能会拼凑出一些有用的东西,但我想在此过程中学习一些好的实践


谢谢你通读了我的小说中的一个问题,如果你愿意放弃一个答案,那就更谢谢你了

如果要实现的行为与每个玩家相关,则应将逻辑放入
playervewmodel
中,并为每个玩家创建一个模型。可以在另一个viewmodel中跟踪模型集合。让我们称之为
App

应用程序中
,我们只做一件事:

  • 获取json数组并为其中的每个对象创建一个新的
    PlayerViewModel
  • 当我们创建一个
    新播放器
    时,我们会做几件事:

  • 首先,我们将所有静态json属性复制到新的player实例。您可以手动执行此操作,就像您在代码中已经执行的操作一样,也可以自动执行此操作,就像我对
    对象.assign所做的操作一样

  • 然后,我们重写一些属性以使用
    ko.observable
    s。您希望能够在UI中更改的每个属性都必须是可观察的。所以,如果你想改变一个名字,你也必须把它作为一个可观察的东西添加进去

  • 现在我们也可以添加我们自己的可观察值和计算值。例如:如果玩家可以更改
    curHp
    ,我们可以自动计算HP百分比

  • 最后,每个
    Player
    通过
    Player.prototype
    获得一组函数。例如:有一个函数在
    输入
    字段中获取值,并将其添加到
    curHp

  • 现在,由于所有信息和逻辑都在
    Player
    模型中,因此您可以轻松地绑定数据,而无需将引用传递给Player,也无需使用
    $parent
    $root

    var Player=函数(playerData){
    //将所有属性复制到新玩家
    //这些是静态特性,适用于单向
    //数据绑定。
    分配(这个,playerData);
    //为双向属性创建可观察对象
    //(要通过UI更改的属性)
    this.curHp=ko.observable(playerData.curHp);
    该值=可观测的ko(0);
    //为UI创建计算值
    this.hpPercentage=ko.pureComputed(函数(){
    返回(this.curHp()/playerData.hp*100).toFixed(1);
    },这个);
    this.healthWarning=ko.pureComputed(函数(){
    var hpPerc=this.hpPercentage();
    如果(hpPerc==0)返回“死”;
    如果(hpPerc<30)返回“小心”;
    如果(hpPerc<70)返回“稳定”;
    返回“OK”;
    },这个);
    };
    //添加函数
    Player.prototype.addHp=函数(){
    var val=parseFloat(this.subtractValue());
    var newHP=Math.min(
    max(this.curHp()+val,0),this.hp);
    这个.curHp(newHP);
    };
    //辅助构造函数
    Player.create=函数(playerJson){
    返回新玩家(playerJson);
    };
    var App=函数(jsonData){
    this.players=jsonData.map(Player.create);
    };
    var initialData=[{id:0,pcName:“玩家1”,hp:12,curHp:4,姓名:“都德兄弟一号”,玩家等级:“游侠”,等级:1,背景:,“种族:”精灵木“,阵型:,,“经验:700,灵感:0,熟练程度奖励:0},{id:1,pcName:“玩家2”,hp:10,curHp:7,姓名:“都德兄弟二号”,玩家等级:“战士”,等级:1,背景:“士兵”,种族:“侏儒”,阵型:“,经验:700,灵感:0,熟练度奖金:0}];
    ko.应用绑定(新应用(初始数据))
    
    
    球员
    
    • 更新HP

    我会给你一个被接受的答案,因为这确实符合我的要求,但我找到了一个不同的解决方案。最后,我决定做的是,当手动复制json属性时,我根据
    pc.curhp
    pc.hp
    这样做:
    obCurHp:ko.observable(pc.curhp)
    。然后,我只做了一些函数,使用所说的观察值计算百分比和进度条宽度(引导)。这样,如果观察值发生变化,依赖关系也会发生变化,因此所有内容都会得到更新。谢谢你的建议!我觉得这就是我想解释的。例如,在我的代码示例中,我写道:
    this.cu
    
    var PCModel = function (pcs) {
        var self = this;
    
        var currentHp = ko.observable(10);
        var maximumHp = ko.observable(10);
    
        self.pcsList = ko.observableArray(ko.utils.arrayMap(pcs, function (pc) {
            return {
                id: pc.id, pcName: pc.pcName, hp: pc.hp, curHp: pc.curHp, name: pc.name, playerClass: pc.playerClass, level: pc.level, background: pc.background, race: pc.race, Alignment: pc.Alignment, exp: pc.exp,
                inspiration: pc.inspiration, proficiencyBonus: pc.proficiencyBonus
            };
        }));
    
        //TODO: REMOVE (Note: Here just for testing).
        self.myFunction= function(pc){
            currentHp--;
        };
    
        self.getHpPercentage = function (pc) {
            var hpRound = Math.round((pc.curHp / pc.hp) * 100);
            return hpRound + "%"
        }
    
        self.hpClass = function (pc) {
            var hp = currentHp() / maximumHp() * 100;
            if (hp >= 70) {
                return 'progress-bar-success';
            } else if (hp < 70 && hp >= 30) {
                return 'progress-bar-warning';
            } else if (hp < 30) {
                return 'progress-bar-danger';
            }
        };
    };
    ko.applyBindings(new PCModel(initialData));
    
    <div style="float:right; margin-top:25px; width: 65vw;">
    <div class="container">
        <ul class="nav nav-tabs" id="sortable" data-bind="foreach: pcsList">
    
            <li data-bind="css: {active: $index() == 0 }" >
                <a data-bind="attr: {href: '#tab' + id}, text: pcName" data-toggle="tab"></a>
            </li>
        </ul>
        <div class="container-border-cup">
            <div class="tab-content " data-bind="foreach: pcsList">
    
                <div class="tab-pane tabbed-content-style" data-bind="attr: {id: 'tab' + id}, css: {active: $index() == 0 }">
                    <h3 data-bind="text: name"></h3>
    
                    <div style="float:left; font-size:15pt; font-weight:500; line-height:35px; padding-right:20px; min-width:100px;">
                        <span data-bind="text: curHp"></span>/<span data-bind="text: hp"></span>
                    </div>
    
                    <button data-bind="click: $root.myFunction">
                        Click me
                    </button>
    
                    <div class="progress" style="width: 50%; height: 35px; float:left">
                        <div class="progress-bar" style="float:left;" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" data-bind="text: $root.getHpPercentage($data), attr:{class: 'progress-bar ' + $root.hpClass($data)}, style:{width: $root.getHpPercentage($data)}"></div>
                    </div>
    
    
                    <div class="input-group" style="padding-left:20px">
                        <span class="input-group-btn">
                            <input type="button" class="btn btn-danger" id="btnToggleHP" value="-" style="width: 35px; font-weight:900;" />
                        </span>
                        <input id="inModHP" style="width:70px" type="text" class="form-control" value="0">
                        <span class="input-group-btn" style="float:left">
                            <input type="button" class="btn btn-default" id="btnGoHP" value="Go" />
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
    </div>