jQuery / Method / .load()

jQuery의 .load(url, 완료함수)는 서버에서 HTML을 비동기로 가져와 선택한 요소의 내부 내용을 바꿉니다. .load("fragment.html #card", 완료함수)처럼 URL 뒤에 공백과 선택자를 붙이면 응답의 해당 부분만 넣습니다. 요청을 보낸 다음 줄에서 결과가 이미 도착했다고 가정하지 말고 완료함수 안에서 처리합니다.

HTML 로드의 대상·반환값·준비 사항

.load() 공식 문서의 대상은 응답을 넣을 기존 요소입니다. 대상 자체는 유지되고 안쪽 내용이 대체됩니다. 대상 선택이 비어 있으면 요청도 보내지 않습니다. 반환값은 기존 jQuery 객체이며 요청 객체인 jqXHR이나 완료된 HTML 문자열이 아닙니다.

예제에는 jQuery의 Ajax 모듈이 필요합니다. 공식 다운로드의 전체 파일을 사용하고 Ajax가 빠진 slim 파일로 바꾸지 않습니다. Ajax는 페이지 전체를 다시 열지 않고 서버와 통신하는 방식입니다. HTML을 가져오는 .load(url)는 오래된 이미지 load 이벤트 단축 메서드와 구분합니다.

다음 파일 두 개를 같은 새 연습 폴더에 만듭니다. 브라우저에서 파일을 더블클릭한 file:// 주소 대신 HTTP 서버로 엽니다. 동일 출처 정책은 스킴·호스트·포트를 기준으로 하므로 이 예제는 두 파일을 같은 서버에서 제공합니다. localhost와 127.0.0.1, 다른 포트도 임의로 섞지 않습니다.

두 파일로 만드는 전체 예제

먼저 UTF-8의 fragment.html을 만듭니다. #card와 그 바깥 문단을 구분했고, 무해한 스크립트는 실행 횟수만 셉니다. 외부에서 가져온 임의의 코드를 시험용으로 넣지 않습니다.

<section id="card">
  <h2>Local fragment</h2>
  <p>This card came from fragment.html.</p>
  <button type="button" class="fragment-action">Count a delegated click</button>
</section>
<p id="outside">Outside the selected card</p>
<script>window.fragmentRuns = (window.fragmentRuns || 0) + 1;</script>

같은 폴더에 load-demo.html을 저장합니다. 원격 파일에서 가져오는 콘텐츠를 넣을 #panel은 미리 존재합니다. 버튼 중복 실행과 요청 중 초기화를 막기 위해 요청이 끝날 때까지 조작부를 비활성화합니다. 완료 콜백의 this는 내용이 들어간 각 대상 요소를 가리킵니다.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Load local HTML into a target</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button { font: inherit; margin: 4px; max-width: 100%; }
    #panel { padding: 12px; border: 1px solid teal; min-height: 60px; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Load a complete response or selected fragment</h1>
  <button type="button" id="selected">Load #card only</button>
  <button type="button" id="whole">Load whole fragment</button>
  <button type="button" id="error">Request missing file</button>
  <button type="button" id="reset">Reset</button>
  <div id="panel">Initial content</div>
  <p id="clicks">delegated clicks=0</p>
  <pre id="status" aria-live="polite">Ready</pre>
  <script>
    $(function () {
      let busy = false, clicks = 0;
      window.fragmentRuns = 0;
      function load(url) {
        if (busy) return;
        busy = true;
        $("#selected, #whole, #error, #reset").prop("disabled", true);
        $("#status").text("Loading...");
        $("#panel").load(url, function (response, textStatus, xhr) {
          if (textStatus === "error") $(this).text("Load failed; try again.");
          $("#status").text(`status=${textStatus}; HTTP=${xhr.status}\nscript runs=${window.fragmentRuns}`);
          busy = false;
          $("#selected, #whole, #error, #reset").prop("disabled", false);
        });
      }
      $("#selected").on("click", function () { load("fragment.html #card"); });
      $("#whole").on("click", function () { load("fragment.html"); });
      $("#error").on("click", function () { load("missing-fragment.html"); });
      $("#panel").on("click.loadLesson", ".fragment-action", function () { clicks++; $("#clicks").text(`delegated clicks=${clicks}`); });
      $("#reset").on("click", function () {
        $("#panel").text("Initial content"); window.fragmentRuns = 0; clicks = 0;
        $("#clicks").text("delegated clicks=0"); $("#status").text("Ready");
      });
    });
  </script>
</body>
</html>

아직 요청하지 않은 초기 상태의 출력은 다음과 같습니다.

Ready

Python 3가 설치된 환경에서 터미널의 현재 폴더를 두 파일이 있는 연습 폴더로 맞추고 다음 명령을 실행합니다. python을 찾지 못하면 Python 설치·실행 경로를 먼저 확인합니다. 포트가 사용 중이면 8001처럼 다른 포트로 바꾸고 브라우저 주소도 함께 바꿉니다.

python -m http.server 8000 --bind 127.0.0.1

서버를 켠 상태에서 http://127.0.0.1:8000/load-demo.html로 접속합니다. jQuery 파일은 인터넷의 CDN(Content Delivery Network, 콘텐츠 전송망)에서 읽으므로 인터넷 연결도 필요합니다. 연습이 끝나면 해당 터미널에서 Ctrl+C로 서버를 종료합니다. 예제는 3.7.1·4.0.0, Windows Edge와 Python http.server에서 실행했으며 검증용 포트만 빈 포트로 바꿨습니다.

일부·전체·실패를 순서대로 비교하기

  1. Load #card only를 누르면 제목 Local fragment와 카드만 들어옵니다. status=success; HTTP=200, script runs=0입니다. #card 바깥 문단은 들어오지 않습니다.
  2. 카드 안의 Count a delegated click을 누르면 delegated clicks가 늘어납니다. 부모 #panel에 한 번 등록한 처리기가 새 콘텐츠에도 적용됩니다.
  3. Load whole fragment는 카드와 바깥 문단을 모두 넣고 script runs를 1 늘립니다. 뒤에서 설명하는 스크립트 처리 차이입니다.
  4. Request missing file은 없는 파일에 요청해 status=error; HTTP=404가 됩니다. 예제는 오류 응답 HTML 대신 고정된 실패 문구를 .text()로 표시합니다.
  5. 실패 후 Load #card only를 다시 누르면 정상 카드를 가져옵니다. Reset은 초기 내용과 카운터로 되돌립니다. 다시 로드해도 위임 처리기를 추가 등록하지 않습니다.

"fragment.html #card"의 공백 뒤는 jQuery가 응답에서 고르는 선택자입니다. "fragment.html#card"처럼 붙이는 URL 해시와 다르며, #card 요소 자체와 자식이 #panel 안에 들어갑니다. 선택자를 붙여도 서버에서 HTML 전체를 받은 뒤 브라우저에서 고르는 것이므로 다운로드 양까지 자동으로 줄지는 않습니다. 선택자에 맞는 내용이 없으면 HTTP 요청은 성공해도 넣을 내용은 비어 있을 수 있습니다.

스크립트·이벤트와 GET·POST 주의점

공식 문서는 선택자 없는 로드에서 HTML 처리 중 스크립트가 실행될 수 있고, 선택자를 덧붙이면 삽입 전에 스크립트 블록을 제거한다고 설명합니다. 예제의 두 버튼은 그 차이를 카운터로 확인합니다. 이 제거를 모든 위험한 HTML을 안전하게 정제한다는 보장으로 해석하지 않습니다. 신뢰할 수 있는 HTML만 넣고 초기화 코드는 완료 콜백이나 명시적인 함수로 관리합니다.

기존 자식에 직접 등록한 처리기는 내용을 바꾼 뒤 새 자식으로 자동 이전되지 않습니다. 예제는 유지되는 #panel에 위임 이벤트를 두었습니다. 여러 대상에 같은 id가 있는 HTML을 반복 삽입하면 중복 id가 생기므로 실제 템플릿의 클래스·id도 검토합니다. 완료 콜백은 대상 요소마다 실행되므로 다중 대상에서 전역 작업이 중복되지 않게 합니다.

data를 객체로 전달하면 .load()는 POST를 사용하고, 그렇지 않으면 GET을 사용합니다. 이 연습의 Python 정적 서버는 HTML GET 확인용이며 POST 처리용 백엔드가 아닙니다. 서버가 받을 방식을 확인하지 않고 객체 인수만 추가하지 않습니다. 응답은 HTML 삽입용이며 JSON 자료를 분석하려는 작업과도 구분합니다.

완료 전에 결과를 읽거나 요청이 안 될 때

개발자 도구 Network에서 실제 요청, 상태 코드와 응답을 확인합니다. .load() 뒤에서 바로 #panel을 읽으면 이전 내용을 볼 수 있으므로 삽입 이후 작업은 완료 콜백 안에 둡니다. 상대 URL은 현재 페이지 위치를 기준으로 요청하므로 폴더 구조와 서버 주소를 함께 확인합니다.

요청 자체가 없다면 대상 .length, jQuery 전체 파일과 스크립트 오류를 확인합니다. 다른 출처는 서버의 적절한 교차 출처 허용 설정이 필요할 수 있으며 브라우저 보안을 끄는 방식으로 해결하지 않습니다. 취소·타임아웃·세밀한 요청 제어가 필요하면 요청 객체를 돌려주는 jQuery.ajax()를 선택합니다. .load() 반환값에 .abort()가 있을 것으로 기대하지 않습니다.