【问题标题】:JS: What function will make my code DRY?JS:什么函数会使我的代码干燥?
【发布时间】:2018-11-05 10:16:42
【问题描述】:

我的计划
最初在黑色网格上绘制的 Etch-A-Sketch。用户单击Erase 以在黑色方块上着色。用户也可以点击 **Rainbow" 在每个方块上绘制随机颜色,即 square[0] 可以是蓝色,square[1] 可以是紫色...等等,它们在每个鼠标悬停。

问题 您会注意到 eraseGrid()drawRainbow() 的代码几乎相同。我必须这样做,否则程序将无法正常工作。这是Rainbow在每个鼠标悬停上绘制不同颜色的唯一方法。

目标 如果你看一下我在底部注释掉的函数,我尝试想出一些我可以用于 eraseGrid()drawRainbow() 的东西,但是在测试功能失效,它没有按预期工作。它不会在每个鼠标悬停上绘制随机颜色,而是创建随机颜色(比如说蓝色)并在网格上绘制蓝色。如果我重新打开 Rainbow,它会创建另一种随机颜色(例如绿色)并将其绘制在网格上。
我不明白为什么我创建的函数不能按预期工作,而重复的代码却可以。


/**************************** Input->Button DOM ****************************/

const newGrid = document.getElementById('new-grid');
newGrid.addEventListener('click', createGrid);

const erase = document.getElementById('erase');
erase.addEventListener('click', eraseGrid);

const rainbow = document.getElementById('rainbow');
rainbow.addEventListener('click', drawRainbow);

/*********************** Grid variable and creation ***********************/

const main = document.querySelector('main');
const div = main.getElementsByTagName('div');

drawGrid(16, ((600 / 16) - 2) + 'px');
pickColor('#333');

function createGrid() {

    // removes divs from largest to smallest
    for (let i = main.childNodes.length - 1; i >= 0 ; i--) {
        main.removeChild(main.childNodes[i]);
    }

    let size;
    do {
        size = parseInt(prompt("Please enter a number from 1 to 64", ""), 10);
    } while(Number.isNaN(size) || size > 64 || size < 1);

    const numPx = (600 / size) - 2;
    let px = numPx + 'px';

    drawGrid(size, px);
    pickColor('#333');
}


function pickColor(color) {
    for (let i = 0; i < main.childNodes.length; i++) {
        main.childNodes[i].addEventListener('mouseover', function change() {
            main.childNodes[i].style.backgroundColor = color;
        })
    }
}

// draw grid of div elements
function drawGrid(size, px) {
    for (let i = 0; i < size; i++) {
        for (let j = 0; j < size; j++) {
            const div = document.createElement('div');
            main.appendChild(div);
            div.setAttribute('style', `width: ${px}; height: ${px}; 
                float: left; border: 1px solid #333;`);
        }
    }

    // clear floats
    const div = document.createElement('div');
    div.setAttribute('class', 'clear');
    main.appendChild(div);
}

function eraseGrid() {
    erase.classList.toggle('erase');
    if (erase.className === 'erase') {
        rainbow.classList.remove('rainbow');
        main.addEventListener('mouseover', function(){
            pickColor('#f2f2f2');
        })
    }
    else {
        main.addEventListener('mouseover', function(){
            pickColor('#333');
        })
    }
}

function randColor() {
    let arr = [];
    for (let i = 0; i < 3; i++) {
        arr.push(Math.floor(Math.random() * 255));
    }
    return arr;
}

function drawRainbow() {
    rainbow.classList.toggle('rainbow');
    if (rainbow.className === 'rainbow') {
        erase.classList.remove('erase');
        main.addEventListener('mouseover', function(){
            pickColor('rgb(' + randColor() + ')');
        })
    }
    else {
        main.addEventListener('mouseover', function(){
            pickColor('#333');
        })
    }
    // changeColor(rainbow, 'rainbow', erase, 'erase', 'rgb(' + randColor() + ')')
}

/*function changeColor(newClass, newClassStr, oldClass, oldClassStr, color) {
    newClass.classList.toggle(newClassStr);
    if (newClass.className === newClassStr) {
        oldClass.classList.remove(oldClassStr);
        main.addEventListener('mouseover', function(){
            pickColor(color);
        })
    }
    else {
        main.addEventListener('mouseover', function(){
            pickColor('#333');
        })
    }
}*/

【问题讨论】:

  • changecolor 反复触发pickcolor,这会导致创建新的事件监听器

标签: javascript function dry


【解决方案1】:

你可以算出名字,但看起来你只是在做

function go(str1, str2){
    document.getElementById(str1).classList.toggle(str1);
    if (document.getElementById(str1).className === str1) {
        document.getElementById(str2).classList.remove(str2);
        main.addEventListener('mouseover', function(){
            pickColor('#f2f2f2');
        })
    }
    else {
        main.addEventListener('mouseover', function(){
            pickColor('#333');
        })
    }
}

只需使用go('erase', 'rainbow')go('rainbow', 'erase') 调用它

function eraseGrid(){
    go('erase', 'rainbow');
}

function drawRainbow(){
    go('rainbow', 'erase');
}

【讨论】:

  • 我从他的代码中复制了它。在他的代码 sn-p 的顶部,您可以看到他通过 id 获取了擦除和彩虹元素。
【解决方案2】:

至于被注释掉的changeColor函数,你应该可以像这样重构它,如果你把rainbow和erase放在一个父对象中,这样你就可以通过名字找到它们。

const objects = {erase, rainbox};

function changeColor(str1, str2) { 
    objects[str1].classList.toggle(str1);
    if (objects[str1].className === str1) {
        objecs[str2].classList.remove(str2);
        main.addEventListener('mouseover', function(){
            pickColor('rgb(' + randColor() + ')');
        })
    }
    else {
        main.addEventListener('mouseover', function(){
            pickColor('#333');
        })
    }
}

再次,正如@me_ 在评论中提到的那样。在每次点击时添加一个 eventListener 很可能不是您想要的。在第五次单击后,您将拥有五个事件监听器和五个函数function(){pickColor('rgb(' + randColor() + ')');},每次您将鼠标悬停在“main”上时都会调用它们(每次单击都会扩展...)

(编辑因为 cmets 非常严格:)

00Saad:我看到有一个 removeEventListener() 方法,我可以通过添加 main.removeEventListener('mouseover', function(){ pickColor('rgb(' + randColor() + ')'); })在 addEventListener 之后?

不,如果您希望以后能够轻松删除它,请将函数存储在变量中。

function(){...} main.removeEventListener('mouseover', function(){...}),将创建一个新的匿名函数,并尝试从 main 的事件侦听器中删除(它不存在)。

此外,如果您使用存储函数 (const a = function(){..}) 和后来的 addEventListener('mouseover', a)),这将有点解决问题,因为无论如何您都不能多次将同一个函数绑定到同一个事件 (它不会有任何影响)。

但是下面的addEventListener-calls 不会有任何区别,所以在你的情况下,将鼠标悬停在changeColor() 的范围之外会更有意义。

let isRandomColor = true;
main.addEventListener('mouseover', function(){
  pickColor( isRandomColor ? randomColor() : '#333' );
});

function changeColor(){
  if (...){
    isRandomColor = true;
  } else {
    isRandomColor = false;
  }
}

【讨论】:

  • 事件监听器太多为什么不好...会导致内存问题吗?
  • 当你添加一个 eventListener 时,你是在说:“每次我在 main 上执行 'mouseover` 时调用这个函数”。它会一直工作,直到您销毁它(或直到您离开页面)。所以下次你点击彩虹时:“每次我做'鼠标悬停'时都调用这个函数”。它将创建一个 new eventListener,现在,每次当你将鼠标悬停在 main 上时,都会触发两个函数。旧的 eventListener 还在。
  • 这就是你正在做的事情:codepen.io/kumorig/pen/QreNMo 并检查这个问题stackoverflow.com/questions/6033821/…(很高兴了解事件监听器)
  • 如果是故意的,那还不错。但是您真的想在鼠标悬停时调用pickColor 43 次吗? (对不起垃圾邮件!)
  • 我看到有一个 removeEventListener() 方法,我可以通过添加 main.removeEventListener('mouseover', function(){ pickColor('rgb(' + randColor() + ' )'); }) 在 addEventListener 之后?
猜你喜欢
  • 2014-12-13
  • 2015-08-18
  • 1970-01-01
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多