I use the prototype chain to write a method of linking provinces and municipalities. I put the variables into the initial function so that I can use the prototype chain to expand. There was no problem during initialization, but something went wrong when I used onchange to select a province or city. The attribute options of selectProvince and selectCity could not be found. I looked up and found that selectProvince and selectCity were not detected at all when using onchange. Yeah, I obviously initialized it in AddressInit, but it wasn't detected. Could you please give me a solution?
Code:
//This is a short piece of json
var provinceList = [{
name: '北京',
cityList: [{
name: '市辖区',
areaList: ['东城区', '西城区', '崇文区', '宣武区', '朝阳区', '丰台区', '石景山区', '海淀区', '门头沟区', '房山区', '通州区', '顺义区', '昌平区', '大兴区', '怀柔区', '平谷区']
}, {
name: '县',
areaList: ['密云县', '延庆县']
}]
}];
//This is html
<select class="select-input" name="selectProvince" id="selectProvince"></select>
<select class="select-input" name="selectCity" id="selectCity"></select>
<select class="select-input" name="selectArea" id="selectArea"></select>
//This is js
var AddressInit = function(selectProvince, selectCity, selectArea, defaultProvince, defaultCity, defaultArea){
this.selectProvince = document.getElementById(selectProvince);
this.selectCity = document.getElementById(selectCity);
this.selectArea = document.getElementById(selectArea);
this.defaultProvince = defaultProvince || '';
this.defaultCity = defaultCity || '';
this.defaultArea = defaultArea || '';
}
AddressInit.prototype = {
constructor: AddressInit,
//初始化
init: function(){
for (var i = 0; i < provinceList.length; i++) {
this.selectAddOption(this.selectProvince, provinceList[i].name, provinceList[i]);
}
this.selected(this.selectProvince, this.defaultProvince);
this.changeProvince();
this.selectProvince.onchange = this.changeProvince;
},
//判断是否有选中的值
selected: function(select,str){
for(var i = 0; i < select.options.length; i++) {
if (select.options[i].value == str) {
select.selectedIndex = i;
return;
}
}
},
//添加option
selectAddOption: function(select, str, obj) {
var option = document.createElement("option");
select.options.add(option);
option.innerText = str;
option.value = str;
option.obj = obj;
},
//改变省
changeProvince: function(){
console.log(selectCity);
this.selectCity.options.length = 0;
this.selectCity.onchange = null;
if (this.selectProvince.selectedIndex == -1) return;
var item = this.selectProvince.options[this.selectProvince.selectedIndex].obj;
for (var i = 0; i < item.cityList.length; i++) {
this.selectAddOption(this.selectCity, item.cityList[i].name, item.cityList[i]);
}
this.selected(this.selectCity, this.defaultCity);
this.changeCity();
this.selectCity.onchange = this.changeCity;
},
//改变市
changeCity: function(){
this.selectArea.options.length = 0;
if (this.selectCity.selectedIndex == -1) return;
var item = this.selectCity.options[this.selectCity.selectedIndex].obj;
for (var i = 0; i < item.areaList.length; i++) {
this.selectAddOption(this.selectArea, item.areaList[i], null);
}
this.selected(this.selectArea, this.defaultArea);
}
}
var ccc = new AddressInit('selectProvince', 'selectCity', 'selectArea');
ccc.init();
ringa_lee2017-05-19 10:26:13
The callback function requires the correct this environment.
Put this line
this.selectCity.onchange = this.changeCity;
changed to
this.selectCity.onchange = this.changeCity.bind(this);
滿天的星座2017-05-19 10:26:13
As mentioned above, there is a problem with this pointer:
this.selectProvince.onchange = this.changeProvince;
You mean that the handler function of select's change event is this.changeProvince
, which is a reference to it.
Actually, it is as follows:
document.getElementById(selectProvince).onchange = function(){
console.log(selectCity);
this.selectCity.options.length = 0; // 触发时报错this.selectCity为undefined 因为this是dom元素
this.selectCity.onchange = null; // 触发时报错this.selectCity为undefined
if (this.selectProvince.selectedIndex == -1) return; // 触发时报错this.selectProvince为undefined 下面的this基本都有问题 事件处理函数中this为dom元素,而不是你的实例对象。
var item = this.selectProvince.options[this.selectProvince.selectedIndex].obj;
for (var i = 0; i < item.cityList.length; i++) {
this.selectAddOption(this.selectCity, item.cityList[i].name, item.cityList[i]);
}
this.selected(this.selectCity, this.defaultCity);
this.changeCity();
this.selectCity.onchange = this.changeCity;
}
Can you see the problem? this
指的是dom对象,即document.getElementById(selectProvince)
in the event handler function certainly doesn’t have what you need.
can be replaced by this.selectCity.onchange = this.changeCity.bind(this)
this.selectCity.onchange = this.changeCity;
这样写 只是表示selectCity.onchange 也是 this.changeCity
这个函数,在js中,this的指向是实际运行时才决定,在onchange事件触发时,this.changeCity
函数内的this
为dom元素,所以就出错了。bind
方法可以替换函数内的this
points to generate a new function.
is this.changeCity.bind(this)
这句在运行时,已经将this.changeCity
函数内的this
替换为了当前的this
(this this refers to your instance object), so as to achieve the effect you need.