Javascript 使用Aurelia动态生成视图中的自定义组件

Javascript 使用Aurelia动态生成视图中的自定义组件,javascript,mvvm,typescript,aurelia,Javascript,Mvvm,Typescript,Aurelia,我目前正在尝试为一款棋盘游戏构建一个web应用程序,并决定在前端使用Aurelia JavaScript框架。我是Aurelia的新手,在尝试单击按钮创建自定义组件的新实例时遇到了麻烦。让我举一个例子来进一步说明我正在努力实现的目标。我尝试实现的游戏的设置如下所示: 我列出了一个简单的例子来进一步解释我遇到的问题。这更像是一个设计问题,源于我对奥雷莉亚不熟悉。在这个简单的示例中,我使用了主app.js viewmodel和app.html视图,Aurelia将其视为主viewmodel和视图。它

我目前正在尝试为一款棋盘游戏构建一个web应用程序,并决定在前端使用Aurelia JavaScript框架。我是Aurelia的新手,在尝试单击按钮创建自定义组件的新实例时遇到了麻烦。让我举一个例子来进一步说明我正在努力实现的目标。我尝试实现的游戏的设置如下所示:

我列出了一个简单的例子来进一步解释我遇到的问题。这更像是一个设计问题,源于我对奥雷莉亚不熟悉。在这个简单的示例中,我使用了主app.js viewmodel和app.html视图,Aurelia将其视为主viewmodel和视图。它们看起来像这样:

app.js

app.html

card.html

目前,通过在app viewmodel的按钮单击事件处理程序中实例化一个新卡对象,我能够在按下app view中的按钮时动态生成新卡。我的问题是,我不认为我应该从app viewmodel手动实例化卡片对象。似乎应该有某种方法告诉Aurelia它需要创建一个新的卡对象,但我不知道该方法是什么。所以我的问题是:有没有更好的方法来动态创建自定义组件,而不需要像我所做的那样手动实例化它们

我之所以认为这似乎不是正确的方法,部分原因是因为在当前的设置中,Card对象的构造函数被调用了两次,而构造函数应该只被调用一次。此外,如果Card类需要依赖注入值,我必须手动将这些值传递到新的Card对象中,我觉得这不对

非常感谢你的帮助


这里有一个指向最小工作repo的链接

我认为这种方法可能在于对compose元素使用model属性。model属性允许您传递视图模型中要使用的值的对象,这些值作为第一个参数在activate方法中可用

所以你可以这样使用它:

因此,卡视图模型保持不变,您移出生成逻辑,并从卡阵列中通过卡对象。这使得事情变得更加清晰和简单,您不会每次都实例化这些重对象

在app.js文件中,您创建了一个新对象,并且调用了构造函数,因为new就是这么做的。一旦compose元素调用它,它就会再次实例化它。您将实例化该对象两次

你要做的不是新卡,而是将一个简单的对象推入你的卡数组。将卡生成逻辑移出一个不会多次实例化的类

编辑 在一些额外的反馈之后,我举出了一个例子,说明了如何将所有这些整合在一起。如您所见,我们已将卡片创建逻辑移动到函数中。我们调用这个函数来生成一个包含两个属性的对象:suit和value。然后我们将其作为数据传递给compose元素,然后在内部使用它

app.js

app.html


您的card.html文件将保持不变。

另一种方法是将card类标记为transient并使用惰性解析器。请原谅我的错误

App.js

Card.js


你应该尽量使你的问题小而集中,这样其他人就可以很容易地理解这个问题,并且可以重复使用他们自己的问题的答案。请花点时间把你的问题简化到尽可能小的程度。好的,我会把它改写得更简单,然后做一个新的最小裸Aurelia项目并发布。我一直在思考应用程序上下文中的所有内容,但这是有道理的,谢谢!看起来像是辉煌:你是对的@miroslavpovic,这将是辉煌的实现:非常感谢你的回答!当我第一次读到它时,它似乎很有道理,但当我去实现它时,我遇到了一些麻烦。我真的不明白我应该在哪里打新卡。您说过要将它移动到一个不会多次实例化的类中,但它当前在app.js中,我认为它只实例化了一次。这不对吗?如果您有时间给我一个例子多一点的代码,我将非常感谢!谢谢不用担心,凯文。昨晚我有点累了,所以我为这个令人困惑的答案道歉,当时这个答案是有道理的。我会更新我的答案,为你提供更多的细节。这将是非常有帮助的,非常感谢@KevinM请看我对以上答案的最新编辑,这是完美的!谢谢你的帮助,我真的很感激。谢谢@JamesCarters的信息!我将研究transient和懒惰解析器。
import { Card } from './card';

export class App {
    cards = [];

    newCard() {
        this.cards.push(new Card());
    }
}
<template>
    <require from="./card"></require>

    <button click.delegate="newCard()">New Card</button>

    <div>
        <li repeat.for="card of cards">
            <compose view-model="card"></compose>
        </li>
    </div>
</template>
export class Card {
    cardValues = ['2','3','4','5','6','7','8','9','10',
        'J','Q','K','A'];
    cardSuits = ['Diamonds', 'Clubs', 'Hearts', 'Spades'];

    value;
    suit;

    activate() {
        this.value = this.pickRandomItem(this.cardValues);
        this.suit = this.pickRandomItem(this.cardSuits);
    }

    pickRandomItem(data) {
        let index = Math.floor(Math.random() * (data.length -1));
        return data[index];
    }
}
<template>
    <div style="border: 2px solid black;
                display: inline-block;
                margin-top: 10px;">
        <h3>Value: ${value}</h3>
        <h4>Suit: ${suit}</h4>
    </div>
</template>
export class App {
    cards = [];

    newCard() {
        this.cards.push(generateCard());
    }
}

function generateCard() {
    let cardValues = ['2','3','4','5','6','7','8','9','10',
        'J','Q','K','A'];

    let cardSuits = ['Diamonds', 'Clubs', 'Hearts', 'Spades'];

    function pickRandomItem(arr) {
        let index = Math.floor(Math.random() * (arr.length -1));
        return arr[index];
    }

    return {
        suit: pickRandomItem(cardSuits),
        value: pickRandomItem(cardValues)
    };
}
<template>
    <button click.delegate="newCard()">New Card</button>

    <div>
        <li repeat.for="cardObj of cards">
            <!-- cardObj will be our object {suit: 'suit', value: 'value'} -->
            <compose view-model="card" model.bind="cardObj"></compose>
        </li>
    </div>
</template>
export class Card {
    suit;
    value;

    activate(model) {
        if (model) {
            this.suit = model.suit;
            this.value = model.value;
        }
    }
}
import { Card } from './card';
import {Lazy,inject} from 'aurelia-framework';

@inject(Lazy.of(Card))
export class App {
    constructor(cardFactory){
        this.cardFactory = cardFactory;
    }
    cards = [];

    newCard() {
        this.cards.push(this.cardFactory());
   }
}
import {transient} from 'aurelia-framework';
@transient()
export class Card {
    //do stuff
}