Build a JavaScript Single Page App Without a Framework - SitePoint

前端框架很棒。它们抽象出构建单页应用程序 (SPA) 的大部分复杂性,并帮助您随着项目的发展以一种可理解的方式组织代码。

然而,也有不利的一面:这些框架会带来一定程度的开销,并且可能会引入它们自己的复杂性。

这就是为什么在本教程中,我们将学习如何在不使用客户端 JavaScript 框架的情况下从头开始构建 SPA。这将帮助您评估这些框架实际上为您做了什么,以及在什么时候使用它们是有意义的。它还将让您了解构成典型 SPA 的各个部分以及它们是如何连接在一起的。

让我们开始吧 …

先决条件

对于本教程,您需要具备现代 JavaScript和jQuery的基础知识。一些使用Handlebars、Express和Axios的经验会派上用场,尽管这不是绝对必要的。您还需要在您的环境中进行以下设置:

  • 节点.js
  • 适用于 Window 用户的Git或Git Bash。

您可以在我们的GitHub 存储库中找到已完成的项目。

构建项目

我们将构建一个简单的货币应用程序,它将提供以下功能:

  • 显示最新汇率
  • 从一种货币转换为另一种货币
  • 根据指定日期显示过去的货币汇率。

我们将使用以下免费的在线 REST API 来实现这些功能:

  • fixer.io API
  • 免费货币转换器 API。

Fixer 是一个完善的 API,提供外汇和货币转换 JSON API。不幸的是,这是一项商业服务,免费计划不允许货币兑换。所以我们还需要使用免费货币转换器 API。转换 API 有一些限制,幸运的是不会影响我们应用程序的功能。无需 API 密钥即可直接访问。但是,Fixer 需要 API 密钥来执行任何请求。只需在他们的网站上注册即可获得免费计划的访问密钥。

理想情况下,我们应该能够在客户端构建整个单页应用程序。但是,由于我们将处理敏感信息(我们的 API 密钥),因此无法将其存储在我们的客户端代码中。这样做会使我们的应用程序容易受到攻击,并且任何初级黑客都可以绕过该应用程序并直接从我们的 API 端点访问数据。为了保护此类敏感信息,我们需要将其放入服务器代码中。因此,我们将设置一个Express服务器来充当客户端代码和云服务之间的代理。通过使用代理,我们可以安全地访问此密钥,因为服务器代码永远不会暴露给浏览器。下图说明了我们完成的项目将如何工作。

记下每个环境将使用的 npm 包——即浏览器(客户端)和服务器。既然您知道我们将要构建什么,请转到下一部分开始创建项目。

项目目录和依赖项

前往您的工作区目录并创建文件夹single-page-application。在 VSCode 或您喜欢的编辑器中打开文件夹,然后使用终端创建以下文件和文件夹:

touch .env .gitignore README.md server.js
mkdir public lib
mkdir public/js
touch public/index.html
touch public/js/app.js

打开.gitignore并添加这些行:

node_modules
.env

打开README.md并添加这些行:

# Single Page ApplicationThis is a project demo that uses Vanilla JS to build a Single Page Application.

接下来,package.json通过在终端中执行以下命令来创建文件:

npm init -y

您应该获得为您生成的以下内容:

{"name": "single-page-application","version": "1.0.0","description": "This is a project demo that uses Vanilla JS to build a Single Page Application.","main": "server.js","directories": {"lib": "lib"},"scripts": {"test": "echo \"Error: no test specified\" && exit 1","start": "node server.js"},"keywords": [],"author": "","license": "ISC"
}

看看 npm 命令有多方便?内容是根据项目结构生成的。现在让我们安装项目所需的核心依赖项。在终端中执行以下命令:

npm install jquery semantic-ui-css handlebars vanilla-router express dotenv axios

软件包安装完成后,转到下一部分开始构建应用程序的基础。

应用基础

在我们开始编写前端代码之前,我们需要实现一个服务器-客户端基础来工作。这意味着从 Express 服务器提供的基本 HTML 视图。node_modules出于性能和可靠性的原因,我们将直接从文件夹中注入前端依赖项。我们必须以一种特殊的方式设置我们的 Express 服务器来完成这项工作。打开server.js并添加以下内容:

require('dotenv').config(); // read .env files
const express = require('express');const app = express();
const port = process.env.PORT || 3000;// Set public folder as root
app.use(express.static('public'));// Allow front-end access to node_modules folder
app.use('/scripts', express.static(`${__dirname}/node_modules/`));// Listen for HTTP requests on port 3000
app.listen(port, () => {console.log('listening on %d', port);
});

这为我们提供了一个基本的 Express 服务器。我已经评论了代码,所以希望这能让您对正在发生的事情有一个相当好的了解。接下来,打开public/index.html并输入:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><link rel="stylesheet" href="scripts/semantic-ui-css/semantic.min.css"><title>SPA Demo</title>
</head>
<body><div class="ui container"><!-- Navigation Menu --><div class="ui four item inverted orange menu"><div class="header item"><i class="money bill alternate outline icon"></i>Single Page App</div><a class="item" href="/">Currency Rates</a><a class="item" href="/exchange">Exchange Rates</a><a class="item" href="/historical">Historical Rates</a></div><!-- Application Root --><div id="app"></div></div><!-- JS Library Dependencies --><script src="scripts/jquery/dist/jquery.min.js"></script><script src="scripts/semantic-ui-css/semantic.min.js"></script><script src="scripts/axios/dist/axios.min.js"></script><script src="scripts/handlebars/dist/handlebars.min.js"></script><script src="scripts/vanilla-router/dist/vanilla-router.min.js"></script><script src="js/app.js"></script>
</body>
</html>

我们使用语义 UI 进行样式设置。请参阅语义 UI 菜单文档以了解用于我们导航栏的代码。转到您的终端并启动服务器:

npm start

在浏览器中打开localhost:3000 。您应该有一个空白页面,其中仅显示导航栏:

现在让我们为我们的应用程序编写一些视图模板。

前端骨架模板

我们将使用Handlebars来编写我们的模板。JavaScript 将用于根据当前 URL 呈现模板。我们将创建的第一个模板将用于显示错误消息,例如 404 或服务器错误。将此代码放在public/index.html导航部分之后:

<!-- Error Template -->
<script id="error-template" type="text/x-handlebars-template"><div class="ui {{color}} inverted segment" style="height:250px;"><br><h2 class="ui center aligned icon header"><i class="exclamation triangle icon"></i><div class="content">{{title}}<div class="sub header">{{message}}</div></div></h2></div>
</script>

接下来,添加以下模板,这些模板将代表我们在导航栏中指定的每个 URL 路径的视图:

<!-- Currency Rates Template -->
<script id="rates-template" type="text/x-handlebars-template"><h1 class="ui header">Currency Rates</h1><hr>
</script><!-- Exchange Conversion Template -->
<script id="exchange-template" type="text/x-handlebars-template"><h1 class="ui header">Exchange Conversion</h1><hr>
</script><!-- Historical Rates Template -->
<script id="historical-template" type="text/x-handlebars-template"><h1 class="ui header">Historical Rates</h1><hr>
</script>

接下来,让我们将所有这些模板编译到public/js/app.js. 编译后,我们将渲染rates-template并查看它的样子:

window.addEventListener('load', () => {const el = $('#app');// Compile Handlebar Templatesconst errorTemplate = Handlebars.compile($('#error-template').html());const ratesTemplate = Handlebars.compile($('#rates-template').html());const exchangeTemplate = Handlebars.compile($('#exchange-template').html());const historicalTemplate = Handlebars.compile($('#historical-template').html());const html = ratesTemplate();el.html(html);
});

请注意,我们将所有 JavaScript 客户端代码包装在一个load事件中。这只是为了确保所有依赖项都已加载并且 DOM 已完成加载。刷新页面,看看我们有什么:

我们正在取得进展。现在,如果您单击除Currency Rates之外的其他链接,浏览器将尝试获取新页面并最终显示如下消息Cannot GET /exchange

我们正在构建一个单页应用程序,这意味着所有操作都应该发生在一个页面中。我们需要一种方法来告诉浏览器在 URL 更改时停止获取新页面。

客户端路由

为了控制浏览器环境中的路由,我们需要实现客户端路由。有许多客户端路由库可以帮助解决这个问题。对于我们的项目,我们将使用vanilla router,这是一个非常易于使用的路由包。

如果你还记得,我们之前已经在index.html. 因此,我们可以立即调用Router该类。删除您添加的最后两个语句app.js并将它们替换为以下代码:

// Router Declaration
const router = new Router({mode: 'history',page404: (path) => {const html = errorTemplate({color: 'yellow',title: 'Error 404 - Page NOT Found!',message: `The path '/${path}' does not exist on this site`,});el.html(html);},
});router.add('/', () => {let html = ratesTemplate();el.html(html);
});router.add('/exchange', () => {let html = exchangeTemplate();el.html(html);
});router.add('/historical', () => {let html = historicalTemplate();el.html(html);
});// Navigate app to current url
router.navigateTo(window.location.pathname);// Highlight Active Menu on Refresh/Page Reload
const link = $(`a[href$='${window.location.pathname}']`);
link.addClass('active');$('a').on('click', (event) => {// Block browser page loadevent.preventDefault();// Highlight Active Menu on Clickconst target = $(event.target);$('.item').removeClass('active');target.addClass('active');// Navigate to clicked urlconst href = target.attr('href');const path = href.substr(href.lastIndexOf('/'));router.navigateTo(path);
});

花一些时间浏览代码。我在各个部分添加了评论来解释正在发生的事情。您会注意到,在路由器的声明中,我们指定了page404使用错误模板的属性。现在让我们测试链接:

链接现在应该可以工作了。但是我们有一个问题。单击/exchangehistorical链接,然后刷新浏览器。我们得到与以前相同的错误 - Cannot GET /exchange。要解决此问题,请转到server.js并在监听代码之前添加此语句:

// Redirect all traffic to index.html
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));

您必须使用Ctrl+C和执行重新启动服务器npm start。返回浏览器并尝试刷新。您现在应该可以看到页面正确呈现。现在,让我们尝试在 URL 中输入一个不存在的路径,例如/exchanges. 该应用程序应显示 404 错误消息:

我们现在已经实现了必要的代码来创建我们的单页应用程序框架。现在让我们开始列出最新的货币汇率。

最新货币汇率

对于这个任务,我们将使用Fixer Latest Rates Endpoint。打开.env文件并添加您的 API 密钥。我们还将指定超时期限和我们将在页面上列出的符号。如果您的互联网连接速度较慢,请随意增加超时值:

API_KEY=<paste key here>
PORT=3000
TIMEOUT=5000
SYMBOLS=EUR,USD,GBP,AUD,BTC,KES,JPY,CNY

接下来创建文件lib/fixer-service.js。在这里,我们将为我们的 Express 服务器编写帮助代码,以便轻松地从 Fixer 请求信息。复制以下代码:

require('dotenv').config();
const axios = require('axios');const symbols = process.env.SYMBOLS || 'EUR,USD,GBP';// Axios Client declaration
const api = axios.create({baseURL: 'http://data.fixer.io/api',params: {access_key: process.env.API_KEY,},timeout: process.env.TIMEOUT || 5000,
});// Generic GET request function
const get = async (url) => {const response = await api.get(url);const { data } = response;if (data.success) {return data;}throw new Error(data.error.type);
};module.exports = {getRates: () => get(`/latest&symbols=${symbols}&base=EUR`),
};

同样,花一些时间浏览代码以了解正在发生的事情。如果您不确定,您还可以查看dotenv、axios的文档并阅读模块导出。现在让我们进行快速测试以确认该getRates()功能是否正常工作。

打开server.js并添加以下代码:

const { getRates } = require('./lib/fixer-service');...
// Place this block at the bottom
const test = async() => {const data = await getRates();console.log(data);
}test();

运行npm startnode server。几秒钟后,您应该得到以下输出:

{success: true,timestamp: 1523871848,base: 'EUR',date: '2018-04-16',rates: {EUR: 1,USD: 1.23732,GBP: 0.865158,AUD: 1.59169,BTC: 0.000153,KES: 124.226892,JPY: 132.608498,CNY: 7.775567}
}

如果您得到与上述类似的内容,则表示代码正在运行。这些值当然会有所不同,因为费率每天都在变化。现在注释掉测试块并在将所有流量重定向到的语句之前插入此代码index.html

// Express Error handler
const errorHandler = (err, req, res) => {if (err.response) {// The request was made and the server responded with a status code// that falls out of the range of 2xxres.status(403).send({ title: 'Server responded with an error', message: err.message });} else if (err.request) {// The request was made but no response was receivedres.status(503).send({ title: 'Unable to communicate with server', message: err.message });} else {// Something happened in setting up the request that triggered an Errorres.status(500).send({ title: 'An unexpected error occurred', message: err.message });}
};// Fetch Latest Currency Rates
app.get('/api/rates', async (req, res) => {try {const data = await getRates();res.setHeader('Content-Type', 'application/json');res.send(data);} catch (error) {errorHandler(error, req, res);}
});

正如我们所看到的,有一个自定义错误处理函数,旨在处理可能在服务器代码执行期间发生的不同错误场景。发生错误时,会构造错误消息并将其发送回客户端。

让我们确认这段代码是否有效。重新启动 Express 服务器并将浏览器导航到此 URL:localhost:3000/api/rates。您应该会看到控制台中显示的相同 JSON 结果。我们现在可以实现一个视图,将这些信息显示在一个整洁、优雅的表格中。

打开public/index.htmlrates-template用以下代码替换:

<!-- Currency Rates Template -->
<script id="rates-template" type="text/x-handlebars-template"><h1 class="ui header">Currency Rates</h1><hr><div class="ui loading basic segment"><div class="ui horizontal list"><div class="item"><i class="calendar alternate outline icon"></i><div class="content"><div class="ui sub header">Date</div><span>{{date}}</span></div></div><div class="item"><i class="money bill alternate outline icon"></i><div class="content"><div class="ui sub header">Base</div><span>{{base}}</span></div></div></div><table class="ui celled striped selectable inverted table"><thead><tr><th>Code</th><th>Rate</th></tr></thead><tbody>{{#each rates}}<tr><td>{{@key}}</td><td>{{this}}</td></tr>{{/each}}</tbody></table></div>
</script>

请记住,我们使用语义 UI 为我们提供样式。我希望您密切关注Segment 加载组件。这将表明在应用程序获取数据时让用户知道正在发生某些事情。我们还使用Table UI来显示费率。如果您是 Semantic 的新手,请阅读链接文档。

现在让我们更新我们的代码public/js/app.js以使用这个新模板。用以下代码替换第一个route.add('/')函数:

// Instantiate api handler
const api = axios.create({baseURL: 'http://localhost:3000/api',timeout: 5000,
});// Display Error Banner
const showError = (error) => {const { title, message } = error.response.data;const html = errorTemplate({ color: 'red', title, message });el.html(html);
};// Display Latest Currency Rates
router.add('/', async () => {// Display loader firstlet html = ratesTemplate();el.html(html);try {// Load Currency Ratesconst response = await api.get('/rates');const { base, date, rates } = response.data;// Display Rates Tablehtml = ratesTemplate({ base, date, rates });el.html(html);} catch (error) {showError(error);} finally {// Remove loader status$('.loading').removeClass('loading');}
});

第一个代码块实例化了一个 API 客户端,用于与我们的代理服务器进行通信。第二个块是用于处理错误的全局函数。它的工作只是在服务器端出现问题时显示错误横幅。第三个块是我们从localhost:3000/api/rates端点获取费率数据并将其传递rates-template给显示信息的地方。

只需刷新浏览器。您现在应该有以下视图:

接下来我们将构建一个用于转换货币的界面。

兑换兑换

对于货币转换,我们将使用两个端点:

  • Fixer 的符号端点
  • 免费货币转换器端点。

我们需要符号端点来获取支持的货币代码列表。我们将使用这些数据来填充用户将用来选择要转换的货币的下拉列表。在函数后面打开lib/fixer-service.js并添加这一行getRates()

getSymbols: () => get('/symbols'),

创建另一个帮助文件 ,lib/free-currency-service.js并添加以下代码:

require('dotenv').config();
const axios = require('axios');const api = axios.create({baseURL: 'https://free.currencyconverterapi.com/api/v5',timeout: process.env.TIMEOUT || 5000,
});module.exports = {convertCurrency: async (from, to) => {const response = await api.get(`/convert?q=${from}_${to}&compact=y`);const key = Object.keys(response.data)[0];const { val } = response.data[key];return { rate: val };},
};

这将帮助我们免费获得从一种货币到另一种货币的兑换率。在客户端代码中,我们必须通过将金额乘以费率来计算转换金额。现在让我们将这两个服务方法添加到我们的 Express 服务器代码中。打开server.js并相应更新:

const { getRates, getSymbols, } = require('./lib/fixer-service');
const { convertCurrency } = require('./lib/free-currency-service');
...
// Insert right after get '/api/rates', just before the redirect statement// Fetch Symbols
app.get('/api/symbols', async (req, res) => {try {const data = await getSymbols();res.setHeader('Content-Type', 'application/json');res.send(data);} catch (error) {errorHandler(error, req, res);}
});// Convert Currency
app.post('/api/convert', async (req, res) => {try {const { from, to } = req.body;const data = await convertCurrency(from, to);res.setHeader('Content-Type', 'application/json');res.send(data);} catch (error) {errorHandler(error, req, res);}
});

现在我们的代理服务器应该能够获取符号和转换率。请注意,这/api/convert是一个 POST 方法。我们将在客户端使用一个表单来构建货币转换 UI。随意使用该test功能来确认两个端点都在工作。这是一个例子:

// Test Symbols Endpoint
const test = async() => {const data = await getSymbols();console.log(data);
}// Test Currency Conversion Endpoint
const test = async() => {const data = await convertCurrency('USD', 'KES');console.log(data);
}

您必须为每次测试重新启动服务器。一旦您确认代码到目前为止工作正常,请记住注释掉测试。现在让我们处理我们的货币转换 UI。通过将现有代码替换为以下代码来打开public/index.html并更新:exchange-template

<script id="exchange-template" type="text/x-handlebars-template"><h1 class="ui header">Exchange Rate</h1><hr><div class="ui basic loading segment"><form class="ui form"><div class="three fields"><div class="field"><label>From</label><select class="ui dropdown" name="from" id="from"><option value="">Select Currency</option>{{#each symbols}}<option value="{{@key}}">{{this}}</option>{{/each}}</select></div><div class="field"><label>To</label><select class="ui dropdown" name="to" id="to"><option value="">Select Currency</option>{{#each symbols}}<option value="{{@key}}">{{this}}</option>{{/each}}</select></div><div class="field"><label>Amount</label><input type="number" name="amount" id="amount" placeholder="Enter amount"></div></div><div class="ui primary submit button">Convert</div><div class="ui error message"></div></form><br><div id="result-segment" class="ui center aligned segment"><h2 id="result" class="ui header">0.00</h2></div></div>
</script>

花点时间阅读脚本并了解正在发生的事情。我们正在使用语义 UI 表单来构建界面。我们还使用 Handlebars 符号来填充下拉框。下面是 Fixer 的 Symbols 端点使用的 JSON 格式:

{"success": true,"symbols": {"AED": "United Arab Emirates Dirham","AFN": "Afghan Afghani","ALL": "Albanian Lek","AMD": "Armenian Dram",}
}

请注意,符号数据是地图格式。这意味着信息被存储为键值{{@key}}{{this}}。现在让我们更新public/js/app.js并使其与新模板一起使用。打开文件并将现有的路由代码替换为/exchange以下内容:

// Perform POST request, calculate and display conversion results
const getConversionResults = async () => {// Extract form dataconst from = $('#from').val();const to = $('#to').val();const amount = $('#amount').val();// Send post data to Express(proxy) servertry {const response = await api.post('/convert', { from, to });const { rate } = response.data;const result = rate * amount;$('#result').html(`${to} ${result}`);} catch (error) {showError(error);} finally {$('#result-segment').removeClass('loading');}
};// Handle Convert Button Click Event
const convertRatesHandler = () => {if ($('.ui.form').form('is valid')) {// hide error message$('.ui.error.message').hide();// Post to Express server$('#result-segment').addClass('loading');getConversionResults();// Prevent page from submitting to serverreturn false;}return true;
};router.add('/exchange', async () => {// Display loader firstlet html = exchangeTemplate();el.html(html);try {// Load Symbolsconst response = await api.get('/symbols');const { symbols } = response.data;html = exchangeTemplate({ symbols });el.html(html);$('.loading').removeClass('loading');// Validate Form Inputs$('.ui.form').form({fields: {from: 'empty',to: 'empty',amount: 'decimal',},});// Specify Submit Handler$('.submit').click(convertRatesHandler);} catch (error) {showError(error);}
});

刷新页面。您现在应该有以下视图:

选择您选择的一些货币并输入金额。然后点击转换按钮:

哎呀!我们刚刚遇到了一个错误场景。至少我们知道我们的错误处理代码是有效的。要找出错误发生的原因,请返回服务器代码并查看/api/convert函数。具体来说,请查看 const { from, to } = req.body;.

Express 似乎无法从request对象中读取属性。为了解决这个问题,我们需要安装可以帮助解决这个问题的中间件:

npm install body-parser

接下来,更新服务器代码如下:

const bodyParser = require('body-parser');
.../** Place this code right before the error handler function **/// Parse POST data as URL encoded data
app.use(bodyParser.urlencoded({extended: true,
}));// Parse POST data as JSON
app.use(bodyParser.json());

再次启动服务器并刷新浏览器。尝试进行另一次转换。它现在应该可以工作了。

现在让我们关注最后一点——历史货币汇率。让我们从视图开始。

历史货币汇率

实现此功能就像组合第一页和第二页中的任务。我们将构建一个小表单,用户需要在其中输入日期。当用户点击提交时,指定日期的汇率将以表格形式显示。我们将使用来自 Fixer API 的历史汇率端点来实现这一点。API 请求如下所示:

https://data.fixer.io/api/2013-12-24? access_key = API_KEY& base = GBP& symbols = USD,CAD,EUR

响应将如下所示:

{"success": true,"historical": true,"date": "2013-12-24","timestamp": 1387929599,"base": "GBP","rates": {"USD": 1.636492,"EUR": 1.196476,"CAD": 1.739516}
}

像这样打开lib/fixer-service.js和历史汇率端点:

.../** Place right after getSymbols **/getHistoricalRate: date => get(`/${date}&symbols=${symbols}&base=EUR`),
...

打开server.js并添加以下代码:

...
const { getRates, getSymbols, getHistoricalRate } = require('./lib/fixer-service');
...
/** Place this after '/api/convert' post function **/// Fetch Currency Rates by date
app.post('/api/historical', async (req, res) => {try {const { date } = req.body;const data = await getHistoricalRate(date);res.setHeader('Content-Type', 'application/json');res.send(data);} catch (error) {errorHandler(error, req, res);}
});
...

如果您对代码的排列方式有任何疑问,请参阅GitHub 上server.js的完整文件。随意编写一个快速测试来确认历史端点是否正常工作:

const test = async() => {const data = await getHistoricalRate('2012-07-14');console.log(data);
}test();

确认一切正常后,请记住注释掉测试块。现在让我们处理客户端代码。

打开index.html. 删除historical-template我们用作占位符的现有内容,并将其替换为以下内容:

<script id="historical-template" type="text/x-handlebars-template"><h1 class="ui header">Historical Rates</h1><hr><form class="ui form"><div class="field"><label>Pick Date</label><div class="ui calendar" id="calendar"><div class="ui input left icon"><i class="calendar icon"></i><input type="text" placeholder="Date" id="date"></div></div></div><div class="ui primary submit button">Fetch Rates</div><div class="ui error message"></div></form><div class="ui basic segment"><div id="historical-table"></div></div>
</script>

先看一下表格。我想指出的一件事是语义 UI 没有正式的日期输入。然而,感谢Michael de Hoog的贡献,我们可以使用Semantic-UI-Calendar模块。只需使用 npm 安装它:

npm install semantic-ui-calendar

返回public/index.html并将其包含在脚本部分中:

...
<script src="scripts/semantic-ui-css/semantic.min.js"></script>
<script src="scripts/semantic-ui-calendar/dist/calendar.min.js"></script>
....

为了显示历史汇率,我们将简单地重复使用rates-template. 接下来打开public/js/app.js并更新现有的路线代码/historical

const getHistoricalRates = async () => {const date = $('#date').val();try {const response = await api.post('/historical', { date });const { base, rates } = response.data;const html = ratesTemplate({ base, date, rates });$('#historical-table').html(html);} catch (error) {showError(error);} finally {$('.segment').removeClass('loading');}
};const historicalRatesHandler = () => {if ($('.ui.form').form('is valid')) {// hide error message$('.ui.error.message').hide();// Indicate loading status$('.segment').addClass('loading');getHistoricalRates();// Prevent page from submitting to serverreturn false;}return true;
};router.add('/historical', () => {// Display formconst html = historicalTemplate();el.html(html);// Activate Date Picker$('#calendar').calendar({type: 'date',formatter: { //format date to yyyy-mm-dddate: date => new Date(date).toISOString().split('T')[0],},});// Validate Date input$('.ui.form').form({fields: {date: 'empty',},});$('.submit').click(historicalRatesHandler);
});

再一次,花时间阅读评论并理解代码和它在做什么。然后重新启动服务器,刷新浏览器并导航到/historical路径。选择 1999 年之前的任何日期,然后单击Fetch Rates。你应该有这样的东西:

如果您选择 1999 年之前的日期或未来的日期,提交表单时将显示错误横幅。

概括

现在我们已经结束了本教程,您应该会看到,在不使用框架的情况下构建由 REST API 支持的单页应用程序并不难。但是有几点我们应该关注:

  • DOM 性能。在我们的客户端代码中,我们直接操作 DOM。随着项目的发展,这很快就会失控,导致 UI 变得迟缓。

  • 浏览器性能。我们已经将很多前端库作为脚本加载到 中index.html,这对于开发目的来说是可以的。对于生产部署,我们需要一个捆绑所有脚本的系统,以便浏览器使用单个请求来加载必要的 JavaScript 资源。

  • 单片代码。对于服务器代码,将代码分解为模块化部分更容易,因为它在 Node 环境中运行。然而,对于客户端代码,除非你使用像webpack这样的打包器,否则在模块中组织起来并不容易。

  • 测试。到目前为止,我们一直在进行手动测试。对于一个生产就绪的应用程序,我们需要建立一个像 Jasmine、Mocha 或 Chai 这样的测试框架来自动化这项工作。这将有助于防止重复出现错误。

当您在不使用框架的情况下进行项目开发时,这些只是您将面临的众多问题中的一小部分。使用诸如 Angular、React 或 Vue 之类的东西将帮助您减轻很多这些担忧。我希望本教程对您有所帮助,并能帮助您成为一名专业的 JavaScript 开发人员。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. SPIE西部光电展重返线下,成功举办科学和工程盛会

    全球首屈一指的年度光子学盛会与SPIE AR/VR/MR会议重返线下&#xff0c;展示生物医学光学、量子和激光技术的最新成果 华盛顿州贝灵汉--(美国商业资讯)--1月22日至27日&#xff0c;国际光电工程学会(SPIE)在满足安全要求的情况下成功迎接国际光子学界人士重返旧金山莫斯康中心…...

    2024/4/13 9:36:10
  2. Vue3+TypeScript笔记1

    Vue3TypeScript笔记1 学习链接&#xff1a;https://www.bilibili.com/video/BV1of4y1v7tB 1.ts文件中的函数中的形参&#xff0c;如果使用了某个类型进行修饰&#xff0c;那么最终在翻译的js文件中是没有这个类型的 2.ts文件中的变量使用的是let进行修饰&#xff0c;编译的j…...

    2024/4/8 20:02:06
  3. 寒假打卡第七天——拓扑排序

    首先&#xff0c;什么是拓扑序列&#xff1f; 拓扑序列是顶点活动网中将活动按发生的先后次序进行的一种排列。. 拓扑排序&#xff0c;是对一个有向无环图 (Directed Acyclic Graph简称DAG)G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一…...

    2024/4/19 12:56:30
  4. JAVA标识符

    1.所有的标识符都应该以字母、&#xffe5;、或下划线开头 2.不能使用关键字作变量/方法名 3.大小写敏感 4.避免中文命名...

    2024/4/30 19:47:59
  5. Spring中的Bean实例化时机

    今天我们来测试Bean实例化的时机 Person类的定义 public class Person {public Person(){//打印输出&#xff0c;方便看到方法调用System.out.println("无参构造被调用.");} }application.xml <?xml version"1.0" encoding"UTF-8"?&…...

    2024/4/13 2:51:01
  6. 搜狗收录提交入口之搜狗泛目录实现

    搜狗进行了大更新&#xff0c;增加了资质提交、网站管理员权限&#xff0c;验证推送从之前的单站点提交200条到现在的不限制提交数量&#xff0c;非验证从之前的单账号单日只能提交200条到现在的不限制提交数量。搜狗的资质提交需要提交网站对应的ICP备案信息&#xff0c;进行对…...

    2024/4/19 5:10:12
  7. 1.Pandas教程-金融分析教程(1)

    注意&#xff1a; 教程内容来自 https://nbviewer.jupyter.org/github/twiecki/financial-analysis-python-tutorial/tree/master/ 这不是完整的系统的pandas教程&#xff0c;此外源教程测试demo老旧&#xff0c;新版本pandas可能无法兼容源程序&#xff0c;本教程是在原教程基…...

    2024/4/19 14:13:00
  8. java小农养成记第三十五天

    day35 今日内容 XML 概念语法解析 XML 1. 概念&#xff1a;可扩展标记语言&#xff08;Extensible Markup Language&#xff09;* 可扩展&#xff1a;标签都是自定义的。\<user>\<student>* 功能* 存储数据&#xff1a;1. 配置文件2. 在网络中传输* xml与html…...

    2024/4/13 2:51:11
  9. 李宏毅 2020 深度学习与人类语言处理 DLHLP-Coreference Resolution-p21

    前言 本文是李宏毅 2020 深度学习与人类语言处理 DLHLP 课程中 Coreference Resolution 指代消解部分的笔记。 https://speech.ee.ntu.edu.tw/~hylee/dlhlp/2020-spring.html 课程官网 李宏毅老师2020新课深度学习与人类语言处理_哔哩哔哩_bilibili -p21 哔哩哔哩搬运 内容…...

    2024/4/13 2:51:16
  10. 1. Pandas教程-10MintoPandas

    介绍&#xff1a;这部分程序是10分钟进入pandas教程. 教程在Windows10环境&#xff0c;使用Anaconda&#xff0c;jupyter下测试的。注意版本区别&#xff0c;若版本有更新某些函数被弃用&#xff0c;请以官方手册为准。文章是jupyter编辑器转化成的markdown&#xff0c;可能会有…...

    2024/4/20 4:11:34
  11. (一)计算机四大学科-----操作系统之计算机系统概述

    一&#xff1a;操作系统的基本概念 1.操作系统是指&#xff1a;控制和管理整个计算机系统的硬件与软件资源&#xff0c;合理地组织、调度计算机的工作与资源的分配&#xff0c;进而为用户和其他软件提供方便接口与环境的程序集合。 2.操心系统是一个最基本的系统软件。 3.操…...

    2024/4/13 2:50:56
  12. 学习数据结构的笔记——时间、空间复杂度

    知识总结&#xff1a; 1.数据结构非常重要&#xff0c;在校园的招聘笔试中经常出现&#xff0c;这关乎一份好的offer 2.重要的学习方法&#xff0c;力扣的算法题&#xff0c; 3..递归的时间复杂度 递归次数*每次递归函数中次数 递归的空间复杂度 递归的深度 4.O&#xf…...

    2024/4/13 2:51:26
  13. seleniumbase学习总结1 - 简介及原理

    1、为什么给这个UI框架投入精力&#xff1f; 想找一款基于pytest封装的UI自动化框架&#xff0c;github搜到这个2.6星&#xff0c;另外自己对slenium比较熟悉&#xff0c;就选了这款框架用来快速落地UI自动化脚本&#xff0c;并最终结合jenkins形成服务化。 2、ing...

    2024/4/8 20:01:58
  14. Android 启动其他应用Activity/Service失败问题

    本文仅针对Android11&#xff0c;如果你的模拟器或设备是Android11的话&#xff0c;请继续看下去。 一、提出问题 最近在使用一个应用绑定另外一个应用的Service时&#xff0c;无论如何都绑定不上&#xff0c;现象是Service的onCreate()和onStartCommand()回调都没有执行。说…...

    2024/4/13 2:51:56
  15. Java基础面试题

    JDK 和 JRE 有什么区别&#xff1f; 具体来说 JDK 其实包含了 JRE&#xff0c;同时还包含了编译 java 源码的编译器 javac&#xff0c;还包含了很多 java 程序调试和分析的工具。简单来说&#xff1a;如果你需要运行 java 程序&#xff0c;只需安装 JRE 就可以了&#xff0c;如…...

    2024/4/8 20:01:56
  16. Java——基础简介

    基础简介 一、发展历史 1991年。James Gosling在SUN公司的工程师小组想要设计这样一种小型计算机语言。 该语言主要用于像电视盒这样的消费类电子产品。 另外,由于不同的厂商选择不同的CPU和操作系统&#xff0c;因此&#xff0c;要求该语言不能和特定的体系结构绑在一起,要…...

    2024/4/20 15:19:22
  17. 今天面了个支付宝拿35K出来的,真是砂纸擦屁股,给我露了一手啊

    今年的春招已经开始了&#xff0c;很多小伙伴收获不错&#xff0c;有的已经拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好&#xff0…...

    2024/4/17 13:53:32
  18. C++基础知识 - 赋值构造函数

    赋值构造函数 如果没有定义赋值构造函数&#xff0c;编译器会自动定义“合成的赋值构造函数”&#xff0c; 与其他合成的构造函数&#xff0c;是“浅拷贝”&#xff08;又称为“位拷贝”&#xff09;。 Human.h #pragma once #include <string> #include <iostream&…...

    2024/4/13 2:51:46
  19. Collections工具类的使用(学习Java第18天)

    目录 一.Collections工具类概述 二.public static void shuffle(List list) :打乱集合顺序。 三.public static void sort(List list):将集合中元素按照默认规则排序。 四.public static void sort(List list&#xff0c;Comparator com ):将集合中元素按照指定规则排序。…...

    2024/4/13 2:51:56
  20. cyberRT源码浅层解析(二) mainboard

    mainboard模块是cyber的程序入口&#xff0c;启动模块&#xff0c;我们可以使用类似roslaunch的方式启动&#xff0c;cyberRT的launch也是封装了mainboard模块&#xff0c;也可以直接使用mainboard -p <process_group> -d … &启动某一个模块。 minaboard模块中一共有…...

    2024/4/13 2:52:06

最新文章

  1. 数据库常问2

    count(*)、count(1)、count(列名)的区别&#xff1f; count(*)&#xff1a; count(*) 是最常见的统计方法之一&#xff0c;它会统计满足条件的所有行数&#xff0c;包括 NULL 值。例如&#xff0c;假设我们有一个名为 students 的表&#xff0c;其中有一个列名为 age&#xf…...

    2024/5/4 3:20:47
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 实验二 pandas库绘图以及数据清洗

    1.1pandas验证操作 1、验证以下代码&#xff0c;并将结果附截图 import pandas as pd A[1,3,6,4,9,10,15] weight[67,66,83,68,79,88] sex[女,男,男,女,男, 男] S1pd.Series(A)#构建S1序列 print(S1) S2pd.Series(weight)#构建S2序列 print(S2) S3pd.Series(sex)#构建S3序列 p…...

    2024/5/2 15:16:15
  4. 每日一题--- 环形链表[力扣][Go]

    环形链表 题目&#xff1a;142. 环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给…...

    2024/5/1 9:37:35
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/3 23:10:03
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/4 2:59:34
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57