javascript - 滑动面板,如何复制它们?

标签 javascript jquery html panel spotify

我可能陷入困境,我是 JavaScript 和 jQuery 的新手, 但我想尝试创建一个类似于 spotify 的面板系统。

看看这张图:

Diag

在 Spotify 播放器网站上,当您点击艺术家或歌曲/专辑等内容时, 它会在屏幕右侧的最顶部面板中滑动,如果您单击其他内容, 一个新的面板将出现在它的位置,而前一个面板将被添加到屏幕左侧我称之为面板堆栈的地方。

以下是 Spotify 的介绍: enter image description here

我想了解如何在 JavaScript/jquery 中执行此操作,有人可以分享一些意见吗?

我尝试过的:( http://jsfiddle.net/k0Lh3ama/ )

我知道我的尝试很糟糕,这就是我来这里的原因

var idx = 0;
var panels = [];
var numpanels = 0;

function panel () {
    this.id = 0;
    this.active = false;
    this.container = {};
}

var panelmgr = new function () {
    this.Create = function (lpPanel) {

        //set all current panels to inactive 
        //and then push them left
        for (var i = 0; i < panels.length; i++) {
            panels[i].active = false;
            panels[i].container.css("left", "10%");
        }

        //set the newest panel to Active and Top Most
        lpPanel.container.css("z-index", 10000);
        lpPanel.container.css("left", "25%");

        //setup some info for the new panel
        lpPanel.id = numpanels++;
        lpPanel.active = true;

        //add it to array
        panels.push(lpPanel);
    };
}

$(".box").click(function (e) {            
    var id = $(this).attr("id");
    var selected = -1;

    //find the panel we've selected and retrieve the index
    for (var i = 0; i < panels.length; i++) {
        if (id == panels[i].container.attr("id")) {
            selected = I;
            break;
        }                    
    }

    //do we have a valid selected panel?
    if (selected >= 0) {

        //Make all panels not selected
        for (var i = 0; i < panels.length; i++) {
            panels[i].active = false;
            panels[i].container.css("left", "10%");
        }

        //now make the panel we selected 
        //the top most panel
        panels[selected].active = true;
        panels[selected].container.css("z-index", 10000);
        panels[selected].container.css("left", "25%");
    }



});

$(document).ready(function () {

    var p1 = new panel();
    var p2 = new panel();
    var p3 = new panel();
    var p4 = new panel();
    var p5 = new panel();

    p1.container = $("#panel1");
    p2.container = $("#panel2");
    p3.container = $("#panel3");
    p4.container = $("#panel4");
    p5.container = $("#panel5");

    panelmgr.Create(p1);
    panelmgr.Create(p2);
    panelmgr.Create(p3);
    panelmgr.Create(p4);
    panelmgr.Create(p5);
});

最佳答案

简而言之,您的原始代码存在几个问题。以下是我尝试使当前代码集正常工作(在底部提供改进建议。请参阅 my original fiddle 以了解在不更改大部分原始代码的情况下工作的代码。我还修改了原始 fiddle (with sliding) 以使用 css 转换到给一个幻灯片效果)

1) 您不断地覆盖您的面板,因为它们的 css top 值全部设置为零。您可以通过为所有非事件面板设置最高值来解决这个问题。 (我假设您希望该项目从堆栈中消失,因为您在选择它时将其移动到当前位置)

//Increment height
var ii = 0;
for (var i = 0; i < panels.length; i++) {
    if(panels[i].active == false){
        panels[i].container.css("top", ii*30+"px");
        ii++;
    }
}

2) 您的 Z-index 和宽度导致 panel stack 面板和 current panel 重叠,默认为最后创建的任何 dom 元素。

您可以通过在“//使所有面板未被选中”循环中将 z-index 值设置为较低的值来解决此问题

panels[i].container.css("z-index", "1");

3) 当 current panels 内容在堆栈中时,您可能还想隐藏它,否则您的堆栈会变得相当困惑。您可以通过将 DOM 面板拆分成如下内容来解决此问题:

<div id="panel5" class="box">
    <div class="panelTitle">Panel 4</div>
    <div class="contents">Stuff to display</div>
</div>

并将以下代码添加到以下循环中:

//Make all panels not selected
for (var i = 0; i < panels.length; i++) {
    //other code emitted for space...
    //hide the contents
    panels[i].container.find(".contents").css("display","none");
}

//now make the panel we selected 
//the top most panel
panels[selected].active = true;
panels[selected].container.css("z-index", 2);
panels[selected].container.css("left", "25%");
panels[selected].container.css("top","0px");
//it's active, so display the contents
panels[selected].container.find(".contents").css("display","block");

4) 如果您希望面板在点击时滑动,我添加了 CSS 转换 - 仅在第二个 fiddle 中 我向您的 .box 添加了一个转换规则 选择器,它将第二次延迟具有类 box 的元素的所有 css 更改。请看css3 transitions有关自定义转换的更多信息。

transition: all 1s;
-webkit-transition: all 1s;
-moz-transition: all 1s;
-o-transition: all 1s;

改进/更好发展的建议

老实说,我可能会进行大量重写。 DOM 操作完成了工作并且是一个公平的开始,但是如果事情变得复杂,那么在 javascript 中跟踪每个面板所需的数据并在需要时生成新鲜的 DOM 元素会容易得多。我可能会根据以下免责声明做一些事情,我没有对以下代码进行整体测试,这只是一个指南:

1) 定义包含面板所有相关信息的数据结构,并在 javascript 中实现它。这类似于您已经拥有的内容,但至少我会添加一个面板标题和面板内容。

与您拥有的类似,但我会添加到它并进行一些参数检查并删除容器

function Panel (jobj) {
    if(typeof jobj === "undefined") throw new ReferenceError("Bad value passed to constructor");
    if(typeof jobj.id === "undefined") throw new ReferenceError("Missing an id");
    this.id = 0;
    this.active = false;
    if(typeof jobj.title === "undefined") throw new ReferenceError("Missing panel title");
    this.title = jobj.title;
    //set to passed value, or if doesn't exist, default to empty array;
    this.tracks = jobj.tracks || [];
}

作为奖励,您可以利用原型(prototype)设计并构建具有不同形式的参数检查的不同类型的面板...我很确定还有其他方法可以做到这一点,但我发现以下方法适合我.

var DiscoverPanel = function(jsonObj){
    if(typeof jsonObj === "undefined")throw new ReferenceError("Expecting a JSON object but received none");
    var panel = new Panel(jsonObj);
    if(typeof jsonObj.genre === "undefined") throw new ReferenceError("Missing genre!")
    panel.genre = jsonObj.genre;
    return panel;
}

2) 为堆栈和当前面板创建 HTML,因此我会将其缩小到 2 个,而不是您当前拥有的 5 个 div 元素。不要忘记根据自己的喜好设置样式

<ul id="stack"></ul>
<div id="current"></div>

3) 在 javascript 而不是 html 中定义面板。一旦您有了传递给构造函数的底层 json 对象的工作示例,您可能会发现编写一个通过 AJAX 调用并返回必要的 JSON 的服务器端服务是有益的。

构造器会这样调用:

//there are plenty of ways to generate the id within the constructor if hard coding
//it bugs you, your post showed a means of doing so.
var p1 = new Panel({title:"Panel 1",id:"p1"});
var p2 = new Panel({title:"Panel 2",id:"p2"});
var dp = new DiscoverPanel({title:"discover",id:"dp",genre:"rock"});
//etc.
var pn = new Panel({title:"Panel n"});
var panels = [p1,p2,dp,...,pn];

4) Onload/domready 为非事件面板生成 innerHTML,可能来自面板标题。

$(document).ready(function () {
    generateList();
}
function generateList(){
    var stack = document.getElementById("stack");
    stack.innerHTML = "";
    panels.forEach(function(panel){
        var item = document.createElement("li");
        item.setAttribute("id",panel.id)
        item.innerHTML = panel.title;
        item.onclick = function(){
            //load this specific panel to the current
            loadCurrent(panel);
            //regenerate the stack
            generateList();
        }
        stack.appendChild(item);
    });
}

5) 继续为当前面板生成innerHTML。这与上述创建元素并根据面板数据生成内容的方法非常相似。

function loadCurrent(panel){
    panel.active = true;
    var cur = document.getElementById("current");
    //Figured table was a good example, but you could get as creative as you want
    //using floats, divs, etc. Could also check the types and handle different types of panels
    var table = document.createElement("table");
    panel.tracks.forEach(function(track){
        var row = document.createElement("tr");
        var td = document.createElement("td");
        td.innerHTML = track.number;
        row.appendChild(td);
        //repeat for whatever other values you have for a track
        //you'd likely add a play function or something of that sort to each.
        table.appendChild(row);
    });
    table.appendChild(cur);
}

关于javascript - 滑动面板,如何复制它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25867205/

相关文章:

javascript - 使用 jquery 使用 JSON 数据重新填充表单

javascript - 函数 .animate 百分比不起作用

javascript - 使用 AngularJS 切换文本字体

javascript - Flash 元素上方的图像

javascript - 如何使两个或多个 html 元素在可编辑区域中表现为一个单元

javascript - 轻轻滚动到页面的一部分的脚本在 javascript 上生成错误

javascript - 如何使用 CSS 将图像格式化为与 HTML 中的多个部分并行?

javascript - 当字段为空时,在提交表单时向元素添加类

jquery - 如何用CSS覆盖输入字段

html - 倾斜边框上的框阴影 :after pseudoelement