滑动面板,如何重现它们?

Posted

技术标签:

【中文标题】滑动面板,如何重现它们?【英文标题】:Sliding Panels, how to reproduce them? 【发布时间】:2014-11-10 02:39:13 【问题描述】:

我可能在这里深陷困境,而且我是 javascript 和 jQuery 的新手, 但我想尝试创建一个面板系统,类似于 spotify 的做法。

看看这张照片:

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

以下是 Spotify:

我想了解如何在 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);
);

【问题讨论】:

我意识到我刚刚发布了我的答案,并且可能误解了幻灯片一词的用法——我的 spotify 版本不滑动,它只是在播放列表、艺术家、专辑等之间切换时加载。我对我看到的 spotify 所做的事情做了一个非常基本的模型,你能扩展一下你所说的幻灯片的意思吗?或者也许,Yatin Mistry 的回应缺少你想要的什么? 【参考方案1】:

简而言之,您的原始代码存在几个问题。下面是我尝试使当前代码集工作的尝试(底部有改进建议。请参阅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 元素。

您可以通过在 `//make all panel not selected`` 循环中将 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 过渡 - 仅在第二个小提琴中 我向您的 .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 || [];

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

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);

【讨论】:

【参考方案2】:

这不是您要查找的内容,也与您发布的代码完全无关。但是,这是我整理的一些东西,可能是您查看的好资源。它没有实现堆栈,但您可以相当容易地应用这些概念。 Check it out.

您可以摆脱 createPanel 函数并在 init 函数中预先创建/分配所有面板,然后让控制器使用这些面板作为基础。然后只需控制 DOM 中显示的内容即可

display: none

将有效地从 DOM 记忆中移除一个元素,并可用于隐藏某些面板。

【讨论】:

【参考方案3】:

检查这个fiddle:http://jsfiddle.net/k0Lh3ama/1/

做 css 的东西。我不是它的主人..

你的 CSS ::

.sidebar
    width:10%;
    background-color:#000;
    color:#FFF;
    height:800px;
    float:left;


.box
    width:7%;
    float:left;
    height:800px;
    background-color:red;
    border:1px solid #000;

.active
    width:64%;
    float:right !important;
     -webkit-transition: all 1s ease-in-out;
-moz-transition: all 1s ease-in-out;
-o-transition: all 1s ease-in-out;
transition: all 1s ease-in-out;

您的 HTML 代码 侧边栏

    <div id="panel2" class="box active">Panel 1 </div>

    <div id="panel3" class="box">Panel 2 </div>

    <div id="panel4" class="box">Panel 3</div>

    <div id="panel5" class="box">Panel 4 </div>

jQuery

$(function()
    $(".box").click(function()
        $(".box").removeClass("active");
        $(this).addClass("active");
    ); 
);

【讨论】:

【参考方案4】:

您可能不应该更改 CSS。基本上,您想要的是两个 div,一个包含“面板”列表,另一个包含单个“面板”的详细视图。我认为这个问题可以分解为多个子问题:

1) 从服务器获取面板对象列表,并动态填充左侧 div,很可能使用包含面板信息的子 div。换句话说,在页面加载时,需要运行一些代码来循环遍历列表并将 div 添加到左侧 div,每个面板一个,并且这些部分的 CSS 应该处理它们的布局方式和所有内容。一个简单的起点可能是为列表中的每个项目添加一个按钮,或者一个图像等。

2) 事件处理程序,这样当您单击列表中的面板时,它会将详细视图加载到右侧 div 中。这也可能会从列表中删除面板,或以某种方式在视觉上更改它(将其变灰),或其他任何方式。

3) 如果项目已加载到其中,则在右侧 div 中显示详细信息的代码,如果没有,则执行其他默认设置。

为了简化这一切而作弊的一种方法可能是让面板和详细视图成为预先构建的页面,并将它们加载到 iframe 等中的主页中。

【讨论】:

以上是关于滑动面板,如何重现它们?的主要内容,如果未能解决你的问题,请参考以下文章

单击时滑动面板跳回主页

IOS容器视图在它们之间滑动

【Axure】触摸屏上下滑动效果

axure动态面板滑动与拖动的区别?

jQuery Mobile 面板不应该在向左滑动时关闭

讲解怎么在Unity的Inspector面板中用滑动条来控制变量的大小