YegerChill
@YegerChill
Front-End developer

Как правильно разбить файлы на модули?

Как правильно разбить файлы на модули?
Я изучаю JS. Сейчас учу ООП, и решил по практиковаться и написать тест на js в ооп стиле.
Я его написал он работает, но как я понял одно из преимуществ ооп это разбиение на модули. И у меня вопрос, как мне правильно разбить файл с классом на модули. И нужно ли использовать webpack?
JS код класса (присутствует описание методов)

/*
	Класс тест - это класс для создания тестов
	Конструктор принимает в себя значения:
	data - объект с вопросами(пример кода ниже),
	//
	Пример: {
		q1: {
			question: "Вопрос",
			type: "radio", // тип вопроса (radio, checkbox, text, number, select)
			answers: ["123", 123, "535"],
			correct: 123, // Важно! Использовать цифры если ответ число
			score: 1 // Количество баллов за каждый вопрос
		}
	}
	//
	container - DOM element
	testClass - css классы[array], 
	testContentClass - css классы[array],
	questionClass - css классы[array],
	answersClass - css классы[array],
	btnClass - css классы[array],
	btnNextClass - css класс "str",
	btnNextText - текст кнопкт "str",
	btnAgainClass - css класс "str",
	btnAgainText - текст кнопки "str",
	textStart - стартовый текст "str",
	textEnd - текст в конце теста "str",
*/

class Test {
	constructor (
		data,
		container = 'body',
		testClass = ["test"],
		testContentClass = ["test__content"],
		questionClass = ["test__question"],
		answersClass = ["test__answers"],
		btnClass = ["test__btn"],
		btnNextClass = "next",
		btnNextText = "Далее",
		btnAgainClass = "again",
		btnAgainText = "Заново",
		textStart = "Тест",
		textEnd = "Тест завершен",
	) {
		this.data = data;
		this.container = document.querySelector(container);
		this.testClass = testClass;
		this.testContentClass = testContentClass;
		this.questionClass = questionClass;
		this.answersClass = answersClass;
		this.btnClass = btnClass;
		this.btnNextClass = btnNextClass;
		this.btnNextText = btnNextText;
		this.btnAgainClass = btnAgainClass;
		this.btnAgainText = btnAgainText;
		this.textStart = textStart;
		this.textEnd = textEnd;
	}


	getQuestion(step) {
		let keys = Object.keys(this.data);
		return this.data[keys[step-1]];
	}

	getQuestionsLength() {
		let keys = Object.keys(this.data);
		return keys.length;
	}

	createDOM() {
		// test
		let test = document.createElement('div');
		this.setClass(test, this.testClass);
		this.container.append(test);
		// testContent
		let testContent = document.createElement('div');
		this.setClass(testContent, this.testContentClass);
		test.append(testContent);
		// question
		let question = document.createElement('div');
		this.setClass(question, this.questionClass);
		testContent.append(question);
		// answers
		let answers = document.createElement('ul');
		this.setClass(answers, this.answersClass);
		testContent.append(answers);
		// btn
		let btn = document.createElement('button');
		this.setClass(btn, this.btnClass);
		btn.classList.add(this.btnNextClass);
		testContent.append(btn);

		this._dom = {
			test: test,
			testContent: testContent,
			question: question,
			answers: answers,
			btn: btn,
		};
		return this._dom;
	}

	get dom() {
		return this._dom;
	}

	/**
	 * @returns {any}
	 */

	setClass(el,classNames) {
		classNames.forEach(className => {
			el.classList.add(className);
		});
	}

	/**
	 * Метод render принимает в себя номер вопроса(начиная с одного), если передают 0 - то включается старотовый экран
	 * @param {*} step - номер вопроса
	 */
	render(step) { // step - номер вопроса, 0 - стартовый экран, номер вопроса начиная с единицы
		if ( step == 0 ) {
			this.score = 0;
			let dom = this.createDOM();
			dom.btn.textContent = this.btnNextText;
			dom.answers.textContent = this.textStart;
		} else {
			let question = this.getQuestion(step);
			let dom = this.dom;
			if ( dom.btn.classList.contains(this.btnAgainClass) ) { // удаляем класс btnAgainClass
				dom.btn.classList.remove(this.btnAgainClass);
				dom.btn.classList.add(this.btnNextClass);
				this.dom.btn.textContent = this.btnNextText;
			}
			dom.question.innerHTML = `${step}. ${question['question']}`;
			dom.answers.setAttribute('data-type', question.type); // для css стилей
			dom.answers.innerHTML = ``;
		
			if ( question.type == 'text' || question.type == 'number' ) {
				dom.answers.innerHTML += `
					<li>
						<input type="${question.type}" id="answer1" name="answer" value="" placeholder="Ваш ответ">
					</li>
				`;
			}
			else if ( question.type == 'select' ) {
				let answers = question.answers;
				this.shuffle(answers); // перемешываем порядок вывода ответов
				let answersHTML = ``;
				for ( let i = 0; i < answers.length; i++ ) {
					answersHTML += `<option value="${answers[i]}">${answers[i]}</option>;`
				}
				dom.answers.innerHTML += `
				<li>
					<select name="select">
					${answersHTML}
					</select>
				</li>
				`;
			}
			else { // если тип вопроса radio или checkbox
				let answers = question.answers;
				this.shuffle(answers); // перемешываем порядок вывода ответов
				for ( let i = 0; i < answers.length; i++ ) {
					dom.answers.innerHTML += `
						<li>
						<input type="${question.type}" id="answer${i+1}" name="answer" value="${answers[i]}">
						<label for="answer${i+1}">
							${answers[i]}
						</label>
						</li>
					`;
				}
			}
		}
	}

	// функция, которая меняет порядок элемнтов массива
	shuffle(array) {
		return array.sort(() => Math.random() - 0.5);
	}

	// если ни один инпут не выбран то вернет false, если выбран(даже не правильно) то вернет true
	checkAnswer() {
		let question = this.getQuestion(step);
		let correct = question.correct; // Если тип radio || select || text || number то у нас только ответ, если тип checkbox то у нас массив ответов
		
		// если input это текстовое поле
		if ( question.type == 'text' || question.type == 'number' ) {
			let value = this.dom.testContent.querySelector('input').value.toLowerCase();
			if ( value.trim() == '' ) {
				return false;
			} else {
				if ( typeof correct == 'string' ) {
					correct = correct.toLowerCase();
				}
				this.checkValueWithCorrectAnswer(value, correct, question.score);
				return true;
			}
		}
		else if ( question.type == 'select' ) {
			let value = this.dom.testContent.querySelector('select').value.toLowerCase();
			if ( value.trim() == '' ) {
				return false;
			} else {
				if ( typeof correct == 'string' ) {
					correct = correct.toLowerCase();
				}
				this.checkValueWithCorrectAnswer(value, correct, question.score);
				return true;
			}
			this.checkValueWithCorrectAnswer(value, correct, question.score);
		}

		else { // if question.type == 'radio' or question.type == 'checkbox'

			let answers = this.dom.testContent.querySelectorAll('input:checked'); // варианты ответов

			if ( question.type == 'radio' ) {
				// если не выбран ни один ответ
				if ( answers.length === 0 ) {
					return false;
				}
				let value = answers[0].value;
				this.checkValueWithCorrectAnswer(value, correct, question.score);
			}
			else if ( question.type == 'checkbox' ) {
				// если не выбран ни один ответ
				if ( answers.length === 0 ) {
					return false;
				}

				// высчитываем сколько баллов за одно задание мы получаем
				let score = question.score / correct.length;

				for ( let i = 0; i < answers.length; i++ ) {
					let value = answers[i].value;
					for ( let q = 0; q < correct.length; q++ ) {
						this.checkValueWithCorrectAnswer(value, correct[q], score);
					}
				}
				// чтобы нельзя было выбрать сразу все варианты и получить баллы
				if ( answers.length > correct.length ) {
					this.score -= score * (answers.length - correct.length);
					if ( this.score < 0 ) {
						this.score = 0;
					}
				}
			}
			return true;
		}
	}

	checkValueWithCorrectAnswer(value, correctAnswer, score) {
		if ( typeof correctAnswer == "number" ) {
			if ( +value == correctAnswer ) {
			this.score += score;
		}
		} else {
			if ( value == correctAnswer ) {
				this.score += score;
			}
		}
	}

	getMaxScore() {
		let data = this.data;
		let maxScore = Object.keys(data).reduce(
			function(accum, value) {
				return accum += data[value].score;
			},
		0);
		return maxScore;
	}

	end() {
		this.dom.answers.innerHTML = `
		${this.textEnd}
		${Math.ceil(this.score)} из ${this.getMaxScore()}
		`;
		this.dom.question.innerHTML = '';
		this.dom.btn.classList.remove(this.btnNextClass);
		this.dom.btn.classList.add(this.btnAgainClass);
		this.dom.btn.textContent = this.btnAgainText;
		console.log(`Точный результат: ${this.score}`);
		this.score = 0;
	}
}

  • Вопрос задан
  • 133 просмотра
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
от 200 000 до 250 000 ₽
Sportmaster Lab Санкт-Петербург
от 200 000 до 300 000 ₽
4People Санкт-Петербург
До 320 000 ₽
02 окт. 2022, в 02:55
7000 руб./за проект
01 окт. 2022, в 20:34
20000 руб./за проект