使用按钮单击和文本框加载 JSON 数据

Posted

技术标签:

【中文标题】使用按钮单击和文本框加载 JSON 数据【英文标题】:Loading JSON data with button click and textbox 【发布时间】:2021-05-20 22:47:12 【问题描述】:

所以我正在学习 javascript,我正在尝试创建一个电影数据库,用户在其中输入一个文本框中的电影 ID,然后单击“加载电影按钮”,该按钮加载有关具有该特定 ID 的电影的信息。

我收到了一个 json 文件,其中包含电影的元素,例如 id、标题、发行日期等。我无法将点击处理程序添加到我的电影请求按钮,该按钮创建一个 XMLHttpRequest 对象并提交一个对特定电影的“GET”请求。如果此请求成功,我的回调函数中可用的响应文本将是一个 JSON 字符串,其中包含以下格式的电影信息。所以在控制台中它会打印出来:


  "Title": "Guardians of the Galaxy Vol. 2",
  "Year": "2017",
  "Rated": "PG-13",
  "Released": "05 May 2017",
  "Runtime": "136 min",
  "imdbID": "tt3896198",
  "Response": "True"

它应该只在加载的 html 页面中将标题和运行时打印为常规文本,因为这就是我在 javascript 文件中要求的内容。

为简单起见,此 json 文件仅包含 1 部电影,但我的原始 json 文件将包含数千部电影的信息,因此当我搜索特定电影 id 时,它应该只加载一部电影的信息,而不是所有电影的信息json 文件中的电影。所以如果我在文本框中输入“tt3896198”,这个id应该会加载电影“银河护卫队2”的数据,因为这是与这部电影匹配的id,如json文件所示。

我尝试查找如何使用 XMLHttpRequests 和 JSON 解析从 json 文件中打印特定信息,但问题是我在网上看到的示例能够通过执行“movie.title”之类的操作来访问其 json 文件中的变量,因为他们的变量是小写的。我的 JSON 文件中的所有变量似乎都是大写的,我认为不允许使用 movie.Title。

另外,我想知道如何根据用户输入的 id 加载电影?有 1000 部具有唯一 id 的电影,我不知道如何只加载一部 id 与文本框中输入的 id 匹配的电影。

现在我的页面只显示一个文本框和一个按钮,但按钮不起作用。任何帮助将不胜感激,当我单击按钮时,我主要是从 json 文件中获取数据以显示在控制台和 HTML 页面上。如果有人可以帮助或指导我让电影 id 元素正常工作,那也将不胜感激!

电影.html:

<html>
    <head>
        <title>Movies page</title>
    </head>

    <body onload="init()">
        <div>
            <input type="text" placeholder="Search" name="textbox">
            <button type="button" id="retrieveMovies">Load a movie</button>
        </div>
        <br />
        <div id="moviediv">

        </div>

    <script src="movies.js"></script>
    </body>

</html>

movie.js:

let movies = [];

function init()
    document.getElementById("retrieveMovies").onclick = loadMovies;
    loadMovies();


function loadMovies()
    let xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() 
        if (this.readyState == 4 && this.status == 200) 
            let responseObject = JSON.parse(xhttp.responseText);
            movies = responseObject.results;
            render();
        
    ;

    xhttp.open("GET", "movie.json", true);
    xhttp.send();


function render()
    let content = "";
    movies.forEach(movie =>
        content += `
            <div>
                <p> Movie: $movie.Title</p>
                <br/>
                <p> Runtime: $movie.Runtime</p>
            </div>
        `
    )
    document.getElementById("moviediv").innerHTML = content;

movie.json:

"Title":"Guardians of the Galaxy Vol. 2","Year":"2017","Rated":"PG-13","Released":"05 May 2017","Runtime":"136 min","imdbID":"tt3896198","Response":"True"

更新:所以我尝试创建一个服务器来运行应用程序,而不是直接从我的目录中打开 html 文件。

server.js:

const http = require('http');
const fs = require('fs');

const server = http.createServer(function (request, response) 
    if(request.method === "GET" && (request.url === "/index.html" || request.url === "/"))
        fs.readFile('index.html', 'utf8', function(err, contents) 
            if(err)
                response.writeHead(500,  "Content-Type": "text/html")
                response.end();
                return;
            
            response.writeHead(200,  "Content-Type": "text/html")
            response.end(contents);
        );
    else if(request.method === "GET" && request.url === "/style.css")
        fs.readFile('style.css', 'utf8', function(err, contents) 
            if(err)
                response.writeHead(500,  "Content-Type": "text/css")
                response.end();
                return;
            
            response.writeHead(200,  "Content-Type": "text/css")
            response.end(contents);
        );
    else if(request.method === "GET" && request.url === "/movies.js")
        fs.readFile('movies.js', 'utf8', function(err, contents) 
            if(err)
                response.writeHead(500,  "Content-Type": "application/javascript")
                response.end();
                return;
            
            response.writeHead(200,  "Content-Type": "application/javascript")
            response.end(contents);
        );
    
);

server.listen(3000);
console.log('Server running at http://127.0.0.1:3000/');

我在我的谷歌浏览器中输入 localhost:3000,它会引导我进入 html 页面。虽然这解决了我之前遇到的错误,但单击添加按钮似乎仍然没有任何反应。

【问题讨论】:

【参考方案1】:

确保在调用init 之前加载您的movies.js 文件。我会将脚本包含在&lt;head&gt; 中,并立即将init 事件作为DOMContentLoaded 事件的回调添加到document

注意:还应使用“kebob-case”与“camelCase”作为 id 和类选择器名称。

index.html

将您的输入封装在一个表单中并监听submit 事件。确保您可以访问您的查询词,例如IMDB ID。我预加载了"tt3896198",以便初始提取将基于它进行过滤。如果删除文本,则不会过滤任何内容。如果有一个术语,它将对其进行过滤。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Movies page</title>
    <link rel="stylesheet" href="style.css">
    <script type="text/javascript" src="movies.js"></script>
    <script type="text/javascript">
      document.addEventListener('DOMContentLoaded', init);
    </script>
  </head>
  <body>
    <form name="movie-search" onsubmit="return false">
      <input type="text" id="query" name="query" placeholder="Search" value="tt3896198" />
      <button id="retrieve-movies">Load a movie</button>
    </form>
    <br />
    <div id="movie-results"></div>
  </body>
</html>

movies.js

使用fetch 而不是XMLHttpRequest 加载电影。监听表单的submit 事件并确保在 HTML 中返回 false,以避免服务器端提交/重定向。我还将变量存储在上下文数据结构中。这使得代码更容易理解。

const context = 
  elements: 
    searchForm: null,
    results: null
  ,
  movies: []
;

const init = () => 
  Object.assign(context.elements, 
    searchForm: document.forms['movie-search'],
    results: document.querySelector("#movie-results")
  );

  context.elements.searchForm.addEventListener('submit', loadMovies);
  loadMovies();
;

const loadMovies = () => 
  fetch("movies.json")
      .then(response => response.json())
      .then(onLoad);
;

const onLoad = (movies) => 
  const query = context.elements.searchForm.elements.query.value.trim();
  context.movies = query ? movies.filter(( imdbID ) => imdbID === query) : movies;
  render();
;

const render = () => 
  context.elements.results.innerHTML = context.movies.map(renderMovie).join('');
;

const renderMovie = (movie) => 
  const  imdbID, Rated, Released, Runtime, Title, Year  = movie;
  return `
    <div class="movie">
      <h2>$Title ($Year)</h2>
      <p>$Rated | $formatRuntime(Runtime) | $Released</p>
      <p><strong>IMDb ID:</strong> $imdbID</p>
    </div>
  `
;

const formatRuntime = (runtime) => 
  const
    [, mins] = runtime.match(/^(\d+) min$/),
    hours = Math.floor(mins / 60),
    minutes = mins % 60;
  return [ hours, minutes ].map(t => ('' + t).padStart(2, '0')).join(':');
;

style.css

将您的结果设置为卡片的网格列。

#movie-results 
  display: grid;
  grid-auto-flow: row;
  justify-content: center;
  align-items: center;


.movie 
  border : thin solid grey;
  padding: 0.5em;
  margin: 0.25em 0;

movies.json

这应该是一个对象数组。

[
  
    "Title": "Guardians of the Galaxy",
    "Year": "2014",
    "Rated": "PG-13",
    "Released": "01 August 2014",
    "Runtime": "121 min",
    "imdbID": "tt2015381",
    "Response": "True"
  ,
  
    "Title": "Guardians of the Galaxy Vol. 2",
    "Year": "2017",
    "Rated": "PG-13",
    "Released": "05 May 2017",
    "Runtime": "136 min",
    "imdbID": "tt3896198",
    "Response": "True"
  
]

【讨论】:

您好,感谢您的帮助!我尝试运行您发布的代码,而“tt3896198”自动出现在文本框中,当我单击加载电影按钮时,我的控制台或 html 浏览器中似乎没有发生任何事情。我假设单击按钮后电影标题和运行时会显示在 html 页面中,但页面保持空白。 我也仔细检查了文件名,我不确定我错过了什么。 @Grayish 确保您的 HTML 类和 id 匹配。我更新了这个回复以包含不止一部电影。如果您将该字段留空,则将加载所有电影,但如果您选择特定 ID,则应仅显示该电影。确保您的 JSON 文件已加载到开发人员选项卡 (F12) 中。在页面加载时以及每次单击按钮时检查您正在加载的文件的 XHR 请求。 所以我使用 F12 检查了文件,每次单击按钮时都会出现错误:movies.js:20 Fetch API cannot load file:///C:/Users/Downloads/电影数据库/movies.json。对于 CORS 请求,URL 方案必须是“http”或“https”。从网上看,我认为这是因为我直接从我的目录中打开了 html 文件。有没有办法防止这种情况?到目前为止,这就是我学会测试我的 html 文件的方式。 @Grayish 如果不禁用安全功能,您将无法在浏览器中加载本地文件。您需要使用 Apache 等 Web 服务器运行索引文件,或在公共网站上托管 JSON。

以上是关于使用按钮单击和文本框加载 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

在按钮单击时附加 JSON 值

在按钮单击文本框值是空的使用 asp.net mvc 显示警报?

JAVA 文本框单击清空

用户单击删除按钮时如何删除动态控件(文本框和按钮)

编写程序界面中包括一个标签、一个文本框和一个按钮。当用户单击按钮时,程序把文本框的内容复制到标签中

通过单击按钮将数据从 Access 获取到 C# 中的文本框