>

javascript做省市级联的下拉列表,不只是三个能放

- 编辑:大富豪棋牌游戏下载 -

javascript做省市级联的下拉列表,不只是三个能放

javascript做省市级联的下拉列表



object.options.add(new Option(label,value))方法向集合里添加一项option对象;
object.options.remove(index)方法移除options集合中的指定项;
object.options(index)或options.item(index)可以通过索引获取options集合的指定项;

select标记还有一个属性为selectedIndex,通过它可能获取当前选择的option索引:object.selectedIndex

 

//1.清空options集合
function optionsClear(object)
{ var length = object.options.length;
for(var i=length-1;i>=0;i--){
e.options.remove(i);
}
}

//2.添加一项新option
function addOption(object)
{ object.add(new Option(label,value));
//使用options集合中最后一项获取焦点
object.selectedIndex = object.lentht-1;
}

//3.删除options集合中指定的一项option
function removeOption(index)
{ if(index >= 0)
{ object.remove(index);
//使用options集合中最后一项获取焦点
object.selectedIndex = object.lentht-1;
}
}

//4.获取当前选定的option的真实值value
function getCurrentOptionValue(index)
{ if(index >= 0)
return object(index).value;
}

//5.获取当前选定的option的显示值label
function getCurrentOptionLabel(index)
{ if(index >= 0)
return object(index).text;
}

//下面是日期的联动下拉框:

function YYYYMMDD(){
//设置月份的集合
MonHead = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
//清除年份下拉框的所有内容,最主要包括空格
var yObj = document.form1.year
optionsClear(yObj);
//再给年下拉框赋内容
yObj.options.add(new Option("请选择",0));
for (var i = 1950; i <= new Date().getFullYear(); i  ) //以1950年为基准,到今年结束
document.form1.year.options.add(new Option(i , i));
//清除月份下拉框的所有内容,最主要包括空格
var mObj = document.form1.month;
optionsClear(mObj);
//再赋月份的下拉框
document.form1.month.options.add(new Option("请选择",0));
for (var i = 1; i < 13; i  )
document.form1.month.options.add(new Option(i,i));
//赋年份的初始值
document.form1.year.value = document.getElementsByName("YYYY")[0].value;
//赋月份的初始值
document.form1.month.value = document.getElementsByName("MM")[0].value;
//赋日期下拉框
var n = MonHead[document.form1.month.value-1];
if (document.form1.month.value ==2 && IsPinYear(YYYYvalue)) n  ;
writeDay(n);
//赋日期的初始值
document.form1.date.value = document.getElementsByName("DD")[0].value;
}

//年发生变化时日期发生变化(主要是判断闰平年)
function YYYYDD(str) {
var MMvalue = document.form1.month.options[document.form1.month.selectedIndex].value;
if (MMvalue == "") {
var e = document.form1.date;
optionsClear(e);
return;
}
var n = MonHead[MMvalue - 1];
if (MMvalue == 2 && IsPinYear(str)) n  ;
writeDay(n)
}

//月发生变化时日期联动
function MMDD(str) {
var YYYYvalue = document.form1.year.options[document.form1.year.selectedIndex].value;
if (YYYYvalue == ""){
var e = document.form1.date;
optionsClear(e);
return;
}
var n = MonHead[str - 1];
if (str == 2 && IsPinYear(YYYYvalue)) n  ;
writeDay(n)
}

//据条件写日期的下拉框
function writeDay(n) {
var e = document.form1.date;
optionsClear(e);
for (var i=1; i<(n 1); i  )
e.options.add(new Option(i,i));
}

//判断是否闰平年
function IsPinYear(year) {
return(0 == year%4 && (year0 !=0 || [email protected] == 0));
}

//清除下拉框的所有内容
function optionsClear(e) {
var length = object.options.length;
for(var i=length-1;i>=0;i--){
e.options.remove(i);
}

}
再送些福利
//1 检测是否有选中

if (objSelect.selectedIndex > - 1 ) {

// 说明选中

} else {

// 说明没有选中

}

//2 删除被选中的项

objSelect.options[objSelect.selectedIndex] = null ;

//3 增加项

objSelect.options[objSelect.length] = new Option( " 你好 " , " hello " );

//4 修改所选择中的项

objSelect.options[objSelect.selectedIndex] = new Option( " 你好 " , " hello " );

//5 得到所选择项的文本

objSelect.options[objSelect.selectedIndex].text;

//6 得到所选择项的值

objSelect.options[objSelect.selectedIndex].value;


 

 

 

object.options.add(new Option(label,value))方法向集合里添加一项option对象; object.options.remove(index)方法移除options集合...

NSMapTable 不只是一个能放weak指针的 NSDictionary

或者KVO,是一个非正式协议,它定义了对象之间观察和通知状态改变的通用机制。

NSMapTable是早在Mac OS X 10.5(Leopard)的引入集合类。乍一看,这似乎是作为一个替换NSDictionary的存在,可以选择“strong”和“week”指针。 在这篇文章中,我会告诉你除了为什么它也非常有用之外的还有垃圾回收机制以及它是如何做NSDictionary中不能(或不应该)做的事情。

基本使用

转至  http://www.isaced.com/post-235.html

使用KVO必须要满足的条件和一般使用步骤:

 

1.该对象必须支持KVC(凡是继承自NSObject的类都支持KVC)2.作为观察者的对象必须实现 -(void)observeValueForKeyPath:ofObject:change:context:方法3.被观察的对象要用- (void)addObserver:forKeyPath:options:context:方法注册观察者4.用完要移除。附上方法- (void)removeObserver:forKeyPath:或者- (void)removeObserver:forKeyPath:context:

Leopard 中更多的Cocoa API

关于这几个方法里面的参数,需要一个一个说明。从-(void)observeValueForKeyPath:ofObject:change:context:方法开始。

可可增加了几个新的集合类在Mac OS X 10.5(Leopard)的。这些措施包括:

//keyPath:被观察的属性- (void)observeValueForKeyPath:(nullableNSString*)keyPath//object:被观察的属性所属的对象ofObject:(nullableid)object//change:这是一个字典,它包含了属性被修改的一些信息。//这个字典中包含的值会根据我们在添加观察者时(addObserver方法)设置的options参数有所变化。change:(nullableNSDictionary *)change//context:添加观察者时的上下文信息,它可以被用作区分那些绑定同一个keypath的不同对象的观察者。//比如说观察一些继承自同一个父类的子类,而这些子类都有一个相同的keyPath。context:(nullablevoid*)context;

  • NSPointerArray
  • NSHashTable
  • NSMapTable

关于change字典里面的键值对,系统提供了这些预定义的key供我们使用

NSPointerArray完全是新的,但大部分的 NSHashTableNSMapTable 的功能之前可从 opaque Foundation C structs of the same names 看到。

NSKeyValueChangeKindKey可以用@"kind"替代,也就是change[NSKeyValueChangeKindKey]等价于change[@"kind"]NSKeyValueChangeNewKey可以用@"new"替代NSKeyValueChangeOldKey可以用@"old"替代NSKeyValueChangeIndexesKey可以用@"indexes"替代NSKeyValueChangeNotificationIsPriorKey可以用@"notificationIsPrior"替代

在某些方面,这些新的类,像NSMutableArrayNSMutableSet和的NSMutableDictionary一样工作,但是给了你使用“week”垃圾回收指针的选择。如果您使用的 Objective-C 2.0 垃圾回收机制,你应该知道什么是使用“week”指针,因此使用此选项的优势应该是清楚的。

change字典里面会有哪些key出现取决于在addObserver方法中options参数的设置情况。(如果有人在看这篇文章的话建议先看下面addObserver方法参数和NSKeyValueObservingOptions的那部分内容,然后再回来看这段,因为这里的key和options关联很大。原谅我- -||)NewKey和OldKey很简单,就是options设置NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld时会在change里加入的键值对。

NSPointerArray也可用于纯指针(指针不一定是Objective-C的类),但NSHashTable和的NSMutableArray类都需要它们的内容是Objective-C的对象。

NSKeyValueChangeNotificationIsPriorKey是在设置了NSKeyValueObservingOptionPrior选项后当被观察的值将要改变(但是还未改变)时发送的通知里会有的key,对应的是一个布尔值。

虽然在一般意义上,NSPointerArray and NSHashTable 被设计为可以替换 NSMutableArray and NSMutableSet 的角色(有序和无序阵列)。
NSMapTable则是不同的,因为它可以在你的设计中使用,而NSMutableDictionary不能(或不应该)。

NSKeyValueChangeKindKey对应的value是一个枚举值(NSKeyValueChange,就是下面这个),当被观察的值被设置时(setter方法调用时)KindKey对应的值为1(NSKeyValueChangeSetting)。

 

如果观测的值是一个可变数组,那么当数组执行插入,删除,替换时kindKey会对应Insertion,Removal和Replacement。

NSDictionary的局限性

typedefNS_ENUM(NSUInteger,NSKeyValueChange) {NSKeyValueChangeSetting= 1,NSKeyValueChangeInsertion= 2,NSKeyValueChangeRemoval= 3,NSKeyValueChangeReplacement= 4,};

NSDictionary提供了key-to-object的映射。从本质上讲,NSDictionary中存储的object位置是由“key”来索引的。

NSKeyValueChangeIndexesKey:当NSKeyValueChangeKindKey对应了2/3/4这几个值得时候,这个key的value是一个NSIndexSet,包含了发生insert,remove,replace的对象的索引集合。如果这个时候打印一下change字典大概会看到里面这样的一个键值对。

由于对象存储在特定位置,NSDictionary中要求key的值不能改变(否则object的位置会突然错误)。为了保证这一点,NSDictionary中始终复制key到它私有位置。

indexes="<_NSCachedIndexSet: 0x7fde0a50cd20>[number of indexes: 1 (in 1 ranges), indexes: (0)]";

这个key的复制行为也是NSDictionary如何工作的基础,但这也有一个限制:你可以只使用Objective-C对象作为 NSDictionary的key,如果它支持NSCopying协议。此外,key应该是小且高效的,以至于复制的时候不会对CPU和内存造成负担。

大富豪棋牌游戏下载,然后是- (void)addObserver:forKeyPath:options:context:方法,这个方法在调用时,观察者和被观察者对象的引用计数都不会增加。也就是在对象被释放之后,如果KVO的监听信息依然存在的话会导致程序崩溃。所以在适当的时候要记得使用removeObserver方法将观察者信息remove掉。

这意味着,NSDictionary中真的只有适合“value”类型的对象作为key(如简短字符串和数字)。这不是离线的对象到对象的映射模型。

//observer:观察者对象,也就是实现了observeValueForKeyPath:ofObject:change:context:方法的对象- (void)addObserver:(NSObject *)observer//keyPath:被观察的属性forKeyPath:(NSString *)keyPath//options:监听选项,这个值可以是NSKeyValueObservingOptions选项的组合//也就是可以这么写(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)options:(NSKeyValueObservingOptions)options//context:同上面的方法context:(nullablevoid*)context;

 

关于NSKeyValueObservingOptions,里面一共有四个值:

对象到对象的映射

//设置后会在observeValueForKeyPath方法的change字典里存入更新后的值。NSKeyValueObservingOptionNew//设置后会在observeValueForKeyPath方法的change字典里存入更新前的值,也就是原有的值。NSKeyValueObservingOptionOld//设置后会在添加观察者的时候立即发送一次通知给观察者,并且在注册观察者方法之前返回。//也就是在addObserver方法执行之后就立即发送了一次通知。NSKeyValueObservingOptionInitial//会在值被改变之前发送一次通知,并且在change字典里多了一个叫notificationIsPrior的key,值是1。//而且change字典不会包含new(NSKeyValueChangeNewKey)这个key。//当然值改变后的那次通知也会发,也就是说会发送两次通知。NSKeyValueObservingOptionPrior

NSMapTable(顾名思义)更适合于一般意义的映射。这取决于它是如何构造的,NSMapTable可以处理的“key-to-object”样式映射的NSDictionary,但它也可以处理“object-to-object”的映射

当观察者不再需要监听属性变化时,需要使用- (void)removeObserver:forKeyPath: 或者- (void)removeObserver:forKeyPath:context:来移除观察者,需要注意的是如果移除了一个没有观察过的属性,程序会抛出异常。也就是说如果之前观察的是"property1",而在移除的时候keyPath参数写的是"property2",这是就会有异常被抛出。可以使用@try/@catch来防止崩溃。

  • 也被称为“associative array”或简称为“map”。

@try{[object removeObserver:observer forKeyPath:@"keyPath")];}@catch(NSException * __unused exception) {}

例如,一个NSMapTable构造如下:

手动通知

NSMapTable *keyToObjectMapping =
    [NSMapTable
        mapTableWithKeyOptions:NSMapTableCopyIn
        valueOptions:NSMapTableStrongMemory];

默认情况下通知会被自动发送,但有的时候我们希望可以手动的控制它。这时候需要在被观察对象的类里面重写 (BOOL)automaticallyNotifiesObserversForKey:方法。例如被观察对象有一个属性叫"bankCodeEn",我们希望这个属性被修改时的通知由我们手动控制,就需要在被观察对象的类文件里面这样写:

将会和NSMutableDictionary工作得一样一样的,复制其“key”,并retaining它的“object”。

(BOOL)automaticallyNotifiesObserversForKey:(NSString*)key{// 如果属性为bankCodeEn则关闭自动发送通知BOOLautomatic =YES;if([key isEqualToString:@"bankCodeEn"]) {      automatic =NO;  }else{// 对于对象中其它没有处理的属性,我们需要调用[super automaticallyNotifiesObserversForKey:key],以避免无意中修改了父类的属性的处理方式automatic = [superautomaticallyNotifiesObserversForKey:key];  }returnautomatic;}

一个纯粹的对象到对象(object-to-object)的映射可以构造如下:

然后再对"bankCodeEn"属性的setter方法做如下处理:

NSMapTable *objectToObjectMapping =
    [NSMapTable mapTableWithStrongToStrongObjects];

- (void)setBankCodeEn:(NSString *)bankCodeEn{//当两次赋予的值完全相等时,没有必要再发送通知。这个if的条件语句可以根据实际需要自行修改,或者干脆不写。if(_bankCodeEn != bankCodeEn) {      [selfwillChangeValueForKey:@"bankCodeEn"];      _bankCodeEn = bankCodeEn;      [selfdidChangeValueForKey:@"bankCodeEn"];  }}

一个对象到对象(object-to-object)的行为可能以前可以用NSDictionary来模拟,如果所有的key都是一个 NSNumber包含于该映射的源对象的内存地址(不要笑,我见过这种情况),但这些内存地址都是奔波在外,Cocoa中首次提供了一个真正的对象到对象 的映射NSMapTable。

注意 willChangeValueForKey:和didChangeValueForKey:方法在默认自动发送通知的情况下是由系统自动调用的,在手动通知时需要我们自己来调用,并且不应该重写这两个方法。

 

注册依赖建

NSMapTable的选项

有时一个属性的改变需要依赖其他的属性,比如一个叫"fullName"的属性,这个属性依赖于"firstName"和"lastName"。

NSMapTable提供的选项是由三部分组成:一个“memory option”(内存选项),一个“personality option”和“copy in”标志。你可以为每个部分使用一个选项(如果没有提供一个选项的部分将会使用默认行为),这个部分都是位标志(bit flag)(二进制 “or” 合并在一起)。

//fullName的getter方法- (NSString*)fullName{return[NSStringstringWithFormat:@"%@  %@", _firstName, _lastName];}

理论上,NSMapTable允许以下选项:

这种情况下如果firstName发生了变化,fullName的值自然也会改变,但是由于没有直接使用setter方法设置fullName,所以如果不做特殊设置的话KVO是不会发送通知的。

  • NSMapTableStrongMemory (a "memory option")
  • NSMapTableWeakMemory (a "memory option")
  • NSMapTableObjectPointerPersonality (a "personality option")
  • NSMapTableCopyIn (a "copy option")

这种情况就需要使用注册依赖建来解决。

NSMapTableStrongMemory是默认的“memory option”。然而,默认的“personality option”,默认“copy in”的行为没有名字那么这两个值可以被视为隐含在列表中。

(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key{  NSSet *keyPaths = [superkeyPathsForValuesAffectingValueForKey:key];if([keyisEqualToString:@"fullName"]) {      keyPaths = [keyPathssetByAddingObjectsFromArray:@[@"firstName", @"lastName"]];  }returnkeyPaths;}

memory option

Objective-C使用“strong”和“week”作为垃圾回收机制相关的术语,它可能不是很明显,这些选项可以在垃圾回收机制代码之外使用(苹果称它为手动内存管理)。

在垃圾回收机制外,他们被定义为:

  • strong: 使用 retain 和 release
  • weak: 不使用 retain 和 release

NSMapTable只允许NSPointerFunctionsOptions对应的Objective-C对象“personality option”。还有其他NSPointerFunctionsOptions “personality option”里的“strong”指针的行为不包括retain和release,但这些选项在NSMapTable都是不允许的。

关于使用垃圾回收机制的“week”之外的警告:
指针将不会被归零如在垃圾回收环境所以你必须要小心,不要取消引用指针,如果它被释放。

这样不论firstName,lastName,fullName中的哪个值放生了变化,监听fullName的KVO都会被触发。还可以使用这个方法来达到同样的目的。

Personality options

该NSMapTableObjectPointerPersonality选项用来控制是否isEqualTo:和哈希对象中的方法添加的对象添加到集合时使用。

  • NSMapTableObjectPointerPersonality指定
    对象的指针的值是用于直接比较和位移哈希生成(isEqualTo:和散列方法是不使用)。
  • NSMapTableObjectPointerPersonality 不指定(默认行为)
    的哈希值与isEqualTo:方法会在调用的关键在确定的存储位置NSMapTable。这些方法的返回值不应改变(是不可变)为主要用在时间NSMapTable。

两行为暗示内容实现了NSObject的协议,所以在这个协议方法也可以在key和object调用。特别地,描述的方法可以在被调用NSMapTable包含密钥和对象无论使用的“Personality options”。该NSMapTable将只支持NSCoding如果所有的key和object实现了NSCoding协议了。

(NSSet*)keyPathsForValuesAffectingFullName {return[NSSetsetWithObjects:@"firstName",@"lastName",nil];}

Copy options

如果NSMapTableCopyIn被指定,当NSCopying协议被加入时NSMapTable使用使自己的数据副本。如果不指定此选项(默认行为)将不会复制。


翻译自:NSMapTable: more than an NSDictionary for weak pointers

这篇文章虽然很久了(2008年),但就算放在当下也是很有学习价值的,感谢Google translate,感谢Baidu translate!

 

 

 

这个方法的使用规则是 (NSSet *)keyPathsForValuesAffecting 属性名(注意属性名首字母大写)。

属性类型为集合的监听

对于集合的KVO,我们需要了解的一点是,KVO旨在观察关系(relationship)而不是集合。对于不可变集合属性,我们更多的是把它当成一个整体来监听,而无法去监听集合中的某个元素的变化;对于可变集合属性,实际上也是当成一个整体,去监听它整体的变化,如添加、删除和替换元素。

例如一个叫arr的NSArray类型属性,我们可以使用集合代理对象(collection proxy object)来处理集合相关的操作。有下面的几个代理方法需要实现

-countOf// 以下两者二选一-objectInAtIndex:-AtIndexes:// 可选(增强性能)-get:range:

具体实现如下

- (NSUInteger)countOfArr{return[_arrcount];}- (id)objectInArrAtIndex:(NSUInteger)index{return[_arr objectAtIndex:index];}

当我们使用对象的arr属性时,通过[object valueForKey:@"arr"]来获取该属性,这个方法返回的代理数组对象支持所有正常的NSArray调用。换句话说,调用者并不知道返回的是一个真正的NSArray,还是一个代理的数组。

对于可变数组的操作

对于可变数组的代理对象,我们需要实现以下几个方法:

// 至少实现一个插入方法和一个删除方法-insertObject:inAtIndex:-removeObjectFromAtIndex:-insert:atIndexes:-removeAtIndexes:// 可选(增强性能)以下方法二选一-replaceObjectInAtIndex:withObject:-replaceAtIndexes:with:

实现如下

- (NSUInteger)countOfArr{return[_arr count];}- (id)objectInArrAtIndex:(NSUInteger)index{return[_arrobjectAtIndex:index];}- (void)insertObject:(id)objectinArrAtIndex:(NSUInteger)index{  [_arrinsertObject:objectatIndex:index];}- (void)removeObjectFromArrAtIndex:(NSUInteger)index{  [_arrremoveObjectAtIndex:index];}- (void)replaceObjectInArrAtIndex:(NSUInteger)indexwithObject:(id)object{  [_arrreplaceObjectAtIndex:indexwithObject:object];}

方法实现后,需要使用[object mutableArrayValueForKey:@"arr"]来访问arr属性才能或取到代理数组。在使用时访问真正数组对象和集合代理对象差别还是很大的。

BankObject*bankInstance = [[BankObjectalloc] init];PersonObject*personInstance = [[PersonObjectalloc] init];[bankInstance addObserver:personInstance forKeyPath:@"departments"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:NULL];bankInstance.departments = [[NSMutableArrayalloc] init];[bankInstance.departments addObject:@"departments"];

这段代码BankObject是被观察对象,PersonObject是观察者对象。BankObject类里面有一个叫departments的可变数组属性。

这段代码只会触发一次KVO,也就是只有在给departments赋予一个初始化数组的时候KVO被触发,在给数组添加内容的时候并没有触发。

BankObject*bankInstance = [[BankObjectalloc] init];PersonObject*personInstance = [[PersonObjectalloc] init];[bankInstance addObserver:personInstance forKeyPath:@"departments"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:NULL];bankInstance.departments = [[NSMutableArrayalloc] init];NSMutableArray*departments = [bankInstance mutableArrayValueForKey:@"departments"];[departments insertObject:@"departments 0"atIndex:0];

使用集合代理对象的方式会触发两次KVO,在给数组插入(删除,替换)数据的时候KVO也会被触发。

监听信息

对于被观察的对象,可以使用observationInfo属性获取都有哪些观察者观察了哪些属性。

id info = bankInstance.observationInfo;

NSLog(@"%@", [info description]);

如果像这样获取了一个被观察对象的info然后打印出来,会看到这样的结果。

(Context:0x0,Property:0x7fdc236a15c0>Context:0x0,Property:0x7fdc236a1880>)

我们可以看到observationInfo指针实际上是指向一个NSKeyValueObservationInfo对象,它包含了指定对象上的所有的监听信息。而每条监听信息而是封装在一个NSKeyValueObservance对象中,从上面可以看到,这个对象中包含消息的观察者、被监听的属性、添加观察者时所设置的一些选项、上下文信息等。

其他的一些小tips

1、如果重复添加注册观察者的方法(addObserver),比如像这样完全一样的两句代码重复两次,那么通知也就会发送两次,系统不会检查也不会替换覆盖。

[bankaddObserver:per1forKeyPath:NSStringFromSelector(@selector(departments))options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];[bankaddObserver:per1forKeyPath:NSStringFromSelector(@selector(departments))options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];

2、因为keyPath是字符串类型,这就导致写错的情况很容易发生,keyPath写错严重的话就会导致程序崩溃。所以为了避免这种情况,可以将@"property"替换成NSStringFromSelector(@selector(property)),这样写首先在敲属性名的时候会有提示,而且在你把属性名敲错的时候由于xcode没有在对应的类里面找到那个被你写错的属性,就会报出警告。像这样:

[bankaddObserver:per1forKeyPath:NSStringFromSelector(@selector(departments))options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:nil];

3、关于context可以这样设置,一个静态变量存着它自己的指针。这意味着它自己什么也没有。

staticvoid* XXContext = &XXContext;

关于KVO的实现机制

KVO使用了OC的runtime来实现,在第一次观察一个对象时,runtime会创建一个继承自被观察对象的类的子类,这个子类重写了被观察属性的setter方法,然后将这个对象的is a指针指向了这个新建的类。也就是说其实这个被观察的对象在程序运行时所属的类已经不是之前我们自己写的那个类了,而是系统创建的子类。

本文由大富豪棋牌游戏二维码发布,转载请注明来源:javascript做省市级联的下拉列表,不只是三个能放