【问题标题】:Knockout Audio Playlist淘汰赛音频播放列表
【发布时间】:2014-05-05 08:52:33
【问题描述】:

我正在创建一个基于音乐的应用程序,它使用 Knockout 进行绑定。应用程序中列出的所有曲目都是从 Soundcloud 外部提取的,如下所示:

$.getJSON('http://api.soundcloud.com/users/guy-j/tracks.json?client_id=c4bc3b1a93902abecbaca3fa4582d970', {limit: 200}, function(data) {
            vm.tracks($.map(data, function (track) {
                return {
                    artwork: track.artwork_url,
                    avatar: track.user.avatar_url,
                    date: track.created_at,
                    description: track.description,
                    duration: track.duration,
                    listens: track.playback_count,
                    permalink: track.permalink_url,
                    purhcase: track.purchase_url,
                    stream: track.stream_url,
                    track: track.title
                };
            }));
        });

这些轨道(一旦获取)被推送到一个空白的 observableArray 中,然后 HTML 视图被绑定到该数组并生成一个轨道列表。我有这样的音频播放/暂停:

要选择/播放曲目,从 observableArray 生成的每个 <li> 都有一个名为“goToTrack”的点击处理程序,然后它将一个名为“self.chosenTrackData”的可观察对象传递给选定的曲目,然后我的音频元素与“ selectedTrackData' 播放所选曲目。

我现在的问题在于,我不太确定使用 Knockout 处理下一个/上一个曲目功能的最佳方法是什么。我必须知道如何区分 observableArray 中的当前点,然后是 ++ 或 -- 取决于您选择的选项?

任何帮助将不胜感激,因为我仍在学习 Knockout!

【问题讨论】:

    标签: javascript jquery knockout.js knockout-2.0


    【解决方案1】:

    我建议保留一个内部“当前曲目”编号,您可以递增或递减该编号并以此为基础进行计算。

    function PlayerViewModel() {
        var self = this,
            currentTrackNo = ko.observable(0);
    
        // data
        self.tracks = ko.observableArray();
    
        // computeds
        self.currentTrack = ko.computed(function () {
            return self.tracks()[currentTrackNo()];
        });
        self.hasTrack = function (track) {
            return !!self.currentTrack();
        };
        self.hasNextTrack = ko.computed(function () {
            return currentTrackNo() < self.tracks().length - 1;
        });
        self.hasPrevTrack = ko.computed(function () {
            return currentTrackNo() > 0;
        });
    
        // API
        self.setNextTrack = function () {
            if (self.hasNextTrack()) {
                currentTrackNo(currentTrackNo() + 1);
            }
        };
        self.setPrevTrack = function () {
            if (self.hasPrevTrack()) {
                currentTrackNo(currentTrackNo() - 1);
            }
        };
        self.setTrack = function (track) {
            var trackNo = ko.utils.arrayIndexOf(self.tracks(), track);
            currentTrackNo(trackNo);
        };
    
        // init
        $.getJSON('...', {limit: 200}); etc;
    }
    

    将您的“当前曲目”视图组件绑定到currentTrack observable。确保以某种方式使用hasTrack(因为currentTrack 可能未定义)。


    替代实现,避免维护单独的轨道号:

    function PlayerViewModel() {
        var self = this;
    
        // data
        self.tracks = ko.observableArray();
        self.currentTrack = ko.observable();
    
        // computeds
        self.currentTrackNo = ko.computed(function () {
            var currentTrack = self.currentTrack();
            return ko.utils.arrayIndexOf(self.tracks(), currentTrack);
        });
        self.hasTrack = function (track) {
            return !!self.currentTrack();
        };
        self.hasNextTrack = ko.computed(function () {
            return self.currentTrackNo() < self.tracks().length - 1;
        });
        self.hasPrevTrack = ko.computed(function () {
            return self.currentTrackNo() > 0;
        });
    
        // API
        self.setNextTrack = function () {
            if (self.hasNextTrack()) {
                self.currentTrack(self.tracks()[self.currentTrackNo() + 1]);
            }
        };
        self.setPrevTrack = function () {
            if (self.hasPrevTrack()) {
                self.currentTrack(self.tracks()[self.currentTrackNo() - 1]);
            }
        };
        self.setTrack = function (track) {
            // make sure that track is actually in self.tracks here
            self.currentTrack(track);
        };
    
        // init
        $.getJSON('...', {limit: 200}); etc;
    }
    

    【讨论】:

    • @leaksterrr 另一种方法是不使用索引,而是在 setNextTrack()/setPrevTrack 方法中直接使用 currentTrack 可观察并使用 ko.utils.arrayIndexOf()。也许这样会更好,因为它允许动态排序的曲目列表 - 下一个/上一个曲目在当前排序顺序中总是正确的。
    • 那么当我添加过滤器并搜索到应用程序时,播放下一首曲目将播放过滤器中的下一首曲目而不是数组中的下一首曲目?重构上述内容以反映这一点的最佳方法是什么?我对 KO 还是比较陌生。
    • 是的。实现实际上非常相似。请参阅修改后的答案。您必须实施一些保护措施,以确保始终有一个“当前”曲目(即自动选择新加载列表的第一个曲目)并对空曲目列表做出反应(即删除旧的“当前”曲目)。过滤器也是如此。简而言之:无论出于何种原因,当当前曲目不在列表中时,您必须确保您的应用程序行为合理。
    猜你喜欢
    • 2013-08-30
    • 2012-11-10
    • 2019-01-09
    • 1970-01-01
    • 2013-04-10
    • 2015-08-15
    • 2013-10-18
    • 2013-02-04
    • 2012-02-18
    相关资源
    最近更新 更多