VanillaJSSPA-如何在SPA视图的插入html下加载特定脚本



我正在制作Vanilla JS SPA-APP,除了在"应用程序";容器中的html加载良好,但html下的javascript不会执行。有没有办法让html下的JS脚本执行?每个视图都有不同的脚本,所以如果可以将它们与特定视图的相关html一起加载,那就太好了。

问候

注册视图:

// 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标记,那也没关系。如果该脚本加载一个";子HTML";第页;子HTML";页面还有一个script标记,该script标记将被忽略。它会显示在DOM和所有内容中,但如果您查看网络流量,它永远不会被请求,也不会被执行。

有很多方法可以解决这个问题,但现在这样的事情只需创建一个包含所有JS文件的大ole捆绑包,并提前加载它们,这样你的子HTML就不必同时发送script了。

如果你真的想这样做,可以使用RequireJS这样的库。请确保在运行时按照说明进行操作。几乎所有人都会认为你想在bundle/compile/package时完成。

我找到了解决方案-我有特定的视图-";页码"-它们使用抽象视图。抽象视图具有getHtml方法,客户端路由器将所选视图插入视图容器<div id="app"></div>。我只需要在抽象视图中添加另一个方法——";CCD_ 8";并将其添加到基于抽象视图的所有其他视图中,所以我现在可以称之为";CCD_ 9";在客户端路由器中的CCD_ 10之后。

摘要视图:

// 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 #####

最新更新