<script> 标签只对页面刷新有效(单页应用)
<script> tag only works on page refresh (Single Page Application)
我正在使用纯 Javascript + express-JS 构建单页应用程序。我有两个视图 linked 到两个锚点 link,这样我就可以在视图之间切换。问题是,其中一个视图(默认视图)显示了一个 d3 图表,它只在网站最初加载或页面刷新时显示它。如果我只是单击它自己的锚点 link,理论上它应该什么也不做,仍然显示图表,但图表消失了,但与该视图对应的所有其他 html 元素仍然存在。我正在确保在加载我的所有内容后,该文件的脚本标记已加载到基础 html 文件中,但问题仍然存在。有人可以指出这里出了什么问题吗?
var tag = document.createElement("script");
function scriptLoad() {
tag.src = "static/js/d3chart.js";
tag.id = "d3chart"
document.getElementsByTagName('head')[0].appendChild(tag);
};
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
scriptLoad();
});
router();
});
HTML 锚点 links 在基础 html 文件中
<a href="/" data-link>View 1</a>
<a href="/view2" data-link>View 2</a>
完整代码
import view1 from "./views/view1.js"
import view2 from "./views/view2.js"
const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\/").replace(/:\w+/g, "(.+)") + "$");
const getParams = match => {
const values = match.result.slice(1);
const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]);
return Object.fromEntries(keys.map((key, i) => {
return [key, values[i]];
}));
};
const navigateTo = url => {
history.pushState(null, null, url);
router();
};
const router = async () => {
const routes = [
{ path: "/", view: view1 },
{ path: "/view2", view: view2 }
];
// Test each route for potential match
const potentialMatches = routes.map(route => {
return {
route: route,
result: location.pathname.match(pathToRegex(route.path))
};
});
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
if (!match) {
match = {
route: routes[0],
result: [location.pathname]
};
}
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();
};
window.addEventListener("popstate", router);
var tag = document.createElement("script");
function scriptLoad () {
tag.src = "static/js/d3chart.js";
tag.id = "d3chart"
document.getElementsByTagName('body')[0].appendChild(tag);
}
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
scriptLoad();
});
router();
});
view1.js 文件 - 启动时的默认视图(图表视图)
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
`;
}
}
您必须将函数内联或在单击“a”html 标记时添加新的事件侦听器。
<a onclick="scriptLoad()" href="/" data-link>View 1</a>
<a onclick="scriptLoad()" href="/view2" data-link>View 2</a>
根据您的评论,文件 d3chart.js
将 运行 创建图表的代码并将其应用于 div 名称 class [=16] =].让您的代码正常工作的快速而肮脏的方法是执行以下操作:
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
// scriptLoad(); <- remove this
});
router();
});
view1.js
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
<script id="d3chart" src="static/js/d3chart.js"></script>
`;
}
}
这会解决您最初的问题,但会产生一个新问题,正如您可能已经想到的那样,它会在您每次加载该视图时发出 HTTP 请求!这可能是您想要的,但如果不是,您将需要稍微更改代码的结构。文件 d3chart.js
的代码需要公开一个 loadChart
函数(或任何您想调用它的函数),然后您将加载该脚本一次并在视图出现时调用 loadChart
函数需要更新。
d3chart.js
function loadChart() {
// Your code to create the chart and apply it to the an element.
}
模板
<script id="d3chart" src="static/js/d3chart.js"></script>
<a href="/" data-link>View 1</a>
<a href="/view2" data-link>View 2</a>
<div id="app"></div>
view1.js
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
<script>loadChart();</script>
`;
}
}
好的,所以 Reddit 上的一个人帮助我解决了这个问题,基本上我要做的就是在 view1.js 文件的 class 中创建一个方法并放置我的 d3 代码在那个方法里面,像这样
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
loadChart() {
// My D3 code here
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
`;
}
}
后来,我不得不调用它,就像在我的路由器文件中那样
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();
view.loadChart?.(); // runs the method after the HTML corresponding to the view has been added to the base HTML.
我正在使用纯 Javascript + express-JS 构建单页应用程序。我有两个视图 linked 到两个锚点 link,这样我就可以在视图之间切换。问题是,其中一个视图(默认视图)显示了一个 d3 图表,它只在网站最初加载或页面刷新时显示它。如果我只是单击它自己的锚点 link,理论上它应该什么也不做,仍然显示图表,但图表消失了,但与该视图对应的所有其他 html 元素仍然存在。我正在确保在加载我的所有内容后,该文件的脚本标记已加载到基础 html 文件中,但问题仍然存在。有人可以指出这里出了什么问题吗?
var tag = document.createElement("script");
function scriptLoad() {
tag.src = "static/js/d3chart.js";
tag.id = "d3chart"
document.getElementsByTagName('head')[0].appendChild(tag);
};
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
scriptLoad();
});
router();
});
HTML 锚点 links 在基础 html 文件中
<a href="/" data-link>View 1</a>
<a href="/view2" data-link>View 2</a>
完整代码
import view1 from "./views/view1.js"
import view2 from "./views/view2.js"
const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\/").replace(/:\w+/g, "(.+)") + "$");
const getParams = match => {
const values = match.result.slice(1);
const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]);
return Object.fromEntries(keys.map((key, i) => {
return [key, values[i]];
}));
};
const navigateTo = url => {
history.pushState(null, null, url);
router();
};
const router = async () => {
const routes = [
{ path: "/", view: view1 },
{ path: "/view2", view: view2 }
];
// Test each route for potential match
const potentialMatches = routes.map(route => {
return {
route: route,
result: location.pathname.match(pathToRegex(route.path))
};
});
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
if (!match) {
match = {
route: routes[0],
result: [location.pathname]
};
}
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();
};
window.addEventListener("popstate", router);
var tag = document.createElement("script");
function scriptLoad () {
tag.src = "static/js/d3chart.js";
tag.id = "d3chart"
document.getElementsByTagName('body')[0].appendChild(tag);
}
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
scriptLoad();
});
router();
});
view1.js 文件 - 启动时的默认视图(图表视图)
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
`;
}
}
您必须将函数内联或在单击“a”html 标记时添加新的事件侦听器。
<a onclick="scriptLoad()" href="/" data-link>View 1</a>
<a onclick="scriptLoad()" href="/view2" data-link>View 2</a>
根据您的评论,文件 d3chart.js
将 运行 创建图表的代码并将其应用于 div 名称 class [=16] =].让您的代码正常工作的快速而肮脏的方法是执行以下操作:
document.addEventListener("DOMContentLoaded", () => {
document.body.addEventListener("click", e => {
if (e.target.matches("[data-link]")) {
e.preventDefault();
navigateTo(e.target.href);
}
// scriptLoad(); <- remove this
});
router();
});
view1.js
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
<script id="d3chart" src="static/js/d3chart.js"></script>
`;
}
}
这会解决您最初的问题,但会产生一个新问题,正如您可能已经想到的那样,它会在您每次加载该视图时发出 HTTP 请求!这可能是您想要的,但如果不是,您将需要稍微更改代码的结构。文件 d3chart.js
的代码需要公开一个 loadChart
函数(或任何您想调用它的函数),然后您将加载该脚本一次并在视图出现时调用 loadChart
函数需要更新。
d3chart.js
function loadChart() {
// Your code to create the chart and apply it to the an element.
}
模板
<script id="d3chart" src="static/js/d3chart.js"></script>
<a href="/" data-link>View 1</a>
<a href="/view2" data-link>View 2</a>
<div id="app"></div>
view1.js
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
<script>loadChart();</script>
`;
}
}
好的,所以 Reddit 上的一个人帮助我解决了这个问题,基本上我要做的就是在 view1.js 文件的 class 中创建一个方法并放置我的 d3 代码在那个方法里面,像这样
import AbstracView from "./AbstractView.js"
export default class extends AbstracView {
constructor() {
super();
this.setTitle("D3 Chart - View1");
}
loadChart() {
// My D3 code here
}
async getHtml() {
return `
<h1>D3 Chart</h1>
<div class="chart-area"></div>
`;
}
}
后来,我不得不调用它,就像在我的路由器文件中那样
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();
view.loadChart?.(); // runs the method after the HTML corresponding to the view has been added to the base HTML.