【发布时间】:2021-02-25 23:31:33
【问题描述】:
目前,我分叉的这个 codepen 在网页上显示一个电视监视器,如下所示,其中频道按钮允许用户切换不同的 gif。此 gif 数据以数组形式存储在 js 文件中。我想创建多个电视机,所以我认为创建一个 TV 类并通过循环实例化 TV 对象 n 次可能会更好。我是 Web 开发环境中的 OOP 新手,所以我还没有弄清楚如何重新构建代码来完成这个任务。由于 id 只允许一个 HTML 元素,复制下面的代码块会在视觉上创建另一台电视,但没有任何动态功能。那么电视机身显示元素会变成什么?它们会被嵌套在脚本的 TV 类中的 show() fx 包围吗?提前非常感谢您!
[此处显示的裁剪输出][1]
HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - Vintage Analog TV</title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><link rel="stylesheet" href="./style.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
</head>
<body>
<!-- partial:indexe.partial.html -->
<main>
<div class="tv-set">
<div class="tv-body">
<div class="screen-container">
<canvas class="static" width="380" height="280"></canvas>
<img class="displayed" src="" alt="Nothing" width="380" height="280">
<div class="screen">
<div class="screen-frame"></div>
<div class="screen-inset"></div>
</div>
</div>
<div class="logo-badge">
<div class="logo-text">Bush</div>
</div>
<div class="controls">
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="channel dial-label pristine">Channel</button>
</div>
</div>
<div class="vents">
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
</div>
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="dial-label" disabled>Volume</button>
</div>
</div>
</div>
</div>
<div class="legs">
<div class="leg"></div>
<div class="leg"></div>
</div>
</div>
</main>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
JS
document.addEventListener("DOMContentLoaded", tv);
// Helper Functions
//returns tagname
jQuery.fn.tagName = function () {
return this.prop("tagName").toLowerCase;
};
// returns nth parent from target element
$.fn.nthParent = function (n) {
var p = this;
for (var i = 0; i < n; i++)
p = p.parent();
return p;
}
phases = [{
channels: ["red", "blue"]
},
{
channels: ["green", "yellow"]
},
{
channels: ["red", "green"]
},
{
channels: ["blue", "green"]
}
]
const container = document.getElementsByTagName("main")[0];
const template = document.getElementsByClassName("tv-set")
for (let i = 0; i < phases.length; i++) {
const clone = template[i].cloneNode(true);
clone.setAttribute("id", "tv-" + (i + 1))
console.log("clone id: ", clone.getAttribute("id"))
clone.setAttribute("data-channel", 0)
clone.setAttribute("name", "tv-" + i)
// clone.style.backgroundColor = phases[i].channels[0]
container.appendChild(clone)
}
function tv() {
let cnvs = document.querySelectorAll(".static");
//Gather all static elements
// let scrns = $(".static").getContext
// console.log("Screen 01: ", scrns)
// var cnv = document.getElementById("static"),
// var cnv = document.querySelector(".static"), //works in place of line above
// Need to establish a boolean array for the isStatic
let c = []
let isStatic_arr = []
// Need to establish a boolean array for the isStatic
cnvs.forEach((cnv) => {
isStatic_arr.push(false)
var c = cnv.getContext("2d"),
cw = cnv.offsetWidth,
ch = cnv.offsetHeight,
staticScrn = c.createImageData(cw, ch),
staticFPS = 30,
// isStatic_arr.push(false),
// isStatic = false,
staticTO,
gifData = [{
// file: "https://i.ibb.co/chSK1Zt/willie.gif",
file: "./media/back-to-school-chacha.gif",
desc: "Stephen Chow Fight Back to School"
// <video controls autoplay>
// <source src="fbts_chacha_sound.mp4" type="video/mp4">
// <source src="movie.ogg" type="video/ogg">
// Your browser does not support the video tag.
// </video>
},
{
file: "https://i.ibb.co/chSK1Zt/willie.gif",
desc: "Steamboat Willie (Mickey Mouse) steering a ship"
},
{
file: "https://i.ibb.co/0FqQVrj/skeletons.gif",
desc: "Spooky scary skeletons sending shivers down your spine"
},
{
file: "https://i.ibb.co/Hpnwgq2/kingkong.gif",
desc: "King Kong waving on Empire State Building",
},
{
file: "https://i.ibb.co/fp0PSjv/tracks.gif",
desc: "Looking at train tracks from behind a train",
},
{
file: "https://i.ibb.co/5FM7BtH/nuke.gif",
desc: "Nuclear explosion at sea",
}
],
gifs = [],
channel = 0;
for (g in gifData) {
gifs.push(new Image());
gifs[g].src = gifData[g].file;
gifs[g].alt = gifData[g].desc;
}
/* Static */
var runStatic = function () {
isStatic = true;
c.clearRect(0, 0, cw, ch);
for (var i = 0; i < staticScrn.data.length; i += 4) {
let shade = 127 + Math.round(Math.random() * 128);
staticScrn.data[0 + i] = shade;
staticScrn.data[1 + i] = shade;
staticScrn.data[2 + i] = shade;
staticScrn.data[3 + i] = 255;
}
c.putImageData(staticScrn, 0, 0);
staticTO = setTimeout(runStatic, 1e3 / staticFPS);
};
runStatic();
/* Channels */
var changeChannel = function (button, idx) {
console.log("Tv-set: ", idx)
console.log("Tv-set- " + idx + "button: " + button)
// var displayed = document.getElementById("displayed");
var displayed = document.querySelectorAll(".displayed")[idx];
var display_parent = $(".displayed")[1]
console.log("Display: ", displayed)
console.log("Display's parent: ", display_parent)
++channel;
if (channel > gifData.length)
channel = 1;
// this.classList.remove("pristine");
button.classList.remove("pristine");
// this.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
button.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
theCanvas = document.querySelectorAll(".static")[idx]
// cnv.classList.remove("hide");
theCanvas.classList.remove("hide");
displayed.classList.add("hide"); //CAUSING PROBLEMS
if (!isStatic[idx])
runStatic();
setTimeout(function () {
// cnv.classList.add("hide");
theCanvas.classList.add("hide");
displayed.classList.remove("hide");
displayed.src = gifs[channel - 1].src;
displayed.alt = gifs[channel - 1].alt;
isStatic = false;
clearTimeout(staticTO);
}, 300);
};
function iterate(item, index) {
console.log(`${item} has index ${index}`);
}
// const buttons = document.getElementsByClassName("channel dial-label pristine");
// const btns_arr = Array.from(document.querySelectorAll(".channel"))
const buttons = document.querySelectorAll(".channel")
buttons.forEach((btn, i) => {
btn.addEventListener('click', () => changeChannel(btn, i));
});
});
}
[1]: https://i.stack.imgur.com/INtzP.png
[2]: https://i.stack.imgur.com/aOxoQ.png
(20 年 11 月 14 日)@ggirodda,非常感谢您提供的示例。不幸的是,我仍然有点卡住。为什么当我使用const template = document.getElementsByClassName("tv-body").children[0] 时,出现错误:script_001.js:154 Uncaught TypeError: Cannot read property '0' of undefined
在 HTMLDocument.tv (script_001.js:154) tv-body 类不应该根据下面的代码 sn-p 有子级吗?
(20 年 11 月 14 日)通过删除 .children[0] 解决了上述错误,但不确定为什么会这样以及为什么它未定义。
(11/19/20) 已解决!有点,就是这样。所有电视克隆都可以按预期运行,这意味着静态显示将在所有未按下频道按钮的电视上保持活动状态,并且可以独立更改频道。以下是我对原始代码所做的主要更改:
- 所有 id 都替换为类,以便可以访问它们并将“tv-body”和“legs”包装在单独的 div 中,以便可以将它们克隆为一个集合。
- 在 tv function() 之外收集所有“tv-set”类元素,然后执行设置函数 forEach()
- 将一些变量(例如 canvas、isStatic)转换为数组,以便它们的状态和显示可以独立切换。我确信这里还有更多工作要做,因为某些变量可能仍会在克隆之间共享。
【问题讨论】:
-
你不需要做 OOP 来实现这一点。您可以在每个电视项目上执行 for 循环以动态附加 html 代码,而不是在类元素上使用 addEventListener,而不是 id
-
@ggirodda,所以用 js 脚本创建一个 for 循环并让 tv_set_01 = tv()?抱歉这个愚蠢的问题,谢谢!
-
见下面代码中的例子