为什么这个JavaScript函数在网站第一次加载时不能正确计算,但之后工作正常?


Why doesn't this JavaScript function calculate correctly when the site is first loaded, but works fine afterwards?

我在一个网站上工作,根据一些用户选择的参数生成随机音乐节奏的符号。它通过使用ajax调用来实现这一点,该调用返回一组随机的表示不同音符的<img>元素。我有一个函数,它被设计成缩放节奏以适应屏幕,而不管它的实际大小。

该函数在ajax调用成功后触发,该调用由按钮上的单击事件触发。

我的问题是,当第一次加载页面时,该函数不能按预期工作。

函数第一次运行后,所有<img>元素的height属性以某种方式被设置为0

然而,如果我再次运行它(通过单击按钮),该函数工作得很好。它在页面刷新后也可以正常工作。

另外,我在IE11中没有这个问题,只有Chrome(我还没有测试过其他浏览器)。

我已经尝试在$(window).load()$(document).ready()事件处理程序中包装代码,但这没有帮助。

网址:http://www.rhythmrandomizer.com

任何帮助都将非常感激!

以下是相关代码:

按钮的事件处理器:

$("#randomize").click(function(){
    //get general options from form
    var timeSignature = $("#timeSignature").val();
    var phraseLength = $("#phraseLength").val();
    //get note options from form
    var checked = [];
    $("#noteOptions :checked").each(function() {
        checked.push($(this).val());
    });
    //alert user and exit function if nothing is selected
    if (checked.length < 1) {
        alert("Please select at least one note value");
        return;
    }

    //format note option ids into a delimited string
    var noteOptions = "";
    for (var i=0; i < checked.length; i++) {
        noteOptions += checked[i] + "a";
    }
    //remove the final comma and space
    noteOptions = noteOptions.substr(0, noteOptions.length - 1);
    //ajax call
    $.ajax("randomize.php", {
        data : {
            timeSignature : timeSignature,
            phraseLength : phraseLength,
            noteOptions : noteOptions
        },
        type : "GET",
        success : function(response) {
            $("#rhythm").html(response);
            scaleRhythm();
        },
        error : function(xhr, status, errorThrown) {
            console.log(status + " | " + errorThrown);
        }
    }); 
});

返回节奏符号的php文件:

<?php
//MySQL connection variables
$hostname = 'localhost';
$user = ini_get('mysqli.default_user');
$pw = ini_get('mysqli.default_pw');
$database = 'rhytxfpd_rhythmrandomizer';
//Connect to database
try {
    $db = new PDO('mysql:host=' . $hostname . ';dbname=' . $database,$user,$pw);
} catch(PDOException $e) {
    echo $e->getMessage();
    die();
}
//Get values from GET
$timeSignature = $_GET['timeSignature'];
$phraseLength = $_GET['phraseLength'];
$noteOptString = $_GET['noteOptions'];
//Split up note options string
$noteOptions = explode('a', $noteOptString);
//Create sql query
$sql = 'SELECT
            noteName,
            noteValue,
            noteGraphic
        FROM
            notes
        WHERE';
//append noteOptions as WHERE clauses
foreach ($noteOptions as $opt) {
    $sql = $sql . ' noteGroupID = ' . $opt . ' OR';
}
//remove final " OR"
$sql = substr($sql, 0, strlen($sql) - 3);
//query the database and get all results as an array
/* This will return a table with the name, graphic, and value of 
 * the notes that the user selected prior to submitting the form
 */
$stmt = $db->query($sql);
$result = $stmt->fetchAll();
//Get the total number of options selected
$numOpts = count($result);
/***************************/
/** BEGIN PRINTING RHYTHM **/
/***************************/
//div to begin the first measure
echo '<div class="measure" id="m1' . $measure . '">';
//Print time signature
echo '<img class="note" src="notes/' . $timeSignature . '.png" title="time signature ' . 
        $timeSignature . '/4" alt="time signature ' . $timeSignature . '/4"/>';
//Prints as many measures as indicated by the phrase length selection
$measure = 1;
while ($measure <= $phraseLength) {
    //begin a new div for other measures.
    if ($measure != 1) {
        echo '<div class="measure" id="m' . $measure . '">';
    }
    //Prints random measure according to time signature
    $beats = 0;
    while ($beats < $timeSignature) {
        //Generate a random number
        $random = rand(0, $numOpts - 1);
        //Get the random note from results
        $note = $result[$random];
        //Continues if chosen note will not fit in the measure
        if ($beats + $note['noteValue'] > $timeSignature) {
            continue;
        }
        //Prints random note
        echo '<img class="note" src="notes/' . $note['noteGraphic'] . '.png" title="' .
                $note['noteName'] . '" alt="' . $note['noteName'] . '"/>';
        //Adds random note's value to total number of beats
        $beats += $note['noteValue'];
        //$beats++;
    }
    //If last measure
    if ($measure == $phraseLength) {
        echo '<img class="note" src="notes/1.png" title="double barline" alt="double barline"/>';
        echo '</div>';
    } else {
        echo '<img class="note" src=notes/b.png title="barline" alt="barline"/>';
        echo '</div>';
    }
    //Increment to next measure
    $measure++;
}

scalerrhythm()函数:

function scaleRhythm() {
    //Get width of rhythm at full resolution
    var rhythmWidth = $("#rhythm").width();
    //Get current screen/window width
    var screenWidth = window.innerWidth;
    //Compute ratio between curren screen and window widths
    var ratio =   screenWidth / rhythmWidth;
    //Multiply img note height by ratio, then by 90% to provide some
    //breathing room on either side of the rhythm
    var newHeight = (400 * ratio) * .9;
    //Set img note height to new height or 300px, whichever is smaller
    if (newHeight < 300) {
        $(".note").css("height",newHeight);
        //code to center rhythm horizontally
        $("#rhythm").css("margin-top",(300-newHeight)/2);
    } else {
        $(".note").css("height",300);
        $("#rhythm").css("margin-top",0);
    }
}

将此javascript添加到您的<script></script>:

$(function(){ $("#randomize").click(); });

这将导致您的页面运行填充随机元素的函数,然后(在该函数的末尾)运行缩放函数。

我通过在chrome控制台上在你的页面上运行它来测试它,它工作了。

如果您在scaleRhythm函数中设置了一个断点,您会注意到在页面加载时它没有运行。您已经定义了函数,但在页面加载时没有调用它。事实上,没有你想要运行的代码(即:ajax调用)得到调用,直到第一次点击发生。所以你需要做的就是像JRulle所说的那样触发按钮上的click事件。

$("#randomize").click();

好的,这是你的问题。第一次单击按钮时,var rhythmWidth = $("#rhythm").width();的计算结果为"0",因为它是空的。

导致后面的函数也为"0":

var ratio =   screenWidth / rhythmWidth;
var newHeight = (400 * ratio) * .9;

我将编辑你的函数如下:

var rhythmWidth = $("#rhythm").width();
if (rhythmWidth == 0) { rhythmWidth = 10; } //assign some reasonable value here

因为你的函数不支持rhythmWidth为"0"