MVC+OOP重构JS项目报seatsIndex is not a function错误咨询
错误原因
- 实例化顺序错误:
const app = new Controller(new Model(), new View());这行代码会先执行new View()触发View的构造函数,构造函数里直接调用了this.updateSelectedSeats(),此时Controller还未初始化,也没有给View绑定handleSelectedSeats回调,updateSelectedSeats接收的seatsIndex参数是undefined,调用就直接抛出类型错误。 - View内部多处调用
updateSelectedSeats时未传参:点击座位的事件回调、电影选择切换的事件回调中,调用updateSelectedSeats都没有传入处理函数作为参数,就算第一次错误修复,后续触发这些事件也会报同样的错。
修复方案
调整逻辑给View增加存储回调的实例属性,等Controller绑定完回调后再执行第一次数据更新,修改后的代码如下:
修改View类
class View { screenContainer = document.querySelector('.screen__container'); unoccupiedSeats = document.querySelectorAll( '.seat__row .seat__position:not(.seat__occupied)' ); count = document.querySelector('#checkout__text--count'); total = document.querySelector('#checkout__text--total'); // 新增存储座位更新回调的属性 #seatsIndexHandler = null; constructor() { this.movieSelect = document.querySelector('#movie'); this.ticketPrice = +this.movieSelect.value; this.populateUI(); this._seatHandler(); // 移除构造函数内的updateSelectedSeats调用,等回调绑定完成后再执行 } _seatHandler() { this.screenContainer.addEventListener('click', e => { const seat = e.target.classList.contains('seat__position'); const occupied = e.target.classList.contains('seat__occupied'); if (seat && !occupied) e.target.classList.toggle('seat__selected'); this.updateSelectedSeats(); }); } bindSetMovieData(handler) { this.movieSelect.addEventListener('change', e => { this.ticketPrice = +e.target.value; handler(e.target.selectedIndex, e.target.value); this.updateSelectedSeats(); }); } // 新增绑定座位回调的方法 bindSeatsIndex(handler) { this.#seatsIndexHandler = handler; // 绑定完成后执行第一次更新 this.updateSelectedSeats(); } updateSelectedSeats() { const selectedSeats = document.querySelectorAll( '.seat__row .seat__selected' ); const index = [...selectedSeats].map(seat => [...this.unoccupiedSeats].indexOf(seat) ); // 回调存在时才执行 if (typeof this.#seatsIndexHandler === 'function') { this.#seatsIndexHandler(index); } const numSeats = selectedSeats.length; this.count.innerText = numSeats; this.total.innerText = numSeats * this.ticketPrice; } populateUI() { const selectedSeats = JSON.parse(localStorage.getItem('selectedSeats')); if (selectedSeats !== null && selectedSeats.length > 1) this.unoccupiedSeats.forEach((seat, index) => { if (selectedSeats.indexOf(index) > -1) seat.classList.add('seat__selected'); }); const selectedMovieIndex = localStorage.getItem('selectedMovieIndex'); if (selectedMovieIndex !== null) { this.movieSelect.selectedIndex = selectedMovieIndex; } this.ticketPrice = localStorage.getItem('selectedMoviePrice'); } }
修改Controller类
class Controller { constructor(model, view) { this.model = model; this.view = view; this.view.bindSetMovieData(this.handleSetMovieData); // 绑定座位处理回调 this.view.bindSeatsIndex(this.handleSelectedSeats); } handleSetMovieData = (index, value) => { this.model.setMovieData(index, value); }; handleSelectedSeats = index => { this.model.selectedSeats(index); }; }
Model类和实例化代码不需要修改,修改后即可正常运行。
内容的提问来源于stack exchange,提问作者jean_vw
相关产品推荐
相关产品推荐

