[转载]SQL Server中char、nchar、varchar、nvarchar的区别 - 无风听海 - 博客园

mikel阅读(927)

[转载]SQL Server中char、nchar、varchar、nvarchar的区别 – 无风听海 – 博客园.

对于程序中的一般字符串类型的字段,SQL Server中有char、varchar、nchar、nvarchar四种类型来对应,那么这四种类型有什么区别呢,这里做一下对比。

1.定长或变长

所谓定长就是长度固定,当要保存的数据长度不够时将自动在其后面填充英文空格,使长度达到相应的长度;有var前缀的,表示是实际存储空间是动态变化的,比如varchar,nvarchar变长字符数据则不会以空格填充。

2.Unicode或非Unicode

数据库中,英文字符只需要一个字节存储就足够了,但汉字和其他众多非英文字符,则需要两个字节存储。如果英文与汉字同时 存在,由于占用空间数不同,容易造成混乱,导致读取出来的字符串是乱码。Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符 都用两个字节表示,即英文字符也是用两个字节表示。而前缀n就表示Unicode字符,比如nchar,nvarchar,这两种类型使用了 Unicode字符集。

3.几种数据类型的存储的最大容量

char,varchar 最多8000个英文,4000个汉字

nchar,nvarchar  最多可存储4000个字符,无论英文还是汉字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
--创建表
CREATE TABLE TempTable(
    id INT PRIMARY KEY,
    charField CHAR(10),
    varcharField VARCHAR(10),
    nvarcharField NVARCHAR(10)
)
INSERT INTO TempTable VALUES(1,'WFTH','WFTH','WFTH')
INSERT INTO TempTable VALUES(2,'无风听海','无风听海','无风听海')
INSERT INTO TempTable VALUES(3,'','','')
INSERT INTO TempTable(id) VALUES(4)
INSERT INTO TempTable VALUES(5,'1234567890','1234567890','12345')
SELECT DATALENGTH(charField) AS charFieldLen,
       DATALENGTH(varcharField) AS varcharFieldLen,
       DATALENGTH(nvarcharField) AS nvarcharFieldLen
FROM temptable WHERE id =1
SELECT DATALENGTH(charField) AS charFieldLen,
       DATALENGTH(varcharField) AS varcharFieldLen,
       DATALENGTH(nvarcharField) AS nvarcharFieldLen
FROM temptable WHERE id =2
SELECT DATALENGTH(charField) AS charFieldLen,
       DATALENGTH(varcharField) AS varcharFieldLen,
       DATALENGTH(nvarcharField) AS nvarcharFieldLen
FROM temptable WHERE id =3
SELECT DATALENGTH(charField) AS charFieldLen,
       DATALENGTH(varcharField) AS varcharFieldLen,
       DATALENGTH(nvarcharField) AS nvarcharFieldLen
FROM temptable WHERE id =4
SELECT DATALENGTH(charField) AS charFieldLen,charField,
       DATALENGTH(varcharField) AS varcharFieldLen,varcharField,
       DATALENGTH(nvarcharField) AS nvarcharFieldLen,nvarcharField
FROM temptable WHERE id =5

[转载]ERP框架开发中的License许可验证机制设计与实现 (包含源代码下载) - James Li - 博客园

mikel阅读(1307)

[转载]ERP框架开发中的License许可验证机制设计与实现 (包含源代码下载) – James Li – 博客园.

许可机制是ERP框架中必不可少的一部分,可以有效的保护框架资源在授权范围内应用,增 加企业投资的回报。在研究了几种类型的许可机制(序列号注册码,Web服务联机验证,授权License文件)后,最后选定以Signed Xml配合RSA算法,作为许可机制的主要技术实现。

主要达到的目的如下

1  可以实现版本控制。企业版可使用所有的功能,专业版只可用部分功能,个人版免费使用,但功能集更少。

public enum Version {  Enterprise, Professional, Personal }

2  功能点的控制上,同时在线用户数量控制,帐套数量控制,硬件验证控制,试用过期控制,虚拟机控制。

  • 在线用户数量 可以控制同时在线的用户数量,超过许可数量,则无法登陆
  • 帐套数量控制 比如,只可以建立10套帐,超过此限制则无法登陆
  • 硬件验证控制 生成许可文件时,会绑定硬件信息(硬盘,CPU,内存,主板),以此硬件信息生成的许可文件,不可以在别的电脑上运行,以控制用户数量。
  • 试用过期控制 超过期限则停止进入系统,有效阻止未授权用户的继续使用,收回投资
  • 虚 拟机控制  因为虚拟机中安装与还原操作系统非常容易方便,我们常以此来试用软件,当软件试用到期后还想继续用,则只需要的还原一下虚拟机中的系统,则可以继续体验。 以此选项,控制软件不可以运行于虚拟机中。常见的虚拟机即VMware Workstation和Virtual PC。

以此理论,设计如下格式的License.lic文件,以作为要颁发的许可证文件。

image

 

在程序编写过程中,参考了CodeProject网站中的文章

Using XML Digital Signatures for Application Licensing – CodeProject
http://www.codeproject.com/Articles/4940/Using-XML-Digital-Signatures-for-Application-Licen

几乎就是对这篇文章的定制,就可以完成以上所需要达到的目的。以下分享几个遇到的实际问题,供您参考。

1 Xml序列时,元素的顺序。通过Google得知,请仔细阅读以下的几段话。

XmlSerializer takes all fields in the order that they are declared.
the order problem on the Compact Framework.Unfortunately, this is by Design.

The order of elements serialized by the NETCF xml serializer is not
guaranteed to match that of the desktop. There is nothing in the generated
schema class included in the attached project that specifies the order of
the elements.

In order to accomplish this you should add the /order option to xsd.exe and
then regenerate the schema class
(xsd.exe /order /c foo.xsd)

By doing this all the particle members will have their explicit order
identifiers and then the serializer will honor the order of the schema. The
new schema generated by with the /order switch will have the orders
property specified on the XmlElementAttribute
e.g. [System.Xml.Serialization.XmlElementAttribute(Order = 2)]

Xml序列化以元素声明的顺序,但是Compack Framework不一样,需要手动指定它们的顺序。

 

2 硬件信息的集成绑定

这应该是一个名值对,比如

CPU: Intel Pentium T440

Hard Driver: WD Elements

所以,需要设计一个List<HardwareInfo>,或是继承于CollectionBase。

public struct HardwareInfo 
{  
public string HardwareId { get;set;} 

public string Description { get;set;}

}

这个List<T>要可以序列化,它要绑定到License.lic文件中。

 

3 类型中,有些对象不需要序列化的,要加上标签以阻止序列化。

[NonSerialized]
private string _hashValue;

4  生成公钥和私匙配对,然后放到代码中去。生成的内容如下

  public static string PrivateKey
        {
            get
            {
                return "<BitStrength>1024</BitStrength><RSAKeyValue><Modulus>uCMDxXTd0bNbiAFrOYjbiGyQpqfZY2Znn70hoQZsprNoXV8tSZ6mM8VswoTNh6S+0qfYntzxpQq29mqv+8mUIuGN/30YpUq9tZFR1bIHEJnPqSRHcQa0ezimTilBN7EN7J6wnQBQqFyt3ZRnLYUsRta1Vjdn4eEc50Q4EfEOlO8=</Modulus><Exponent>AQAB</Exponent><P>99QWQo0ulkBCDyHwL3amXKahDSmcGa3bJHz23M++65jtxYp0LViGH+ngr5FYSxp7oAj37dKTiw4h6NO/+J6amw==</P><Q>vjVO29oMfKynSHZgRIeRhcInt6ReHm19of8YIsvBVYgasg9qi0lONFUvmW51fPrXdTPWz4fHmlnv3leWN7AaPQ==</Q><DP>tiyKHGvJthsQNC1/cHRogCzgsFtI6zt4no7ZrKFtt6PYDODk27x6A5WZW5Wc8MBL5e0RyxmC6bH+zTZypGB6Rw==</DP><DQ>Rr/bYkl75Y/u9TQa4MKwbVlnnpZD7/t4BJ63IpI5ipACpgK39bFBppOdDewZRXCkXdL3buApbY9QepqHpJUbXQ==</DQ><InverseQ>zZu/5jmI8PSbo1e6nXfaAtzZQiSUO0q3D1Dm30w51lukRw8OlkmrMOszLF7LontM/4kLhmri2BU5yeTChppXLQ==</InverseQ><D>q5JsrCqlmQRfEA4KY9Siga5u5epWA2liupOW5xw+VuGqJ/5MC2HZCTo2idUGURJvf4dHr1a9jgO60UY9bgW4kWOkLdZ3xzn0wqYyt/VCdvQE1qH/YnVEeLUZqjrbH14Zw8isR2Yxf33QCFfvHWTqIvwtm0ZdniH+cEIRgEwsPNk=</D></RSAKeyValue>";
            }
        }

        public static string PublicKey
        {
            get
            {
                return "<BitStrength>1024</BitStrength><RSAKeyValue><Modulus>uCMDxXTd0bNbiAFrOYjbiGyQpqfZY2Znn70hoQZsprNoXV8tSZ6mM8VswoTNh6S+0qfYntzxpQq29mqv+8mUIuGN/30YpUq9tZFR1bIHEJnPqSRHcQa0ezimTilBN7EN7J6wnQBQqFyt3ZRnLYUsRta1Vjdn4eEc50Q4EfEOlO8=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
            }
        }

公钥只可以拿来验证许可文件,私匙可以验证,但主要的是用来生成Xml文件签名。

 

5 请注意License文件的最后一个节,它放的是绑定的硬件信息,这一节信息是加密的。为了可以解密,这里用RSA算法。这个过程如下,用户试用软件,申 请许可文件,给用户一个EXE文件程序,用于生成hardware.id文件,然后用户将此文件发给软件公司,软件公司依据此文件,向用户发放试用许可文 件。

 string hardware = RSACryptionHelper.EncryptString(inputString, publicKey);

当用户将绑定有硬件信息的许可拿到别的电脑上运行时,会报异常

 if ((configuration.Items.Count == 0) && (this.LicenseType == LicenseType.Enterprise))
    {
        throw new LicenseException("Hardware fingerprint is missing in license file");
    }

 

6  许可类型

public enum  LicenseType
{  
   Internal,
   Enterprise,
   Professional,
   Personal
}

所有类型的license都会过期,在license中指定的ExpiredDate之后,都将无法运行。所以没有加Trial类型的许可。

我手头有个数据库工具软件,还有800多天的试用期,可还可使用2年多一点。IT这个行业既很传统,10年的技术,C#.NET WinForms技术,现在还在普及使用中,又很超前,大量的新技术,新知识注入到这个行业中。

2年的时间内可以做很多事,看很多书,走很多路,且行且看。

 

7  Signed Xml技术的要点主要是明文查看,但可以防止篡改。眼睁睁的看着2013-5-30号就过期了,你就是没有办法把它改成2100-5-30号。这一下子可以100年后,你改了,这企业再也不能从你这里收取费用,可怎么养活程序员呢。

但是,有两个软件可以做到一个,就是篡改系统的当前时间,然后注入到你的进程中。推荐软件RunAsDate。这软件的功能强大,可以设置当前时间,然后启动软件。如果你试用一个很好的软件,又不想付费,也找不到Cracker或是KEY的话,可以试下这个办法。

image


8   ExpiryDate是2013-5-30时,但是到了这一天,用户把时间又改回到2013-4-30号,又可以继续试用一个月。对于这个问题,也要处 理。对于MIS/ERP类型的软件,也可以不用处理。对数据的主要要求之一是准确,现在是5-2号了,你把时间改回到4-2号,继续使用软件,系统的日记 帐时间也是4-2号。以后查帐的时候,这是很严重的问题。5-2号的进仓单,实际对应的是系统中的4-2号的单据,很不方便与追踪问题。

如果要控制用户改时间,则需要记住用户第一次使用系统的时间,发现用户系统时间,直接报错,异常退出。

<IssuedDate>2013-04-30T10:58:52.5456701+08:00</IssuedDate>
<ExpiryDate>2013-05-30T23:59:59.997</ExpiryDate>

 

请到如下的网页中下载源代码,供您参考。

Using XML Digital Signatures for Application Licensing – CodeProject
http://www.codeproject.com/Articles/4940/Using-XML-Digital-Signatures-for-Application-Licen

[转载]通过分析内存来优化.NET程序 - smark - 博客园

mikel阅读(920)

[转载]通过分析内存来优化.NET程序 – smark – 博客园.

最近在做一个MSMQ的Agent服务,在这里分享一下这个服务在优化的一点经验,通过分析内存更准确地定位出程序中存在的性能问题,从而让程序的性能以倍数的提升.

问题的引发

由于通过.NET MSMQ的Client实现消息分布和故障转移实在测试效果并不理想..所以决定实现一个MSMQ的Agent服务,由于有网络编写的经验所以对实现的效 果还有很有信心的.可惜最终实现出来的效果实在惨不忍睹…4个连接并发消息写入只有150/秒,实在是完全坑爹的结果!在架构上的设计并不存在问题, 所以问题一定存在程序实现过程中,以往的经验告诉自己做内存分析是最直接的办法.

问题排查一Buffer没正常回收到Pool

由于在测试过程CPU使用率并不高,所以怀疑是Buffer没有回收到Pool导致

从分析的结果来说,的确是自己在写代码的时候犯错了…存在大量的buffer被Pop出来导致大量内存被创建.但从代码流程上来看找不到任何原因.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public override void MessageWrite(IMessage msg, BufferWriter writer)
        {
            HttpData hb = msg as HttpData; 
            try
            {
                using (hb.Message)
                {
                    msg.Save(writer);
                }
            }
            finally
            {
                
                if (hb != null)
                {
                    hb.Message = null;
                    HttpDataPackage.HttpDataPool.Push(hb);
                }
            }
        }

分析结果已经说明了问题所在,所以调试了一下程序,发现问题的根源是HttpData的Message为空,但using不会报错坑爹啊…

1
2
3
4
5
6
7
public void ToProtocolData(HttpData httpbase)
        {
            httpbase.Action = Action;
            httpbase.Message = this;
            OnToProtocolData(httpbase);
            ;
        }

适当地修改一处程序问题解决.

吐能力提高但CPU占用资源过高

经过上面程序的修复4连接的秒吞吐能力由原来每秒150左右,上升到每秒2100/秒.得到的效果是非常的明显的,但总的来说CPU占用资源还有点过高,为了验证上一次修复的问题又进行了一次内存分析,分析的结果如下:

分析说明了一个问题由于Assembly.GetName()导致了大量的string创建,代码如下:

1
value = string.Format("{0},{1}={2}", type.FullName, type.Assembly.GetName().Name, JsonConvert.SerializeObject(Message));

适当地修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
value = string.Format("{0}={1}", GetTypeName(type), JsonConvert.SerializeObject(Message));
private static System.Collections.Hashtable mNames = new System.Collections.Hashtable(1024);
private static string GetTypeName(Type type)
{
    string name = (string)mNames[type];
    if (name == null)
    {
        lock (mNames)
        {
            name = (string)mNames[type];
            if (name == null)
            {
                name = string.Format("{0},{1}", type.FullName, type.Assembly.GetName().Name);
                mNames[type] = name;
            }
        }
    }
    return name;
}

经过以上的进一步优化后,服务的效果算是比较理想,完全满足了现阶段的需要.

意外的发现

从测试分析的结果看来,Newtonsoft.Json这个组件还有针对性优化的空间

针对以上分析,Newtonsoft.Json存在的问题应该如何优化,那就要留大家思考了.

总结

其实很多朋友喜欢通过CPU计时来看程序的快慢,但得到的结果只能说明问题,但对于如何解 决这些问题,测试运行时间的结果似乎起不到什么作用.其实.NET程序有一个东西往往没有得到关注,MS在一些文档中要强调我们没有必要关心,这个东西其 实就是GC!的确我们对GC的工作直接可控性是没有,但有一点可以肯定的就是GC的工作由对象的创建导致,如果想控制GC我们最好是从设计层面上控制对象 的创建,这是最直接有效的办法.

[转载]Eclipse+PyDev+Django+Mysql搭建Python web开发环境 - 海 子 - 博客园

mikel阅读(1006)

[转载]Eclipse+PyDev+Django+Mysql搭建Python web开发环境 – 海 子 – 博客园.

Eclipse+PyDev+Django+MySQL搭建Python web开发环境

Python的web框架有很多,目前主流的有Django、Tornado、Web.py等,最流行的要属Django了,也是被大家最看好的框架之一。下面就来讲讲如何搭建Django的开发环境。

一.准备工作

需要下载的软件:

JDK:官网下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk6downloads-1902814.html

Python安装包:我用的是python 2.6.6的安装包,官网下载地址是:http://www.python.org/download/releases/

Eclipse:我用的是Eclipse 3.7.2 for java ee developers版本的,官网下载地址是:

http://www.eclipse.org/downloads/packages/release/indigo/sr2

Pydev:http://sourceforge.net/projects/pydev/files/

Django:https://www.djangoproject.com/download/

MySQLhttp://www.mysql.com/downloads/mysql/

Mysql-Python:http://www.lfd.uci.edu/~gohlke/pythonlibs/

二.配置过程

我的环境是win xp,32位系统。

1.安装JDK

在JDK官网http://www.oracle.com/technetwork/java/javase/downloads/jdk6downloads-1902814.html选择合适的版本,注意32位和64位的区别。

注意安装好JDK好之后,要配置一下环境变量,具体如何安装JDK请参考我之前的文章

http://www.cnblogs.com/dolphin0520/archive/2012/03/08/2385309.html

2.安装Python

Python目前出了3.x版本的,个人觉得最好还是用2.6或者2.7版本的,2.x版本的第三方库比较多,也相对稳定。

安装好Python之后,需要配置一下环境变量,具体安装方法参考:

http://www.cnblogs.com/dolphin0520/archive/2013/03/05/2943747.html

3.安装Eclipse

Eclipse的安装包下载下来解压即可使用。

4.在Eclipse中配置Pydev

Pydev是一个Eclipse插件,使得可以在Eclipse中编写Python程序。下载好Pydev的安装包之后,解压可以看到 features和plugins两个文件夹。在Eclipse根目录下建立一个文件夹Pydev,把解压得到的两个文件夹放到Pydev文件夹下,然后 在Eclipse根目录下建立一个名为links的文件夹(若links文件夹存在则不用新建),在links文件夹下建立一个文件pydev.ini, 用记事本打开,将   path=Pydev 添加进去保存关闭即可。然后打开Eclipse,选择Window -> Preferences -> Pydev- > Interpreter-Python,然后在右侧的“Python Interpreters”面板中选择New,在弹出的对话框的 “Interpreter Name”写Python,在“Interpreter Executable”中定位到python.exe的地址,然后一直选择“ok”即可:

这里介绍的是离线安装Pydev的方法,当然可以在线进行安装,读者可以自行百度在线安装Pydev的方法。

5.安装Django

在官网https://www.djangoproject.com/download/下载了Django的安装包之后,先进行解压,然后在在cmd下进入解压的文件目录下,运行命令python setup.py install,安装完毕之后,需要配置一下环境变量,一般情况下,安装好的Django在Python安装目录的

Lib\site-packages下,然后将D:\Program Files\Python26\Lib\site-packages\django\bin;添加到系统环境变量path中(注意路径值根据个人安装情况 而定)。添加成功之后关闭cmd。再重新启动一个cmd,输入命令django-admin.py startproject mysite,如果没有提示错误,则表示安装成功。

6.安装Mysql

具体安装过程可参照:http://wenku.baidu.com/view/49b110c7bb4cf7ec4afed083.html

7.安装Mysql-Python

Mysql-Python是Python连接Mysql的接口,在http://www.lfd.uci.edu/~gohlke/pythonlibs/下载相应的安装文件安装完毕,打开cmd,输入python,然后输入import _mysql和import MySQLdb,若没有提示错误,则表示安装成功。

[转载]5张表格教会你优化B2C盈利 – i天下网商-最具深度的电商知识媒体

mikel阅读(863)

[转载]5张表格教会你优化B2C盈利 – i天下网商-最具深度的电商知识媒体.

文/张陈勇

 

摸清商品结构

小丁他们得到一笔投资,创建一个区域综合B2C。这个B2C主营超市商品,但到底要经营哪些品类,各品类下需要哪些商品,各品类商品所占比例,如何跟踪商品招商情况,小丁毫无头绪,问我怎么办。

“你需要做一张商品维度表。”我说。

这是一份商品分类分维度的表格,比如花生属于坚果这个品类,花生有味道、外形、规格、价格等多个维度。它能帮助我们跟踪商品招商情况,优化商品结构,甚至增加收益。

那么如何建立“商品维度表”?

第一步是罗列出准备经营的商品品类,以及每个小类下的重要维度(如表1)。准备此表格时,可以参考各大网站的分类与导航字段。

第二步是把招商到的商品填入商品维度表中(见表2)。

第三步,当我们填入足够多商品时,就可以使用“数据透视表”功能或SQL语句提取报表,了解商品引入情况(见表3)。

“我明白了。”小丁说,“通过这些表格,我就能知道各品类下有多少商品,每个品类各维度商品多少。如果某个品类和维度下商品过多,则限制引进新品;如果过少,则要重点引进。”

“是的。”我回答,“我们还可以通过此表格控制SKU总数,根据总库存资金分配每个品类下的SKU数量,对每个品类设定SKU范围指标。小品类的每 一个维度代表了一种需求,单个商品有多个维度,引进一些多维度商品,就能用较少的SKU,满足更多元的需求,这样就能在不影响用户体验的情况下降低库存资 金。”

小丁说:“这个表格是挺好的,不过工作量也很大,投入这样多人力时间是否值得?”

我说:“商品维度表还有其他用处,它伴随整个项目经营过程,在优化商品结构、提高盈利上也有大用,到时候你就知道了。”

 

维度表里挖效益

几个月后,网站上线正常运营,小丁发现,一方面顾客反映商品不够丰富,找不到所需商品,另一方面不少商品出现滞销,库存占用不少资金,于是来询问我商品维度表是否能解决这个问题。

“当然可以,你需要在报表中加入SKU占比和销售占比字段,如表4。”

“在表4中,花生SKU占比0.13%,销量占比0.21%,销量占比大于SKU占比。如果同类商品(比如瓜子)的SKU和销量占比相差没有这么大,则说明消费者欢迎花生,花生的品类太少了,应该增加。”

“从商品维度上看,0—100g规格的花生SKU占比达到80%,但销量占比才46%,说明0—100g的规格的花生太多了,应该减少,相应增加其他规格的花生单品。”

“这太好了,长此以往,商品结构会越来越优化,降低滞销库存,增加周转。”

“不仅如此,商品维度表还能帮助你提升收益。你看表5。”

小丁说:“这个表和上一个表差不多啊,只是把销量占比改成了贡献占比。”

我回答道:“是的,上一个表的目的,是优化商品结构,从而符合消费者需求,所以从商品销量维度比较。而这一个表的目的是为了提升收益,所以要从贡献度考虑。”

“贡献占比是什么,怎么算出的?”

“贡献度占比=(某段时间毛利-固定成本)/整体毛利。”我在纸上写了下来,“不同商品毛利率、周转率不同。B2C固定成本(配送包装成本)高于线 下卖场。因为线下卖场的主要成本(房租、人力、水电)随销量增加分摊降低,而B2C即使销量增加,固定成本分摊降低空间也很小。贡献率考虑了以上情况。”

小丁说:“明白了,根据贡献率占比和SKU占比数据分析,增加高贡献率商品,减少低贡献率商品,这样整体收益就会增加。”

我回答:“是的,但分析数据时,还要考虑其他情况,比如某些敏感商品,虽然毛利率很低,贡献率不高,但如果不经营,用户就会流失,因此是不能停售的。”

“一般而言,A类敏感商品(吸引商品)和维度结构商品是不能缺少的。维度结构商品的受众小,但如果欠缺,部分用户就会认为商品不够丰富。毕竟商品结构不管如何优化,2/8原则总是有效的,并不是所有销量少的商品都可以精简。”

我继续说道:“还需考虑季节因素。有些商品贡献度突然下滑,可能只是季节问题,并不代表此商品永远不受欢迎。商品维度表为我们提供数据基础,分析时要结合实际经验和行业特点。”

“商品维度表”是商品结构优化的基础表格,特别适合品类多样、SKU丰富的零售业态,线上线下都可使用。线下零售更多使用ABC分析法,一般只分析 品类,不分析品类维度。线上业态比线下有更海量商品,更全的数据基础(维度数据),更智能的分析工具,所以总体而言,商品维度表对线上业态有更大作用。

(作者微博:@张陈勇)

[转载]Jquery 操作Cookie - 飞舞的蒲公英 - 博客园

mikel阅读(1363)

[转载]Jquery 操作Cookie – 飞舞的蒲公英 – 博客园.

关于cookie的path设置需要注意,如果不设置path:’/’的话,path则会根据目录自动设置[如:http://www.xxx.com/user/,path会被设置为 ‘/user’]

$.extend({
 
/**
 1. 设置cookie的值,把name变量的值设为value  
example $.cookie(’name’, ‘value’);
 2.新建一个cookie 包括有效期 路径 域名等
example $.cookie(’name’, ‘value’, {expires: 7, path: ‘/’, domain: ‘jquery.com’, secure: true});
3.新建cookie
example $.cookie(’name’, ‘value’);
4.删除一个cookie
example $.cookie(’name’, null);
5.取一个cookie(name)值给myvar
var account= $.cookie('name');
**/
    cookieHelper: function(name, value, options) {
        if (typeof value != 'undefined') { // name and value given, set cookie
            options = options || {};
            if (value === null) {
                value = '';
                options.expires = -1;
            }
            var expires = '';
            if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
                var date;
                if (typeof options.expires == 'number') {
                    date = new Date();
                    date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
                } else {
                    date = options.expires;
                }
                expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
            }
            var path = options.path ? '; path=' + options.path : '';
            var domain = options.domain ? '; domain=' + options.domain : '';
            var secure = options.secure ? '; secure' : '';
            document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
        } else { // only name given, get cookie
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
    }
 
}); 

[原创]谷歌浏览器Chrome下jQuery的position().left取不到值问题

mikel阅读(1179)

最近要做一个鼠标滑过显示弹出层,鼠标离开后隐藏的功能,在ie和firefox下用JQuery的position().left层的定位没有问题,但是在Chrome下的position().left无效,只能用offset().left获取坐标位置显示层,代码如下:


        $(function() {
            $('#topshop').mouseover(function() {
                var x = $(this).position();
                var markDiv = $("#babyNew_sortBody");
                if (x.left == 0) {//chrome下left=0
                    markDiv.css("left", $(this).offset().left);
                } else {
                    markDiv.css("left", $(this).position().left);
                }
                markDiv.css("top", $(this).position().top + 40);
                markDiv.css('display', 'block');
            });
            $('#babyNew_sortBody').mouseleave(function() {
                $("#babyNew_sortBody").attr('style', 'display:none;');
            });
        });

[转载]jQuery 事件 - mouseleave() 方法

mikel阅读(1009)

[转载]jQuery 事件 – mouseleave() 方法.

实例

当鼠标指针离开元素时,改变元素的背景色:

$("p").mouseleave(function(){
  $("p").css("background-color","#E9E9E4");
});

亲自试一试

定义和用法

当鼠标指针离开元素时,会发生 mouseleave 事件。

该事件大多数时候会与 mouseenter 事件一起使用。

mouseleave() 方法触发 mouseleave 事件,或规定当发生 mouseleave 事件时运行的函数。

注释:与 mouSEOut 事件不同,只有在鼠标指针离开被选元素时,才会触发 mouseleave 事件。如果鼠标指针离开任何子元素,同样会触发 mouSEOut 事件。请看下面例子的演示。

亲自试一试:mouseleave 与 mouseout 的不同

触发 mouseleave 事件

语法

$(selector).mouseleave()

亲自试一试

将函数绑定到 mouseleave 事件

语法

$(selector).mouseleave(function)
参数 描述
function 可选。规定当发生 mouseleave 事件时运行的函数。

亲自试一试

[原创]IE6下wbox弹出iframe窗口加载页面空白问题解决

mikel阅读(1016)

最近项目测试中发现在用wbox弹出iframe窗口中,ie6下页面加载失败导致空白页面,可是查看页面源码发现页面只是加载了一部分,没有加载完成就停止了,去网上搜了下关于iframe的ie6下的兼容性问题,[转载]ie6下的iframe,问题多多。 – izumi – 博客园中介绍了有8种之多,哦买噶的!ie6你让我情何以堪!于是一一测试,终于在ie6弹出层加载完成空白后,再右键-刷新页面,页面出现了!于是对照[转载]ie6下的iframe,问题多多。 – izumi – 博客园中的第8条,需要加载两次iframe的src,于是对wbox进行了修改了,加入了getframe方法,然后调用页面showbox()后根据浏览器版本调用getframe进行重复加载

wbox.js代码如下:

        this.getFrame = function() {
            return $(this).find('iframe[name=wBoxIframe]');
        }

调用页面代码:

        wbox.showBox();
        var ifr = wbox.getFrame();//获取wbox中的iframe

        if (getbrowser()) {
            ifr.load();//调用加载事件,重绘窗口的标题样式
            document.frames['wBoxIframe'].location.reload();//iframe对象重新加载url
        }

[转载]iframe的onload事件 - 与时俱进 - 博客园

mikel阅读(1280)

[转载]iframe的onload事件 – 与时俱进 – 博客园.

很 多时候,我们会需要改变一个iframe的地址(src属性),或者使用表单(form)的target在指定的iframe进行提交后,在 iframe加载完毕(onload)时立即响应某个操作,以提高WEB应用程序的价值。本文讨论了跨浏览器的iframe onload事件的监听方法。

如果你没时间去阅读全文,可以看解决方案的内容概要:

  1. 同域的页面嵌套,最好的是让内嵌的页面调用父页面的函数,如 window.parent.callparentFunctoin()。
  2. 如 果是异域,或者子页面已存在且无法修改,那么:在Firefox/Opera/Safari中,可以直接使用iframe onload事件;而在IE中,可以通过定时器测定子页面的document.readyState,或者使用iframe onreadystatechange事件计算该事件的响应次数。

以上内容基于参考文档: Q239638 和 Q188763.

如果你对这个话题很感兴趣,请一定要继续阅读哦。。。

注[1]:为 了使问题更集中,本文所述的<iframe>均直接写在父页面中,对使用 document.createElement(“iframe”)或者其它方式建立的iframe不作讨论,因为这样会使问题在IE下变得更加复杂,但 只要使用本文的结论,无论何方式下建立的iframe,问题仍然会得到解决。

一个简单的包含iframe的父页面将是如下样子的:

<!DOCTYPE ...> <html xmlns="...">   <head>   <meta ... />   <title>Iframe</title>   <body>     <iframe name="iframe1"  id="iframe1" width="300" height="50" src="#" ></iframe>     <script type="text/javascript">//codes here</script>   </body> </html>

开始:

让我们从一种简单的情形和解决方法开始:

1.WINDOW.PARENT 对象

1.1 调用父页面对象

<!–This is an inner page in the iframe–>
<script type=”text/JavaScript”>
window.onload=function{ window.parent.iframeCall();}
</script>

在网上找到的方法中,最令人开心的一个,莫过于在能子页面中调用父页面的对象了:

window.parent.callFunciton()。

不过我想:可能这点全地球人都已经知道了。只是这个方法有一个缺点,那就是子父页面必须在同域中。

还有一点,就是前端工程师们需对子页面有修改权;或者,可以请负责此子页面的同事为我们添加一段代码:

<script type=”text/JavaScript”>
if(window.parent!=window) window.parent.iframeCall();
</script>

把它放到window.onlad中,或者直接放在</body>之前。

注[2]:在对iframe或其它窗口性质的前端编程中,同域名是最完美的先天条件。只要在同一域名中,各个窗口间的对象是共享的,我们完全可以自由发挥,在不同的窗口间来回驾驭。总之,只有想不到,没有做不到。

1.2 异域

在不同域名的页面,浏览器出于安全考虑,几乎完全封锁了页面间的对象来往,这里没有鹊桥,牛郎和织女只能远远想望。当然,用iframe嵌套页面还是可以的,毕竟还可以思念。

面对家族的封锁,罗密欧还是很想见朱丽叶,他在夜里架起梯子抓到朱丽叶的窗前与她见面;在异域的页面嵌套中,子页面总是可以直接改变父窗口的location以防止被嵌套,但父页面对这个一点办法也没有。

当然,子页面除了仅仅永恒地拥有父窗口.location的修改权外,也没有其它了。例如,在IE下,子页面只能直接修改父页面的.location为另一个源:

<script tyle=”text/javascript”>parent.location=”http://anotherPage.com/”;</script>

但无法访问其它对象,如window.name,document等,连location.href等location的子属性就无法访问。当然,在防止嵌套方面,使用top.location会更强大。

但Firefox中,似乎还可以为top.location添加一些东西,但这是在我不严谨的测试中出现过的情况,未经找到相应的权威文档哦。

2. IFRAME ONLOAD 事件

在Firefox/Opera/Safari中,直接使用frame元素的onload事件即可:
document.getElementById(“iframe1”).onload=function(){
//your codes here.
};
只可惜它在IE下经常无效,因为在IE下它最多只能被激活一次,而且无论你有多少个iframe,被激活的也只能是最后一个的。更详细的描述请看:Q239638 和 Q188763

原因
这些事件是在IFRAME内的文档对象模型中激活的,而不是父页面的。在IFRAME加载完毕的时候,这个事件就被激活了,而且ReadyState已经是“完成”状态。所以你无法通过这个事件来查检一个IFRAME是否加载完毕。

为了得到更好的表现,我们再稍稍研究一个问题:IFRAME递归。

3.IFRAME 递归

在处理IFRAME时,浏览器应该有一个基本规则,那就是防止递归,防止页面无限的自我加载,使客户端设备崩溃。事实上,文中出现的几个浏览器均做到这点,只是不同的浏览器有不同的处理方式。请分别尝试以下代码:
<iframe src=”” onload=”finish()” name=”iframe1”></iframe>
<iframe src=”#hashonly” onload=”finish()” name=”iframe2”></iframe>
<iframe src=”?search” onload=”finish()” name=”iframe3”></iframe>
<iframe src=”http://anotherPage.com” onload=”finish()” name=”iframe4”></iframe>
执行的结果是,在父页面加载时,上面的iframe onload函数在IE/Opera/Safari中均会被激活,Firefox对第二个没有反应。这主要因为他们在防止递归方面的处理是不同的。
对于#hashonly和?search这样的URL,浏览器会解释为页面本身。但hash和search的不同之处是,改变 search可以组成新的源,而改变hash不会。通常地,浏览器一遇到同源的iframe内页即会停止加载,但Safari却会加载多一次。
假如把finish()函数写成如下:
var finsh=function(){alert(”onload from :”+this.src);}
运行时分别弹出的消息弹出框的次数如下:

ifm/brw:    IE    |    Firefox    |    Opera    |    Safari iframe1:    1     |       1       |      1      |      0 iframe2:    1     |       0       |      1      |      1 iframe3:    2     |       1       |      2      |      2 iframe4:    1     |       1       |      1      |      1

再结合页面所呈现的内容,可得看出这些浏览器在处理递归问题上的一些细则:

  • Firefox 不会在iframe中加载任何东西和激活onload事件(可能是任何事件)
  • IE和Opera不会在iframe中加载页面,但会激活onload事件。
  • Safari(windows版本)会在iframe中加载页面一次且仅仅一次,并会激活onlaod事件且仅激活依附在父页面上那个iframe的onload事件。

关 于本节,如果仅把iframe用于页面嵌套,那意义不大;如果用于动态加载/呈现内页,或者用于良好用户体验的form target表单提交处理(不是Ajax),并且要求较高的浏览器兼容性时,作用才会显示出来。根据本节结果,为了提高兼容性,最好事先把iframe指 向一个空页面——blank.html,因为它在4种浏览器中的表现是一样的。如果不想事先加载页面,那就得花多点心思去判断浏览器类型了。

4.代码实现

4.1Firefox/Opera/Safari,直接使用iframe onload事件

document.getElementById(“iframe1”).onload=function(){     //your codes here. };

4.2在IE下,定时器测document.readyState或者注册iframeonreadystatechange事件

4.2.1定时器以及document.readyState

var fm1=window.frames["iframe1"]; var fmState=function(){   var state=null;   if(document.readyState){     try{       state=fm1.document.readyState;     }catch(e){state=null;}     if(state=="complete" || !state){//loading,interactive,complete       //onComplete();       return;     }     window.setTimeout(fmState,10);   } }; //在改变src或者通过form target提交表单时,执行语句: if(fmState.TimeoutInt) window.clearTimeout(fmState.timeoutInt); fmState.timeoutInt = window.setTimeout(fmState,400);

为 什么要延时400毫秒?因为javascript对DOM的操作是异步的,我们必须等待脚本对DOM落实执行后才开始下一步。400秒这个数取决与客户端 的设备和浏览器的响应速度,好的设备的响应速度能在10毫秒以内甚至更快,但100毫秒左右可能比较大众化,400毫秒应该是十分保守的了。总之,较大的 毫秒数能适合更多的用户设备状况,并能减少了客户端设备的工作量。

至于document.readyState,指的是iframe内子页的docuent.readyState,而不是父页面的。只要允许,即在同域情况下,document.readyState会返回5个状态:

uninitialized 对象未初始化.
loading 对象正在加载数据.
loaded 对象已加载完数据.
interactive 在这个状态下,用户可以参与互动,即使在对象未加载完毕也可以
complete 对象已完成初始化.

为什么使用try和 catch?因为在异域的情况下,当iframe的子页到达interactive状态时,父页面就会失去访问权,所以最多只能返回到loaded这一步,因此IE出一个未知错误——其实就是没有权限,所以try和catch,让这个错误沉默下去。

幸好这个方法只针对IE(目前我能使用到的版本:IE6/7),否则麻烦大了:Opera不等页面加载完就开始交互了,而IE会等页面加载完毕才进行交互,所以感觉用Opera打开网页的速度相对比IE快。

4.2.2.onreadystatechange 事件三步曲

var stateID={}; var fmStChange=function(){   if(ifFirstLoad) return;   stateID[this.id]=stateID[this.id] ? stateID[this.id]+1:1;   switch (stateID[this.id]){     case 1:       //state loading       //onComplete(STEP1);       break;     case 2:       //state interactive       //onComplete(STEP2);       break;     case 3:       //state complete       //onComplete(LASTSTEP);       break;   }   if(stateID[this.id]&gt;=3) stateID[this.id]=null; }; $("iframe1").onreadystatechange=fmStChange; //if you want to ignore the parent page load //add the following two line var ifFirstLoad=true; $("iframe1").onload=function(){ifFirstLoad=false;}

每当iframe加载页面,过程内会激活onreadystatechange事件三次,相应的状态分别是loading,interactive和complete,而最后一次才是complete,所以我们得计算一下,直到第三次才算是完成。

注意:这 个方案中的stateID在状态判断时非常重要,要进行必要的修正和保护,如在每次应用iframe 时,把stateID[iframe_id]复位为null,或者在第三次响应完成之前,不要对iframe进行新轮页面加载,或者在新一轮的页面加载前 消除之前的事件并复位。