【问题标题】:How do I convert this to an OOP structure?如何将其转换为 OOP 结构?
【发布时间】: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) 已解决!有点,就是这样。所有电视克隆都可以按预期运行,这意味着静态显示将在所有未按下频道按钮的电视上保持活动状态,并且可以独立更改频道。以下是我对原始代码所做的主要更改:

  1. 所有 id 都替换为类,以便可以访问它们并将“tv-body”和“legs”包装在单独的 div 中,以便可以将它们克隆为一个集合。
  2. 在 tv function() 之外收集所有“tv-set”类元素,然后执行设置函数 forEach()
  3. 将一些变量(例如 canvas、isStatic)转换为数组,以便它们的状态和显示可以独立切换。我确信这里还有更多工作要做,因为某些变量可能仍会在克隆之间共享。

【问题讨论】:

  • 你不需要做 OOP 来实现这一点。您可以在每个电视项目上执行 for 循环以动态附加 html 代码,而不是在类元素上使用 addEventListener,而不是 id
  • @ggirodda,所以用 js 脚本创建一个 for 循环并让 tv_set_01 = tv()?抱歉这个愚蠢的问题,谢谢!
  • 见下面代码中的例子

标签: function class object


【解决方案1】:

你可以从下面的代码中得到一些启发,例子不那么复杂,但思路是一样的

const tvs = [
  { channels: ["red", "blue"] },
  { channels: ["green", "yellow"] }
]

function changeChannel(idx) {
  const tv = tvs[idx]
  const tvNode = document.getElementById("tv-" + idx)
  const currentChannelIdx = parseInt(tvNode.getAttribute("data-channel"))
  const nextChannelIdx = tv.channels[currentChannelIdx + 1] ? currentChannelIdx + 1 : 0;
  tvNode.style.backgroundColor = tv.channels[nextChannelIdx]
  tvNode.setAttribute("data-channel", nextChannelIdx)
}

const container = document.getElementById("container")
const template = document.getElementById("tv-template").children[0]

for (let i = 0; i < tvs.length; i++) {
  const clone = template.cloneNode(true);
  clone.setAttribute("id", "tv-" + i)
  clone.setAttribute("data-channel", 0)
  clone.style.backgroundColor = tvs[i].channels[0]
  container.appendChild(clone)
}

const buttons = document.getElementsByClassName("channel-btn")

for (let i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', () => changeChannel(i), false);
}
<div id="container"></div>

<div id="tv-template" style="display: none;">
  <div class="tv" style="width: 70px; height: 70px; margin-bottom: 20px;">
    <button class="channel-btn">next</button>
  </div>
</div>

【讨论】:

  • 因此,第一个 for 循环减去代码 sn-p 中的背景颜色,我实际上是在复制包含其所有子元素的电视显示器,然后根据它的顺序为每个元素分配一个 unqiue 标识符是从上面的 dicts{} 数组中读入的?再次感谢!
  • 是的,在第一个循环中,为数组的每个项目克隆一个节点模板,并根据其在数组中的位置('tv-' + POSITION)附加到具有 id 的容器, 并且 data-channel 默认等于 0。 data-channel 实际上是当前背景颜色的索引,这个属性将用于计算下一个背景要放在 tv 元素上
  • 好的,现在我已经克隆了显示器,我正在尝试让每个电视的频道按钮工作。对于要传递给函数的按钮项,我一直未定义。当我尝试获取 tvs.length 时,会发生相同的“未定义”错误,因此我必须对迭代次数进行硬编码。我在想我可以使用 tv-id 例如“tv-1”作为按钮父级的名称并将名称为“channel-button”的子元素传递给 changeChannel 函数吗?这样,如果我还要添加一个电源按钮,fxn 就会知道是哪一个。
  • 您可以遍历每个按钮父级,而不是在循环中找到按钮子级,使用const theButton = currentButtonParent.getElementsByClassName("the-button-class")[0],然后使用theButton.addEventListener("click" ...)。您可以从按钮父类的循环中获取索引,该索引将用于获取 tvs 数组中的当前项
  • 再次抱歉@ggirodda,但是当您说“按钮父级”时,这是否意味着保留相同的语法const buttons = document.getElementsByClassName("channel-btn") 或者指的是环绕在
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-09
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 2021-10-18
  • 1970-01-01
相关资源
最近更新 更多