我只需输入url
并按Enter即可阻止用户访问某个页面。例如,用户可以通过一些向导访问此页面。我知道javaScript
可以监控浏览器上的点击事件,是否可以监控url
更改?换句话说,是否可以知道用户如何访问该页面? (自己添加路径,或者只是按照应用程序向导自然添加?)
编辑:
使用案例:在线测验,包含多个问题和页面,最终是结果页面。我想在回答一个问题后阻止用户进入结果页面。
答案 0 :(得分:2)
由于您的问题确实没有启动代码,因此很难知道您当前使用的是哪个框架。因此,我实施了一个非常基本的测验(它没有真正做到答案部分,没有显示任何结果,而且总体来说非常基本,但我想提供一个有点完整的例子。)
要检测页面内的更改(当前哈希路径),您可以订阅窗口的hashchange
事件,例如:
window.addEventListener('hashchange', handleRoute.bind(router));
但是,为了确保用户不直接导航到特定路线,您还可以订阅load
事件。
window.addEventListener('load', handleRoute.bind(router));
要验证(在我的情况下)是否允许用户在当前路由上,我添加了一个验证方法,只需检查:
这部分在此处理:
function isPageValid(route, qry) {
switch (route.scope) {
case 'questions':
// only allow the question page when the current question is the actual one in the querystring
return (parseInt(qry.split('=')[1]) === answered.length) && answered.length <= questions.length;
// only allow the results when we have all the answers
case 'results':
return answered.length === parseInt(questions.length);
}
// everything else should be valid (eg: default page)
return true;
}
由于无论如何根据我的路由器加载当前路由,我不必担心其他页面当时有效,所以如果它不是问题或结果,我总是发送{{1} } back:)
如果不存在,将显示默认页面
对于其余部分,小提琴是非常基本的,它向您显示起始页面,2个潜在的问题而您无法真正选择任何内容,但是在问题列表完成时仅显示结果页面的原则应该是清楚的。
我在代码中添加了一些注释,希望一切都清楚:)
true
'use strict';
var questions = [{
title: 'Is SO a good resource',
answers: ["yes", "no", "sometimes"],
correct: 2
}, {
title: 'Do you like to use stackoverflow on a daily basis',
answers: ["yes", "no"],
correct: 0
}],
answered = [];
// bind the nextQuestion element to the nextQuestion function
document.getElementById('nextQuestion').addEventListener('click', nextQuestion);
/*
* @method nextQuestion
* here the user will click when he wants to navigate to the next question
* If all questions are completed, it will navigate to the results page
* If there are more questions, it will navigate to /q=currentQuestion+1
*/
function nextQuestion(e) {
answered.push({
value: 0
});
if (answered.length < questions.length) {
document.location.href = '#/q=' + answered.length;
} else {
document.location.href = '#/results';
}
e.preventDefault();
}
/*
* @method showQuestion
* Gets called when the question gets changed
*/
function showQuestion(route, qry) {
var currentQuestion = answered.length;
document.getElementById('currentQuestion').innerHTML = currentQuestion;
document.getElementById('question').innerHTML = questions[currentQuestion].title;
if (currentQuestion === questions.length - 1) {
document.getElementById('nextQuestion').innerHTML = 'show results';
} else {
document.getElementById('nextQuestion').innerHTML = 'next question';
}
}
/*
* @method showResults
* Dummy method, answered are should contain all current answers
* just prints a message to the console
*/
function showResults(route, qry) {
console.log('can finally see the results :)');
}
/*
* @method isPageValid
* Validates the current route & qry
* @param route the current active route
* @param qry the current querystring that was validated to get to this route
* @returns true if the page is valid, false if it is not valid
*/
function isPageValid(route, qry) {
switch (route.scope) {
case 'questions':
// only allow the question page when the current question is the actual one in the querystring
return (parseInt(qry.split('=')[1]) === answered.length) && answered.length <= questions.length;
// only allow the results when we have all the answers
case 'results':
return answered.length === parseInt(questions.length);
}
// everything else should be valid (eg: default page)
return true;
}
/*
* @method handleRoute
* All routes are part of it's context (this object)
* Loops all properties of the context and checks which route matches the current part after #
*/
function handleRoute() {
var qry = document.location.href.split('#')[1],
result, defaultRoute, prop;
// hide all .scoped-block elements
document.querySelectorAll('.scoped-block').forEach(item => {
item.classList.add('hidden');
});
console.log('current query: ' + qry);
for (prop in this) {
if (this.hasOwnProperty(prop)) {
if (!this[prop].test) {
defaultRoute = this[prop];
} else {
if (this[prop].test.test(qry)) {
result = this[prop];
console.log('matches: ' + prop);
}
}
}
}
// if we have a designated page, validate it
if (result && !result.validate(result, qry)) {
// the page is not allowed to be shown (route to the default page)
console.info('cannot navigate to ' + result.scope + ' page (yet)')
result = undefined;
}
// make sure result contains the current valid route or the defaultRoute
result = result || defaultRoute;
console.log('current scope: ' + result.scope);
// set the current scope as the visible element
document.getElementById(result.scope).classList.remove('hidden');
if (result.action) {
result.action(result, qry);
}
}
// setup the available routes + potential validations
var router = {
questionPage: {
test: /\/q=[0-9]{1,2}$/,
validate: isPageValid,
action: showQuestion,
scope: 'questions'
},
resultPage: {
test: /\/results$/,
validate: isPageValid,
action: showResults,
scope: 'results'
},
startPage: {
action: function() {
// reset the answers
answered.splice(0, answered.length);
},
scope: 'startPage'
}
};
// adds the handle route method to the onload + hashchange method
window.addEventListener('hashchange', handleRoute.bind(router));
window.addEventListener('load', handleRoute.bind(router));
.hidden { display: none; visibility: hidden; }
.scoped-block {
// dummy element
}