我可能陷入困境,我是 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);
});
最佳答案
简而言之,您的原始代码存在几个问题。以下是我尝试使当前代码集正常工作(在底部提供改进建议。请参阅 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/