ตัวแปรคงอยู่ระหว่างการโหลดหน้า


97

ฉันกำลังพยายามจับภาพการกดปุ่มส่งของแบบฟอร์มของฉันและหากมีการส่งแบบฟอร์มหน้านี้จะรีเฟรชและฉันแสดงช่องที่ซ่อนอยู่สองสามช่อง ฉันต้องการจับภาพว่ามีการส่งแบบฟอร์มมาก่อนหรือไม่และหากส่งเมื่อโหลดซ้ำฉันต้องการยกเลิกการซ่อนฟิลด์ที่ซ่อนอยู่ ฉันพยายามใช้ตัวแปรส่วนกลางเพื่อให้บรรลุสิ่งนี้ แต่ฉันไม่สามารถทำให้มันทำงานได้อย่างถูกต้อง

นี่คือสิ่งที่ฉันลอง:

  var clicked = false;

  $(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch'; clicked = true;  return true;");

    if (clicked == true) {
      // show hidden fields
    } else {
      // don't show hidden fields
    }
  });

ข้อเสนอแนะใด ๆ เกี่ยวกับสิ่งที่ผิดปกติกับรหัสนี้?


1
ฉันไม่คิดว่าสิ่งนี้จะทำได้หากไม่มีที่เก็บข้อมูลบางประเภท ตัวแปร JS ของคุณจะถูกลบออกทั้งหมด ขอบเขตทั้งหมดของคุณจะถูกรีไซเคิล
Dave Alperovich

ทำไมคุณไม่ใส่หน้าเว็บส่วนใหญ่เป็น "บางส่วน" แล้วรีเฟรช
Dave Alperovich

บางส่วนคืออะไร? ขออภัยฉันไม่ทราบเรื่องนั้น
Neophile

คุณได้พิจารณาการส่งแบบฟอร์มผ่าน ajax และแสดงฟิลด์หลังจากการส่งหรือไม่?
dannyshaw

1
คุณสามารถอธิบายได้อย่างละเอียดว่าเหตุใดคุณจึงต้องรีเฟรชหน้านี้ หากเราสามารถหลีกเลี่ยงได้คุณอาจทำสิ่งที่ต้องการได้หากคุณpreventDefaultอยู่ในsubmitงาน (แทนที่จะclickใช้งาน)
Peleg

คำตอบ:


207

เนื่องจาก HTTP ไม่มีสถานะทุกครั้งที่คุณโหลดหน้าเว็บจะใช้ค่าเริ่มต้นของสิ่งที่คุณตั้งไว้ใน JavaScript คุณไม่สามารถตั้งค่าตัวแปรส่วนกลางใน JS และทำให้ค่านั้นคงอยู่หลังจากโหลดหน้าเว็บอีกครั้ง

มีสองวิธีที่คุณสามารถเก็บค่าไว้ที่อื่นเพื่อให้คุณสามารถเริ่มต้นเมื่อโหลดโดยใช้ JavaScript


สตริงการค้นหา

เมื่อส่งแบบฟอร์มโดยใช้GETเมธอด url จะได้รับการอัปเดตด้วยสตริงการสืบค้น ( ?parameter=value&something=42) คุณสามารถใช้สิ่งนี้ได้โดยตั้งค่าช่องป้อนข้อมูลในรูปแบบเป็นค่าที่แน่นอน นี่เป็นตัวอย่างที่ง่ายที่สุด:

<form method="GET">
    <input type="hidden" name="clicked" value="true" />
    <input type="submit" />
</form>

ในการโหลดครั้งแรกของหน้าจะไม่มีการตั้งค่าสตริงการสืบค้น เมื่อคุณส่งรูปแบบนี้nameและการรวมกันของการป้อนข้อมูลที่ถูกส่งผ่านในสตริงแบบสอบถามเป็นvalue clicked=trueดังนั้นเมื่อหน้าเว็บโหลดอีกครั้งด้วยสตริงการสืบค้นนั้นคุณสามารถตรวจสอบได้ว่ามีการคลิกปุ่มหรือไม่

หากต้องการอ่านข้อมูลนี้คุณสามารถใช้สคริปต์ต่อไปนี้ในการโหลดหน้า:

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

var clicked = getParameterByName('clicked');

( ที่มา )

ความสามารถในการใช้สิ่งนี้ขึ้นอยู่กับว่าแบบฟอร์มของคุณทำงานอย่างไรในปัจจุบันหากคุณใช้ POST อยู่แล้วอาจเป็นปัญหาได้

นอกจากนี้สำหรับชุดข้อมูลขนาดใหญ่จะมีค่าน้อยกว่าที่เหมาะสม การส่งผ่านสตริงไม่ใช่เรื่องใหญ่ แต่สำหรับอาร์เรย์และออบเจ็กต์ของข้อมูลคุณควรใช้ Web Storage หรือคุกกี้ แม้ว่ารายละเอียดจะแตกต่างกันเล็กน้อยในแต่ละเบราว์เซอร์ แต่ขีด จำกัด ของความยาว URI ในทางปฏิบัติคือประมาณ2,000 อักขระ


ที่เก็บข้อมูลบนเว็บ

ด้วยการแนะนำ HTML5 เรายังมี Web Storage ซึ่งช่วยให้คุณสามารถบันทึกข้อมูลในเบราว์เซอร์ในการโหลดหน้าเว็บ นอกจากนี้localStorageที่สามารถบันทึกข้อมูลเป็นระยะเวลานาน (ตราบเท่าที่ผู้ใช้ไม่ได้ด้วยตนเองล้างมัน) และsessionStorageซึ่งบันทึกข้อมูลเฉพาะในช่วงเซสชันการเรียกดูของคุณในปัจจุบัน ข้อนี้มีประโยชน์สำหรับคุณที่นี่เนื่องจากคุณไม่ต้องการให้ "คลิก" ตั้งค่าเป็นจริงเมื่อผู้ใช้กลับมาในภายหลัง

ที่นี่ฉันตั้งค่าที่เก็บข้อมูลในเหตุการณ์การคลิกปุ่ม แต่คุณสามารถผูกไว้กับแบบฟอร์มส่งหรืออย่างอื่นได้

$('input[type="submit"][value="Search"]').click(function() {
    sessionStorage.setItem('clicked', 'true');
});

จากนั้นเมื่อคุณโหลดหน้าเว็บคุณสามารถตรวจสอบว่าได้ตั้งค่าไว้หรือไม่โดยใช้สิ่งนี้

var clicked = sessionStorage.getItem('clicked');

แม้ว่าค่านี้จะถูกบันทึกเฉพาะในช่วงการเรียกดูนี้ แต่คุณอาจต้องการรีเซ็ตก่อนหน้านี้ โดยใช้:

sessionStorage.removeItem('clicked');

หากคุณต้องการบันทึกออบเจ็กต์ JS หรืออาร์เรย์คุณควรแปลงเป็นสตริง ตามข้อกำหนดควรเป็นไปได้ที่จะบันทึกประเภทข้อมูลอื่น ๆ แต่ยังไม่สามารถใช้งานได้อย่างถูกต้องในเบราว์เซอร์

//set
localStorage.setItem('myObject', JSON.stringify(myObject));

//get
var myObject = JSON.parse(localStorage.getItem('myObject'));

การรองรับเบราว์เซอร์ค่อนข้างดีดังนั้นคุณควรใช้สิ่งนี้อย่างปลอดภัยเว้นแต่คุณจะต้องรองรับเบราว์เซอร์ที่เก่า / คลุมเครือจริงๆ Web Storage คืออนาคต


คุ้กกี้

อีกทางเลือกหนึ่งของ Web Storage คือการบันทึกข้อมูลในคุกกี้ คุกกี้ส่วนใหญ่สร้างขึ้นเพื่ออ่านข้อมูลฝั่งเซิร์ฟเวอร์ แต่สามารถใช้สำหรับข้อมูลฝั่งไคลเอ็นต์ได้เช่นกัน

คุณใช้ jQuery อยู่แล้วซึ่งทำให้การตั้งค่าคุกกี้ค่อนข้างง่าย อีกครั้งฉันใช้clickเหตุการณ์ที่นี่ แต่สามารถใช้ได้ทุกที่

$('input[type="submit"][value="Search"]').click(function() {
    $.cookie('clicked', 'true', {expires: 1}); // expires in 1 day
});

จากนั้นในการโหลดหน้าเว็บคุณสามารถอ่านคุกกี้ได้ดังนี้:

var clicked = $.cookie('clicked');

เนื่องจากคุกกี้ยังคงมีอยู่ในเซสชันในกรณีของคุณคุณจะต้องยกเลิกการตั้งค่าทันทีที่คุณทำสิ่งที่คุณต้องการทำกับมัน คุณคงไม่ต้องการให้ผู้ใช้กลับมาในวันต่อมาและยังคงclickedตั้งค่าเป็นจริง

if(clicked === "true") {
    //doYourStuff();
    $.cookie('clicked', null);
}

(วิธีที่ไม่ใช่ jQuery ในการตั้งค่า / อ่านคุกกี้สามารถพบได้ที่นี่ )

โดยส่วนตัวแล้วฉันจะไม่ใช้คุกกี้เพื่ออะไรง่ายๆอย่างการจำสถานะที่ถูกคลิก แต่ถ้าสตริงการสืบค้นไม่ใช่ตัวเลือกและคุณต้องรองรับเบราว์เซอร์รุ่นเก่าที่ไม่รองรับ sessionStorage สิ่งนี้จะใช้ได้ คุณควรใช้สิ่งนั้นด้วยการตรวจสอบ sessionStorage ก่อนและเฉพาะในกรณีที่ล้มเหลวให้ใช้วิธีการคุกกี้


window.name

แม้ว่านี่จะดูเหมือนเป็นการแฮ็กสำหรับฉันที่อาจเกิดขึ้นก่อน localStorage / sessionStorage คุณสามารถจัดเก็บข้อมูลในwindow.nameคุณสมบัติ:

window.name = "my value"

สามารถจัดเก็บสตริงได้เท่านั้นดังนั้นหากคุณต้องการบันทึกอ็อบเจ็กต์คุณจะต้องสตริงมันเหมือนกับlocalStorageตัวอย่างด้านบน:

window.name = JSON.stringify({ clicked: true });

ความแตกต่างที่สำคัญคือข้อมูลนี้จะถูกเก็บรักษาไว้ไม่เพียง แต่การรีเฟรชหน้าเท่านั้น แต่ยังรวมถึงโดเมนต่างๆด้วย อย่างไรก็ตามมันถูก จำกัด ไว้เฉพาะแท็บปัจจุบันที่คุณอยู่

ซึ่งหมายความว่าคุณสามารถบันทึกข้อมูลบางอย่างในเพจของคุณได้และตราบเท่าที่ผู้ใช้ยังคงอยู่ในแท็บนั้นคุณจะสามารถเข้าถึงข้อมูลเดียวกันนั้นได้แม้ว่าเขาจะเรียกดูเว็บไซต์อื่นและย้อนกลับก็ตาม โดยทั่วไปฉันจะแนะนำให้ใช้สิ่งนี้เว้นแต่คุณจะต้องจัดเก็บข้อมูลข้ามโดเมนในระหว่างการเรียกดูครั้งเดียว


9
ฮึหลังจากเขียนแล้วฉันได้อ่านคำอธิบายรางวัลของคุณที่ระบุว่า "ไม่มีคุกกี้หรือพื้นที่เก็บข้อมูลในเครื่อง" ฉันจะเก็บความคิดเห็นนี้ไว้เหมือนเดิมสำหรับคนอื่น ๆ ที่อาจต้องการ แต่คุณจะต้องใช้สตริงข้อความค้นหาที่ฉันเดา
Stephan Muller

1
โดยทั่วไปฉันใช้ localStorage ในหลาย ๆ กรณีสำหรับเว็บแอปพลิเคชันของฉันอยู่แล้วและฉันต้องการหลีกเลี่ยงการใช้ตัวแปร localStorage มากเกินไป อย่างไรก็ตามฉันชอบความคิดในการลบรายการ localStorage เมื่อฉันทำเสร็จแล้ว นั่นคือสิ่งที่ฉันไม่คิดเมื่อใช้ตัวแปร localStorage ของฉัน
Neophile

3
ในกรณีของคำขอโพสต์คุณสามารถแก้ไขการดำเนินการ -attribute $ ("# formid"). attr ("action", url + "& clicked = 1") และตรวจพบ GET หรือ POST จาก $ ("# formid"). attr ( "method") แต่ไม่สามารถแก้ปัญหาในการตรวจหาปัญหาการโหลดซ้ำได้
Tero Tolonen

2
@TheNewbie เป็นเวลานานแล้วที่ฉันเขียนคำตอบนี้ แต่ฉันเพิ่งเพิ่มตัวเลือกใหม่ ( window.name) มันอาจทำในสิ่งที่คุณต้องการโดยไม่ต้องใช้คุกกี้ / localStorage
Stephan Muller

1
ฉันต้องการเพิ่มพื้นที่จัดเก็บข้อมูลในเครื่องและเซสชันไม่น่าเชื่อถือโดยสิ้นเชิงในเบราว์เซอร์รุ่นใหม่ โดยปกติจะมีทางเลือกกลับไปที่ window.name
JavaScript

5

ลองใช้$.holdReady(),history

function show() {
  return $("form input[type=hidden]")
          .replaceWith(function(i, el) {
            return "<input type=text>"
          });
}

$.holdReady(true);
    if (history.state !== null && history.state.clicked === true) {
       // show hidden fields
       // if `history.state.clicked === true` ,
       // replace `input type=hidden` with `input type=text`
       show();
       console.log(history);

    } else {
        // don't show hidden fields
        console.log(history);
    }
$.holdReady(false);

  $(document).ready(function() {

    $("input[type=submit][value=Search]")
    .on("click", function(e) {
        e.preventDefault();
        if (history.state === null) {
          // do stuff
          history.pushState({"clicked":true});
          // replace `input type=hidden` with `input type=text`
          show();
          console.log(history);
        } else {
          // do other stuff
        };
    });

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="POST">
    <input type="text" name="name" value="" />
    <input type="submit" value="Search" />
    <input type="hidden" />
    <input type="hidden" />
</form>


1

ใช้localeStorageหรือsessionStorageดูเหมือนจะเป็นทางออกที่ดีที่สุด

การบันทึกclickedตัวแปรในขอบเขต globle เก็บไว้ในลักษณะนี้:

if(localeStorage.getItem("clicked") === null)
    localeStorage.setItem("clicked", "FALSE"); // for the first time

$(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch';return true;");

    var clicked = localeStorage.getItem("clicked") == "FALSE" ? "TRUE" : "FALSE";

    localeStorage.setItem("clicked", clicked);

    if (clicked == "TRUE") {
      // show hidden fields
    } else {
      // don't show hidden fields
    }

});

ฉันตั้งใจที่จะไม่ใช้ localstorage หรือ sessionStorage โดยเฉพาะอย่างยิ่ง
Neophile

-5

คุณสามารถลองสิ่งนี้:

 $("input[type='submit'][value='Search']").click(function(){
     form.act.value='detailSearch'; 
     clicked = true;  
     return true;
});

เมื่อเพจโหลดซ้ำยังคงได้รับค่าที่คลิกเป็นเท็จ
Neophile

1
@TheNewbie คุณคิดว่าคุณสามารถส่งข้อความค้นหาได้หรือไม่? ด้วยการรีเฟรชหน้าวิธีการปัจจุบันจะไม่ทำงาน
renakre
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.