Vanilla JS SPA - 如何在 SPA 视图的插入 html 下加载特定脚本
Vanilla JS SPA - How to load specific scripts under the inserted html of the SPA View
我正在制作 Vanilla JS SPA - APP - 并且除此之外一切正常33=] 不执行。有没有办法让html下的JS脚本执行?每个视图都有不同的脚本,因此如果可以将它们与特定视图的相关 html 一起加载会更好。
此致
注册VIEW:
// Imports
// Using the abstract class
import AbstractView from "./AbstractView.js";
// Class ###########################################################>
export default class extends AbstractView {
// Constructor =================================================>
constructor() {
super(); // The abstract class Constructor "Base constructor"
this.setTitle("Register");
}
// Get Html ====================================================>
async getHtml() {
return `
<form id="registerForm">
<div name="register" class="inputContainer">
<h4 class="title">Register</h4>
<hr class="hrTitle">
<diV class="colom">
<div class="form-group">
<label for="email">Email:</label>
<input name="email" type="text" maxlength="25" id="email" class="form-control inputDark" />
<label id="emailValidation"></label>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input name="password" type="text" maxlength="40" id="password" class="form-control inputDark" />
<label id="passwordValidation"></label>
</div>
<div class="form-group">
<label for="repeatPassword">Repeat Password:</label>
<input type="text" maxlength="40" id="repeatPassword" class="form-control inputDark" />
<label id="repeatPasswordValidation"></label>
</div>
<div class="form-group">
<label for="firstname">FirstName:</label>
<input name="firstname" type="text" maxlength="20" id="firstname" class="form-control inputDark" />
<label id="firstNameValidation"></label>
</div>
<div class="form-group">
<label for="lastname">LastName:</label>
<input name="lastname" type="text" maxlength="20" id="lastname" class="form-control inputDark" />
<label id="lastNameValidation"></label>
</div>
<div class="form-group">
<label for="age">Age:</label>
<input name="age" type="text" maxlength="3" id="age" class="form-control inputDark" />
<label is="ageValidation"></label>
</div>
<div class="form-group">
<label for="phonenumber">Phonenumber:</label>
<input name="phonenumber" type="text" maxlength="8" id="phonenumber" class="form-control inputDark" />
<label id="phonenumberValidation"></label>
</div>
<div class="form-group">
<label for="rememberMe" class="subTitle" >Remember Me:</label>
<input name="rememberMe" value="true" type="checkbox" id="rememberMe" class="form-control inputDark" />
</div>
</div>
<button type="submit" onkeypress="javascript:registerAccount()" onmousedown="javascript:registerAccount(); " class="blue-dark-button">Enter</button>
</div>
</form>
<script>(function(){alert('this happened automatically');})();>/script> // This script does not loads on innerHtml insertion.
`;
}
Index.js - HTML 的路由和插入视图:
它在底部 document.querySelector("#app").innerHTML = await view.getHtml();
// Imports
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import Register from "./views/Register.js";
// Navigator--------------------------------------------------------------------------------->
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
// Router------------------------------------------------------------------------------------>
const router = async () => {
const routes = [
{path: "/", view: Dashboard}, // On Path "/" use the dashboard class and inject html in the #app div
{path: "/posts", view: Posts },
{path: "/settings", view: Settings },
{path: "/Register", view: Register }
];
// Test each route for potential match ----------------------------------------------------->
// Get the current Url and check if its defined in routes method "Check if its one of our Spa Urls" ----------------------------------------------------->
const potentialMatches = routes.map(route => {
return {
route: route,
isMatch: location.pathname === route.path // true if match else false
};
});
// Check if there is Match------------------------------------------------------------------->
let match = potentialMatches.find(potentialMatch => potentialMatch.isMatch); // Get isMatch from potentialMatches
// If no match return to StartPage
if(!match)
{
match = {
route: routes[0],
isMatch: true
};
}
const view = new match.route.view(); // If match use the routes array of the router and get the view function for the route
document.querySelector("#app").innerHTML = await view.getHtml(); // Get the #app div and use the view function to inject Html in it from the view class ex."Dashboard, Posts, Settings etc."
};
// On-Navigating-Back&Forth-Load the Content--Together with the url------------------------------------------------------------------------------------>
window.addEventListener("popstate", router); // On popstate "If back button is pressed" use the router array to load back the previeous SPA View
// Listen to document fully Loaded
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => { //Listen for click in the body
if(e.target.matches("[data-link]")){ // If body item was clicked and its data-link decorated
e.preventDefault(); // Prevent deafult behavior dont follow the link
navigateTo(e.target.href); // Navigate method
}
});
router(); // Load the content if the url is defined in our "Spa Urls"
});
//#### Client Routing END #####
Index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Leanheat</title>
<link rel="stylesheet" href="/Static/css/index.css">
<link rel="stylesheet" href="Static/css/components.css" />
<script src="Static/js/api/apiAdresses.js"></script>
<script src="Static/js/api/CRUD/register.js"></script>
<script src="Static/js/components/Messages.js"></script>
</head>
<!--BODY------------------------------------------------------------------------------------------------------>
<body>
<div class="wrapper-1">
<!--SideBar - LEFT ------------------------->
<div id="left-bar" class="left-bar">
<a href="/" class="left-bar__link" onclick="" data-link>Dashboard</a>
<a href="/posts" class="left-bar__link" data-link>Posts</a>
<a href="/settings" class="left-bar__link" data-link>Settings</a>
</div>
<!--<div class="sucsess-Message"><p> SUCCESS</p></div>-->
<div class="wrapper-2">
<div class="top-bar">
<a href="/Register" onclick="" data-link>Register</a>
<a href="/LogIn">Log In</a>
<a href="/LogOut" >Log Out</a>
</div>
<!--APP - Content ------------------------>
<div id="app"></div>
</div>
</div>
<!--SPA - JS - Routing ------------------->
<script type="module" src="/Static/js/index.js"></script>
</body>
</html>
这是 JavaScript 和 AJAX 的“功能”,用于尝试防止任意代码执行。 script
标签只能深入一层...因此,如果您加载一个 HTML 页面并且该 HTML 页面有一个 script
标签,那很好。如果该脚本加载一个“sub-HTML”页面并且该“sub-HTML”页面也有一个 script
标签,那么 script
标签 将被忽略。它会出现在 DOM 和所有内容中,但如果您查看网络流量,它从未被请求过,也不会被执行。
有很多方法可以解决这个问题,但现在像这样的事情只是创建一个包含所有 JS 文件的大 ole 包并预先加载它们,这样您的子 HTML 就不必发送它了script
连同它。
如果你真的想那样做,可以使用像 RequireJS 这样的库。确保您按照说明在运行时执行此操作。几乎所有人都会假设您想在 bundle/compile/package 时间做这件事。
我找到了解决方案 - 我有特定的视图 - “页面” - 使用抽象视图。
抽象视图具有 getHtml - 方法,客户端路由器是将所选视图插入 <div id="app"></div>
- 视图容器的路由器。我只需要向抽象视图添加另一个方法 - “async executeViewScript(){}
”并将其添加到基于抽象视图的所有其他视图,所以我现在可以在async getHtml(){}
在客户端路由器中。
抽象视图:
// Class ###########################################################>
export default class{
// Constructor =================================================>
constructor()
{
}
// Set Title ====================================================>
setTitle(title) {
document.title = title;
}
// Get Html ====================================================>
async getHtml()
{
return "";
}
// View Script ====================================================>
async executeViewScript() // !!! The fix
{
}
}
Index.js - 客户端路由器:
// Imports
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import Register from "./views/Register.js";
import Login from "./views/Login.js";
import Profile from "./views/Profile.js";
// Navigator--------------------------------------------------------------------------------->
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
// Router------------------------------------------------------------------------------------>
const router = async () => {
const routes = [
{path: "/", view: Dashboard}, // On Path "/" use the dashboard class and inject html in the #app div
{path: "/posts", view: Posts },
{path: "/settings", view: Settings },
{path: "/Register", view: Register },
{path: "/Login", view: Login },
{path: "/Profile", view: Profile }
];
// Test each route for potential match ----------------------------------------------------->
// Get the current Url and check if its defined in routes method "Check if its one of our Spa Urls" ----------------------------------------------------->
const potentialMatches = routes.map(route => {
return {
route: route,
isMatch: location.pathname === route.path // true if match else false
};
});
// Check if there is Match------------------------------------------------------------------->
let match = potentialMatches.find(potentialMatch => potentialMatch.isMatch); // Get isMatch from potentialMatches
// If no match return to StartPage
if(!match)
{
match = {
route: routes[0],
isMatch: true
};
}
const view = new match.route.view(); // If match use the routes array of the router and get the view function for the route
document.querySelector("#app").innerHTML = await view.getHtml(); // Get the #app div and use the view function to inject Html in it from the view class ex."Dashboard, Posts, Settings etc."
await view.executeViewScript(); // !!! The fix - THIS is the script that executes exactly after the inserted HTML-
};
// On-Navigating-Back&Forth-Load the Content--Together with the url------------------------------------------------------------------------------------>
window.addEventListener("popstate", router); // On popstate "If back button is pressed" use the router array to load back the previeous SPA View
// Listen to document fully Loaded
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => { //Listen for click in the body
if(e.target.matches("[data-link]")){ // If body item was clicked and its data-link decorated
e.preventDefault(); // Prevent deafult behavior dont follow the link
navigateTo(e.target.href); // Navigate method
}
});
router(); // Load the content if the url is defined in our "Spa Urls"
});
//#### Client Routing END #####
我正在制作 Vanilla JS SPA - APP - 并且除此之外一切正常33=] 不执行。有没有办法让html下的JS脚本执行?每个视图都有不同的脚本,因此如果可以将它们与特定视图的相关 html 一起加载会更好。
此致
注册VIEW:
// Imports
// Using the abstract class
import AbstractView from "./AbstractView.js";
// Class ###########################################################>
export default class extends AbstractView {
// Constructor =================================================>
constructor() {
super(); // The abstract class Constructor "Base constructor"
this.setTitle("Register");
}
// Get Html ====================================================>
async getHtml() {
return `
<form id="registerForm">
<div name="register" class="inputContainer">
<h4 class="title">Register</h4>
<hr class="hrTitle">
<diV class="colom">
<div class="form-group">
<label for="email">Email:</label>
<input name="email" type="text" maxlength="25" id="email" class="form-control inputDark" />
<label id="emailValidation"></label>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input name="password" type="text" maxlength="40" id="password" class="form-control inputDark" />
<label id="passwordValidation"></label>
</div>
<div class="form-group">
<label for="repeatPassword">Repeat Password:</label>
<input type="text" maxlength="40" id="repeatPassword" class="form-control inputDark" />
<label id="repeatPasswordValidation"></label>
</div>
<div class="form-group">
<label for="firstname">FirstName:</label>
<input name="firstname" type="text" maxlength="20" id="firstname" class="form-control inputDark" />
<label id="firstNameValidation"></label>
</div>
<div class="form-group">
<label for="lastname">LastName:</label>
<input name="lastname" type="text" maxlength="20" id="lastname" class="form-control inputDark" />
<label id="lastNameValidation"></label>
</div>
<div class="form-group">
<label for="age">Age:</label>
<input name="age" type="text" maxlength="3" id="age" class="form-control inputDark" />
<label is="ageValidation"></label>
</div>
<div class="form-group">
<label for="phonenumber">Phonenumber:</label>
<input name="phonenumber" type="text" maxlength="8" id="phonenumber" class="form-control inputDark" />
<label id="phonenumberValidation"></label>
</div>
<div class="form-group">
<label for="rememberMe" class="subTitle" >Remember Me:</label>
<input name="rememberMe" value="true" type="checkbox" id="rememberMe" class="form-control inputDark" />
</div>
</div>
<button type="submit" onkeypress="javascript:registerAccount()" onmousedown="javascript:registerAccount(); " class="blue-dark-button">Enter</button>
</div>
</form>
<script>(function(){alert('this happened automatically');})();>/script> // This script does not loads on innerHtml insertion.
`;
}
Index.js - HTML 的路由和插入视图:
它在底部 document.querySelector("#app").innerHTML = await view.getHtml();
// Imports
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import Register from "./views/Register.js";
// Navigator--------------------------------------------------------------------------------->
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
// Router------------------------------------------------------------------------------------>
const router = async () => {
const routes = [
{path: "/", view: Dashboard}, // On Path "/" use the dashboard class and inject html in the #app div
{path: "/posts", view: Posts },
{path: "/settings", view: Settings },
{path: "/Register", view: Register }
];
// Test each route for potential match ----------------------------------------------------->
// Get the current Url and check if its defined in routes method "Check if its one of our Spa Urls" ----------------------------------------------------->
const potentialMatches = routes.map(route => {
return {
route: route,
isMatch: location.pathname === route.path // true if match else false
};
});
// Check if there is Match------------------------------------------------------------------->
let match = potentialMatches.find(potentialMatch => potentialMatch.isMatch); // Get isMatch from potentialMatches
// If no match return to StartPage
if(!match)
{
match = {
route: routes[0],
isMatch: true
};
}
const view = new match.route.view(); // If match use the routes array of the router and get the view function for the route
document.querySelector("#app").innerHTML = await view.getHtml(); // Get the #app div and use the view function to inject Html in it from the view class ex."Dashboard, Posts, Settings etc."
};
// On-Navigating-Back&Forth-Load the Content--Together with the url------------------------------------------------------------------------------------>
window.addEventListener("popstate", router); // On popstate "If back button is pressed" use the router array to load back the previeous SPA View
// Listen to document fully Loaded
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => { //Listen for click in the body
if(e.target.matches("[data-link]")){ // If body item was clicked and its data-link decorated
e.preventDefault(); // Prevent deafult behavior dont follow the link
navigateTo(e.target.href); // Navigate method
}
});
router(); // Load the content if the url is defined in our "Spa Urls"
});
//#### Client Routing END #####
Index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Leanheat</title>
<link rel="stylesheet" href="/Static/css/index.css">
<link rel="stylesheet" href="Static/css/components.css" />
<script src="Static/js/api/apiAdresses.js"></script>
<script src="Static/js/api/CRUD/register.js"></script>
<script src="Static/js/components/Messages.js"></script>
</head>
<!--BODY------------------------------------------------------------------------------------------------------>
<body>
<div class="wrapper-1">
<!--SideBar - LEFT ------------------------->
<div id="left-bar" class="left-bar">
<a href="/" class="left-bar__link" onclick="" data-link>Dashboard</a>
<a href="/posts" class="left-bar__link" data-link>Posts</a>
<a href="/settings" class="left-bar__link" data-link>Settings</a>
</div>
<!--<div class="sucsess-Message"><p> SUCCESS</p></div>-->
<div class="wrapper-2">
<div class="top-bar">
<a href="/Register" onclick="" data-link>Register</a>
<a href="/LogIn">Log In</a>
<a href="/LogOut" >Log Out</a>
</div>
<!--APP - Content ------------------------>
<div id="app"></div>
</div>
</div>
<!--SPA - JS - Routing ------------------->
<script type="module" src="/Static/js/index.js"></script>
</body>
</html>
这是 JavaScript 和 AJAX 的“功能”,用于尝试防止任意代码执行。 script
标签只能深入一层...因此,如果您加载一个 HTML 页面并且该 HTML 页面有一个 script
标签,那很好。如果该脚本加载一个“sub-HTML”页面并且该“sub-HTML”页面也有一个 script
标签,那么 script
标签 将被忽略。它会出现在 DOM 和所有内容中,但如果您查看网络流量,它从未被请求过,也不会被执行。
有很多方法可以解决这个问题,但现在像这样的事情只是创建一个包含所有 JS 文件的大 ole 包并预先加载它们,这样您的子 HTML 就不必发送它了script
连同它。
如果你真的想那样做,可以使用像 RequireJS 这样的库。确保您按照说明在运行时执行此操作。几乎所有人都会假设您想在 bundle/compile/package 时间做这件事。
我找到了解决方案 - 我有特定的视图 - “页面” - 使用抽象视图。
抽象视图具有 getHtml - 方法,客户端路由器是将所选视图插入 <div id="app"></div>
- 视图容器的路由器。我只需要向抽象视图添加另一个方法 - “async executeViewScript(){}
”并将其添加到基于抽象视图的所有其他视图,所以我现在可以在async getHtml(){}
在客户端路由器中。
抽象视图:
// Class ###########################################################>
export default class{
// Constructor =================================================>
constructor()
{
}
// Set Title ====================================================>
setTitle(title) {
document.title = title;
}
// Get Html ====================================================>
async getHtml()
{
return "";
}
// View Script ====================================================>
async executeViewScript() // !!! The fix
{
}
}
Index.js - 客户端路由器:
// Imports
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import Settings from "./views/Settings.js";
import Register from "./views/Register.js";
import Login from "./views/Login.js";
import Profile from "./views/Profile.js";
// Navigator--------------------------------------------------------------------------------->
const navigateTo = url => {
history.pushState(null, null, url); // Add the url to the history APi of Js
router();
};
// Router------------------------------------------------------------------------------------>
const router = async () => {
const routes = [
{path: "/", view: Dashboard}, // On Path "/" use the dashboard class and inject html in the #app div
{path: "/posts", view: Posts },
{path: "/settings", view: Settings },
{path: "/Register", view: Register },
{path: "/Login", view: Login },
{path: "/Profile", view: Profile }
];
// Test each route for potential match ----------------------------------------------------->
// Get the current Url and check if its defined in routes method "Check if its one of our Spa Urls" ----------------------------------------------------->
const potentialMatches = routes.map(route => {
return {
route: route,
isMatch: location.pathname === route.path // true if match else false
};
});
// Check if there is Match------------------------------------------------------------------->
let match = potentialMatches.find(potentialMatch => potentialMatch.isMatch); // Get isMatch from potentialMatches
// If no match return to StartPage
if(!match)
{
match = {
route: routes[0],
isMatch: true
};
}
const view = new match.route.view(); // If match use the routes array of the router and get the view function for the route
document.querySelector("#app").innerHTML = await view.getHtml(); // Get the #app div and use the view function to inject Html in it from the view class ex."Dashboard, Posts, Settings etc."
await view.executeViewScript(); // !!! The fix - THIS is the script that executes exactly after the inserted HTML-
};
// On-Navigating-Back&Forth-Load the Content--Together with the url------------------------------------------------------------------------------------>
window.addEventListener("popstate", router); // On popstate "If back button is pressed" use the router array to load back the previeous SPA View
// Listen to document fully Loaded
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => { //Listen for click in the body
if(e.target.matches("[data-link]")){ // If body item was clicked and its data-link decorated
e.preventDefault(); // Prevent deafult behavior dont follow the link
navigateTo(e.target.href); // Navigate method
}
});
router(); // Load the content if the url is defined in our "Spa Urls"
});
//#### Client Routing END #####