mercredi 28 mars 2012

学习之模块架构 DotNetNuke 6

前面的博客介绍了:

博客园原文地址 :  学习之模块架构 DotNetNuke 6

这篇博客主要是讲模块的架构和加载,以及模块与DotNetNuke门户网站(Portals)系统的关系。充分了解模块可以帮助DNN开发者根据需要更清晰的构建模块。
在DNN中,模块是一个可插入的用户接口组件,用来处理请求并生成动态的内容。它只能出现在ASP.NET页面上,而页面可以包括任意数量的模块"实例"。
整个模块架构包括四个部分 : 门户网站(Portal),页面(Tab),模块(Module)和模块容器(Container)。

  • 门户网站(Portal)
Portal可以定义为一个基于Web的应用程序,从不同的源聚集内容,并寄宿信息系统的表示层(模块)。下图描述了Portal的基本架构,DNN处理页面请求时需要执行许多步骤。下述步骤在页面初始化的过程中执行,用来在运行时动态地加载模块。动态创建的模块然后就能够处理它们自己的生存周期,包括诸如初始化、加载、呈现等各种事件。

图一 : Portal的基本架构

第一步: 页面配置检索(Page Configuration Retrieval)

第1步就是为被请求的页面检索模块。检索步骤由许多重要的信息块构成,例如页面上出现的各个模块、模块在页面上显示的区域(即内容窗格Pane),以及与每个模块相关联的安全角色。
//Default.aspx.cs//OnInit//load skin control and register UI js
UI.Skins.Skin ctlSkin = UI.Skins.Skin.GetSkin(this);
//add skin to page
SkinPlaceHolder.Controls.Add(ctlSkin);

//DotNetNuke.UI.Skins.Skin.cs : OnInit()
bool success;
//Load the Module Control(s)
success = Globals.IsAdminControl() ? ProcessSlaveModule() : ProcessMasterModules();

//DotNetNuke.UI.Skins.Skin.cs : ProcessMasterModules()
bool success = true;
if (TabPermissionController.CanViewPage())
{
  //check portal expiry date
  if (!CheckExpired())
  {
    if ((PortalSettings.ActiveTab.StartDate < DateAndTime.Now && PortalSettings.ActiveTab.EndDate > DateAndTime.Now) || TabPermissionController.CanAdminPage() || Globals.IsLayoutMode())
    {
      //dynamically populate the panes with modules
      if (PortalSettings.ActiveTab.Modules.Count > 0)
      {
        foreach (ModuleInfo objModule in PortalSettings.ActiveTab.Modules)
        {
          success = ProcessModule(objModule);
        }
      }

第二步: 安全审计(Security Audit)

第2步就是判断在上一步中检索出来的安全信息。通过检查当前用户的角色(是注册用户还是匿名用户)以及与每个模块相关联的查看角色,就可以为当前页面形成一列经过“授权”的模块。
private Boolean ProcessModule(ModuleInfo module)
{
  bool success = true;
  if (ModulePermissionController.CanViewModule(module) && module.IsDeleted == false &&
((module.StartDate < DateTime.Now && module.EndDate > DateTime.Now) || Globals.IsLayoutMode() || Globals.IsEditMode()))
  {
  //...
  }
  //...
}

第三步:内容注入(Content Injection)

第3步(也是最后一步)就是将“授权”模块动态地插入到页面上相应的内容窗格中。在所有的模块加载之后,每个模块就能够执行各自的事件并呈现内容。
Pane pane = GetPane(module);
if (pane != null)
{
  success = InjectModule(pane, module);
}

  • 页面(Tab)
图二描述了基本的Portal的Tab组件。页面本身表示一个完整的标记文档,由大量的内容窗格(Pane)组成,并且在每个内容窗格中还包含大量的模块。

图二:页面组件

每个模块都包含一个标题、若干装饰(Container)以及由模块生成的内容。装饰可以包括若干按钮、链接以及一个改变模块状态或者执行与模块相关功能的悬浮菜单。

  • 模块(Module)
正如前面所述,Portal是基于Web的应用程序,处理各种请求并生成动态内容。每个模块都生成自己的标记块(称为段),再和皮肤的标记一起展示完整的文档。
因为每个模块都生成自己的标记,所以可以将模块视为较大应用程序中的微型应用程序。通常,用户通过单击链接或者提交表单(所提交的表单由门户网站系统及传递给相应模块的命令处理)与每个模块生成的内容交互。

  • 模块容器(Container)
模块周围的装饰称为模块容器。通过容器,用户能够与模块交互,执行诸如最小化、最大化以及其他高级特性(如果用户拥有该页面的编辑特权)的动作。
图三示范了一个HTML模块在用户以编辑特权登录时的模块容器。这个模块容器包含许多项,例如拥有一列管理选项的悬浮菜单、模块的标题。

图三:模块容器

DotNetNuke est le plus gros projet open-source en technologie .Net.

lundi 26 mars 2012

分享之数据库实体关系图 DotNetNuke 5.6.1

下图所示是DotNetNuke 5.6.1社区版的ERD(Entity-Relationship Diagram). 找了好久只找到这个版本的,估计不是官方的,是一个叫R2i的公司在维护的。但我觉得这个已经足够了,因为5.6.x是DNN 6之前的最后一个版本,所以我觉得DNN 6和它之间内核库不会有Break changes,当然少许的改动或优化总是有的。
为什么要分享这个图呢? 因为我觉得ERD对我们理解全部DNN的架构非常重要,并且能够帮助我们减少开发第三方模块的时间。
在下图中,表框的不同颜色表示了他们类别的不同 :
  • 蓝色 : 认证系统,比如用户认证,页面模块查看权限...
  • 红色 : 内容管理,比如皮肤,页面...
  • 绿色 : 辅助系统,比如异常记录,任务...
  • 黑色 : 配置系统,比如模块定义,语言包...
  • 灰色 : 第三方核心插件,比如Text/HTML模块,搜索模块...




这个图是有点小了,估计大家看不清楚。所以提供PDF下载外加MetaData下载 : ERD PDF || METADATA XLS
希望想学习或想了解DNN的园友看完之后,对DNN的Architecture有更全面的了解。5 jours avant 01 Avril !

vendredi 23 mars 2012

如何创建新模块 DotNetNuke 6 & Entity Framework Code First

Soleil 索引 :
第一部分:开发新模块 - DNN6

Étoile 如果你还不知道DotNetNuke是什么的话,请访问 www.dotnetnuke.com
Étoile 如果你还不知道如何在本地安装DNN 6, 请猛戳 http://codeciel.blogspot.fr/2012/03/how-to-install-dotnetnuke-6-on-local.html
Arc-en-ciel 如果你想要知道如何开发一个你自己的DNN6模块,那么这篇文章就是你需要的。


  • 步骤1:通过DNN6 Host创建desktop module和module definition
从数据库的角度出发,这一步会把新模块的相关信息存入数据库,让DNN可以识别,这样你就可以把这个模块加入任意页面。如果你仔细看了DNN数据库的结构后,你会发现有很多和模块(Module)相关的表 - dbo.DesktopModules, dbo.Modules, dbo.ModuleDefinitions, dbo.TabModules, dbo.PortalDesktopModules. 这儿不会细讲这些表的用途,如果可以的话,有机会我会专门为此写一篇博客。
所以,现在你只要按照下面的步骤就可以创建一个属于你的DNN模块 :
  - 用host账户登入你的DNN6网站
  - 点击Host页面,再进入Extensions页面
  - 单击Manage按钮, 选择Create New Module,你将会看到(如Figure 1所示):
提示: 如果你找不到Manage按钮,请确认你的页面模式(通常在右上角可以看见)是Edit而不是View或Layout。
1
Figure 1 : 创建模块
  - 填好这些文本框后。(最后把"Add Test Page ?"打上勾,以简化步骤)
  - 单击“Create Module”, 然后你就可以看见新的模块已经出现在了“TestEFCodeFirstPage”页面上(如Figure 2 所示)了
2
Figure 2 : 新页面里包含了新模块

  • 步骤2:把新模块与VS项目联系起来
  - 现在打开VS2010,创建新项目,如Figure 3 所示。
提示:值得注意的事,项目的名字必须与module的名字相同,即“EFCodeFirst”,开始的时候你可以把这个项目保存到任何位置,因为一旦完成创建之后,我们会把这个文件夹移动到<网站根目录>/DesktopModules里,合并这俩个文件夹。
3
Figure 3 : 创建新vs2010项目
  - 再次用VS2010打开“EFCodeFirst.csproj”. 因为我们还需要配置这个项目,来让它可以顺利的在DNN6下编译和运行。
  - 点击项目属性,然后进入到Compiler页面,修改输出路径为<网站根目录>\bin\
  - 如果你Site的运行环境是.net framework version 2.0.50727.5448的话,请在IIS里修改Site的application pool为ASP.NET V4.0。因为EF Code First是需要.net 4.0的。
  - 添加Dotnetnuke.dll引用,它可以在<网站根目录>\bin\下找到。需要注意的是在属性里将copy local设置为false。
提示:上面这种添加Dotnetnuke.dll引用的方法不是企业开发常用的,或者说是应该避免的才比较正确。因为Dotnetnuke不断在更新,为了保证团队开发时,Dotnetnuke.dll引用都是同一个版本,我们通常会固定一个稳定的版本来开发。具体操作是:存放指定版本Dotnetnuke.dll的文件夹是共享的,所有的dnn引用都是指向这个文件夹的。
  - 重命名web.config文件为web.config.old,因为在网站的根目录已经有了一个web.config。
  - 删除EFView.ascx文件
  - 添加一个新文件,文件类型是Web User Control,还是命名为“EFView.ascx ”,以便DNN能识别。
  - 打开文件EFView.ascx, 我们随便写点东西进去,比如 : “This is my first dnn6 module”
  - 打开文件EFView.ascx.cs,将它的基类换成PortalModuleBase,保存并编译这个项目
  - 刷新页面http://dnn614/TestEFCodeFirstPage.aspx,你将会看到如Figure 4所示 :
4
Figure 4 : 测试页面和行模块

好了,看到这里你就应该知道如何创建一个DNN6模块了。在这个模块里,你可以根据需求,随意开发。下面的第二部分就是,在一个DNN模块里使用Entity Framework Code First进行实战开发。




第二部分 : DNN模块里使用EF Code First

Pouce levé 这部分是基于这篇文章: Introduction to Entity Framework Code First


  • 步骤 3* : Entity Framework 简介
在我直接进入正题之前,我想先介绍一下EF。EF是一个.NET平台下的ORM框架,个人觉得做的很不错,之前还接触过另外俩款在.NET平台下的ORM - LLBLGen Pro和NHibernate。LLBLGen Pro自从收费之后,功能也越来越强大,用起来也挺顺手的,之所以没有继续用的原因很简单:我现在这个客户公司,不想花钱买它的licence。NHibernate是从Java版的Hibernate移植过来的,就好比Lucene.NET与Lucene的关系一样,不同的是Lucene.NET早早就进Apache的孵化器了,而NHibernate的生命力还很强大。我没有用NHibernate的原因也很简单,被它的配置文件惊吓住了。比较这三款的优缺点不是这里的重点,每个人的习惯和思考方式不一样,所以喜好自然不同,选一款自己用的顺手又顺心的ORM就可以了。下面开始介绍EF的三种使用方法 :
EF在4.0的时候只提供俩种与实体交互的方法,即数据库优先模型优先。前一种情况下,你在开发你的应用前开始设计数据库。然后你可以用VS自带的实体数据模型设计工具来设计一个虚拟模型,操作很简单:直接从数据库把表拖拽到设计器中(如Figure 5所示)。后一种情况下,我们先用实体数据模型设计工具来手工设计模型(如Figure 6所示),然后指定数据库的连接。但不管是前面哪种情况,你都要使用实体数据模型设计器来生成你的数据模型对象。

2-1
Figure 5 : 数据库优先

2-2
Figure 6 : 模型优先

EF在4.1中引入一种新的模式来生成模型对象 : 代码优先(Code First)。在代码优先这种方式里,你不会遇到任何设计器。先全部用.NET Framework来搭建对象类,然后用一些特定属性和相关技术来生成EF数据模型。(如Figure 7一样)

2-3
Figure 7 : 代码优先

上面大致讲了一下这三种方法,如果你感觉有点混淆,静下心来,仔细看Figure 8,我相信你肯定会清楚不少。在我们这个模块中,我们使用的是最后一种。


2-4
Figure 8 : EF与实体交互的方式

第二部分的目的不仅仅是完成我们的模块,而是一步一步的,让大家弄清楚使用EF Code First的全部过程。接下来,在开发模块,你将处理一个用来表示博客帖子的数据模型,实际上,数据是驻留在SQL Server里一个名叫BlogPosts表中的。通过使用模型对象,你能够从表中读写数据。


  • 步骤 3 :  创建模型
假设我们的数据模型是用来储存博客帖子和博客贴分类的。根据三层架构的思想,我们应该另外创建一个project来专门开发数据模型 :在与“EFCodeFirst”项目同一个solution里创建Library类型的新项目,命名为“EFCodeFirstLib”。这个类库项目里将会包括俩个模型对象,即BlogPost和Category。他们的模型代码如下展示 :
提示: EFCodeFirstLib项目的文件夹应该放在<网站根文件夹>/DesktopModules/, 并且其编译路径应该是<网站根文件夹>/bin/.
public class BlogPost
{
  public Guid Id { get; set; }
  public string Title { get; set; }
  public string Content { get; set; }
  public DateTime PublishDate { get; set; }
  public virtual Category Category { get; set; }
}
  
public class Category
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<BlogPost> BlogPosts { get; set; }
}

在BlogPost类中,定义了五个属性: Id, Title, Content, PublishDate 和 Category。注意里面的Category是外键。Category类有三个属性:Id, Name 和 BlogPosts。其中的BlogPosts 是一个属性集合,因为可以有很多个博客帖子属于同一个category。需要记住的是,默认情况下,表示主键的属性类型应该是int或Guid。当然,你可以用一些attributes定制主键。我们将在后面讨论。


  • 步骤4 : 创建Data Context
现在模型对象都已经创建好了,让我们开始创建一个Data Context,通过它可以让你查询和处理实体数据,另外,它的基类是DbContext类。下面就是我们在模块中要使用的Data Context:
public partial class BlogContext : DbContext
{
  public BlogContext():base("BlogDb")
  {
  }

  public DbSet<BlogPost> BlogPosts { get; set; }
  public DbSet<Category> Categories { get; set; }
}
BlogContext类继承了DbContext类。在它的构造函数中,调用了基类的构造器并且传递了所需的数据库名称。当你首次运行应用时,将会为你用这个名字创建数据库。如果不传递这个名称,默认创建数据库的名字将会是DbContext类的fully qualified name。在我们这个例子中就是“EFCodeFirstLib.BlogContext”。
BlogContext类定义了俩个公共属性,即BlogPosts和Categories。这些属性的类型是DbSet。DbSet类代表了一个实体集(从数据库角度,就是一个数据库的表),可以执行CRUD(创建,读取,更新,删除)操作


  • 步骤5 : 测试数据库的生成(可选)
我们现在可以测试我们已经写的代码了,当然你也可以选择跳过这一步。
首先在EFCodeFirst项目的“EFView.ascx”中添加一个按钮(button),并且生成相应的按钮点击事件方法。加入我们刚刚创建的EFCodeFirstLib项目的引用。



Figure 9 : 测试页面


然后在按钮点击事件方法中写入以下代码:
using (var db = new BlogContext())
{
  Guid id = Guid.NewGuid();
  var cat = new Category { Id = id, Name = "ASP.NET" };
  var post = new BlogPost { Title="Title1", Content="Hello World!", PublishDate=new DateTime(2011,1,1), Category=cat};
  db.Categories.Add(cat);
  db.BlogPosts.Add(post);
  int i = db.SaveChanges();
}
上面的代码创建了一个BlogContext实例,接着创建了Category和BlogPost类的各自实例。把新创建的实体实例加入到DbSets里面,最后调用SaveChanges()方法。 SaveChanges()方法将持久化加入的实体数据,也就是把实体数据写入数据库相应的表中,并且返回此次操作执行的记录数。
现在我们编译这俩个项目,在浏览器中打开http://dnn614/TestEFCodeFirstPage.aspx. 点击页面中的按钮。 因为我们是第一次运行并点击按钮,EF将会在SQL Express里创建新的数据库和表。库名是BlogDb,因为我们在DataContext的构造里已经指出了;俩个表名分别是BlogPosts和Categories。


Sans titre1
Figure 11: SQLExpress里创建的数据库和表

值得注意的是BlogPosts和Categories表里的Id列被设定为主键, 同样BlogPosts表中,有一名叫Category_Id的外键被定义。

  • 步骤6 : 每次运行(点击按钮)时重新创建数据库
在测试时,你也许想要在每次运行应用时都创建或重新创建数据库,以便初始化运行环境。同时也想在创建数据库的时候加入一些测试数据。当你修改了你的实体代码时,因为数据库的表也会相应的改变, 数据库也应该重新创建。默认情况下,EF只会在你首次运行时创建数据库,之后应用会一直操作这同一个数据库。这当然不是我们想要的,因为我们的实体代码会随着需求的变更而修改或增加,为了改变这种默认行为,你需要在代码里创建一个database initializer,并且继承DropCreateDatabaseAlways类。如名字暗示的那样,DropCreateDatabaseAlways类总是会重新创建数据库。下面的代码就是我们自己的BlogContextInitializer :
提示:你也可以继承DropCreateDatabaseIfModelChanges类,它只会在Model改变的时候,重新创建数据库。
public class BlogContextInitializer : DropCreateDatabaseAlways<BlogContext>
{
  protected override void Seed(BlogContext context)
  {
    Category cat1 = new Category { Id=Guid.NewGuid(), Name=".NET Framework" };
    Category cat2 = new Category { Id = Guid.NewGuid(), Name = "SQL Server" };
    Category cat3 = new Category { Id = Guid.NewGuid(), Name = "jQuery" };
    context.Categories.Add(cat1);
    context.Categories.Add(cat2);
    context.Categories.Add(cat3);
    context.SaveChanges();
  }
}
BlogContextInitializer 继承了DropCreateDatabaseAlways 基类,并且重写了Seed()方法,方法里写入了一些往数据库里添加样本数据的代码:添加了三个categories。一旦完成了initializer,你需要添加以下代码到按钮点击事件方法里去:
protected void Button1_Click(object sender, EventArgs e)
{
  Database.SetInitializer<BlogContext>(new BlogContextInitializer());
   ...
   ...
}
现在你就会发现每次点击按钮时,数据库都会重新创建,并且填充样本数据到Categories表里。

  • 步骤7 : 在Code First里使用已有的数据库
上面的代码里,你允许EF自己创建数据。但在许多情况下,你会想要用已经存在的数据库而不是创建一个新的。又因为我们在DNN里使用EF Code First,所以在任何情况下都不可能全部重新创建DNN使用的数据库(DNN614)。我们不得不使用其它的数据库(比如DNN614_BlogDb)。如何让Code First知道我们想要使用那个数据库呢?只需要在web.config的Connection String里指明就可以了:
<connectionStrings>
  <add name="SiteSqlServer" connectionString="Data Source=(local)\LEGAL;Initial Catalog=DNN614;User ID=login614;Password=xxx" providerName="System.Data.SqlClient" />
  <add name="BlogDb" connectionString="Data Source=(local)\LEGAL;Initial Catalog=DNN614_BlogDb;User ID=lgfr;Password=xxx" providerName="System.Data.SqlClient"/>
</connectionStrings>

Sans titre
Figure 12 : 指明已有的数据库

需要注意的地方是,我们在<connectionStrings>里添加的数据库连接字符串的名字,必须和我们在DataContext构造器里指明的一样(“BlogDb”)。
如果你在DataContext没有指明,那么那个数据库连接字符串的名字就必须和DataContext类名一样(“BlogContext”)。
为了让大家更清楚Code First选择数据库连接字符串的流程,我们用这个例子再解释一遍 :
  •   情况一:在DataContext中(BlogContext)指明了名字“BlogDb”
      EF首先会在configuration文件里查找是否有名字为“BlogDb”的数据库连接字符串。
      如果有,EF就会使用这个。如果没有,EF就会在本地的SQL Express中创建一个名为“BlogDb”的新数据库。
  •   情况二:没有在DataContext中(BlogContext)指明
      EF首先也会在configuration文件里查找名为“BlogContext ”的数据库连接字符串。
      如果找到,EF就是使用;否则EF就会在SQL Express里创建一个名为“EFCodeFirstLib.BlogContext”的新数据库。其中EFCodeFirstLib是BlogContext的命名空间。

  • 步骤8 : 使用Data Annotations来标明数据表和键的信息
上面的例子中,当创建实体对象对应的数据库和表时,EF使用的是默认的约定。我们也可以用一些data annotations来定制EF的行为。例如下面代码所示,我们添加了一些data annotations属性来标明表名([Table]),主键([Key]) 和外键([ForeignKey])信息。
[Table("BlogPosts")]
public class BlogPost
{
  [Key]
  public Guid Id { get; set; }
  public string Title { get; set; }
  public string Content { get; set; }
  public DateTime PublishDate { get; set; }
  [ForeignKey("Category")]
  public Guid CategoryId { get; set; }
  public virtual Category Category { get; set; }
}

[Table("Categories")]
public class Category
{
  [Key]
  public Guid Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<BlogPost> BlogPosts { get; set; }
}

  • 总结 :
Entity Framework Code First允许我们直接在代码使用EF特性,比如未经任何实体数据模型设计。这种方式下,全部使用C#类来创建实体对象,需要定义一个继承了DbContext类的DataContext类,同时可以使用data annotation属性显式地标明相关信息。默认时,当应用第一次运行时,EF会在SQL Express里创建新的数据库;我们可以通过创建自己的数据库初始化策略(Database Initializer)来改变这种默认行为。也可以使用已经存在的数据库,只需在configuration文件里标明了数据库连接字符串。 
Code First相对与其他两种方式来说,有很大的灵活性。但我觉得在DNN中不太适合使用,因为我不是特别能接受一个DNN网站同时有俩个数据库,维护起立不方便。所以,在现实项目中,我经常使用的方式是Database First。
最后友情提供一下本例中的DNN模块安装包和源代码:安装包  源代码Profitez-le et je vous souhaite un très bon weekend !!

jeudi 22 mars 2012

分享几个Web开发必备小抄

摘选自: "20 Cheat Sheets for Web Development you must have".


点击可查看大图!


1) PHP
本人说不上讨厌PHP,却绝对的不喜欢,可能是上学的时候留下的阴影吧。最近正在用Wordpress建站,不得已得用PHP。



2) HTML Character Entities



3) CSS



4) Javascript



5) JQuery 1.3



6) Regular Expressions
不多说了,必须的必备。



7) Apache Mod Rewrite
Url重写,最近在WordPress里会用到它,既可以让url更易读,又可以提高SEO。



8) WordPress Mind Map
一个讲解了WordPress流程的思维导图,非常清晰。
      


9) SEO
做一个优秀的SEO必然要花一番功夫的,有的放矢能事半功倍。
     


小小总结:
以上九个小抄就是我摘录下来的,基本是现在都用的着的。不过有些东东可能正在过时,正在更新好像更准确一些。要是有人或自己能不断更新这些图就好了。Quelle Bonne Idée!



mercredi 21 mars 2012

Juice UI: 整合了jQuery UI的开源ASP.NET Web控件

前言 

这篇文章的原文来自Jon Galloway,想看原文的请猛戳链接。第一次接触这个Juice UI是看到同事分享的邮件,当时只是粗略看看,不过感觉把jQuery UI整合到ASP.NET Web控件里去确实是个不错的主意。今天偶然在网上看到了这篇文章,就动手把它翻译过来,和大家分享。以下是译文:

今天早上的MVP峰会上,Scott Hunter刚刚从appendTo网站新发布了一个开源项目,名字叫Juice UI。Juice UI是一个Web窗体控件的集合,并整合了jQuery UI。你可以通过添加JuiceUI NuGet package到你自己的应用中,立即就可以使用它。同时源码是提供下载的(go nuts with the source), 他的版权协议是基于MIT和GPL的。


Juice UI,能做什么?

jQuery UI 是一个构建在jQuery之上的UI库。它为平常的场景提供了非常多且强大的部件,例如日期选择期,对话框和选项卡等等;并且一些顶尖的js开发者(some of the sharpest Javascript developers in the field)参与开发提供了坚实的基础。虽然你总是可以利用一些使用了jQuery和jQuery UI的库,但是全新的Juice UI控件可以让这些工作更简单。
例如:
   1:  <asp:TextBox runat="server" ID="_Restrict" />
   2:  <Juice:Datepicker
   3:       runat="server"
   4:       TargetControlID="_Restrict"
   5:       MinDate="-20"
   6:       MaxDate="+1M +10D" /> 

执行这段代码,就可以得到:
2012-02-28 09h16_03


组件和行为

Juice UI 发布的时候就已经包括了14个部件或行为。如果你想查看全部控件列表的话,请点击http://juiceui.com/controls, 并且提供互动例子让我们更深入了解控件。
2012-02-28 09h17_29
下面也列出了所有控件,点击可直接转到相应文档:

实战

  • 添加JuiceUI NuGet package
打开VS2010,创建项目前请确保VS2010已安装了NuGet插件。创建一个ASP.NET 4 Web Forms项目。右击项目中的References文件夹,选择Manage NuGet Packages..., 然后找到 "juiceui",点击安装。

2012-02-28 08h10_11

  • JuiceUI 的名字空间
通过NuGet package添加JuiceUI时,NuGet会自动的把Juice UI的名字空间写入到你的web.config文件里, 比如:
   1:  <configuration> 
   2:      <system.web> 
   3:          <compilation debug="true" targetFramework="4.0" /> 
   4:          <pages> 
   5:              <controls> 
   6:                  <add assembly="JuiceUI" namespace="Juice" tagPrefix="juice" /> 
   7:              </controls> 
   8:          </pages> 
   9:      </system.web> 
  10:  </configuration> 

如果确实需要Juice UI名字空间的话,通常我会移除上面这段config,在页面中使用<@Import Namespace="JuiceUI" />指令来添加名字空间。


使用Juice UI控件
首先,你需要一个<asp:ScriptManager> - 把它添加到一个页面上或者你site的Master页面上。
   1:  <asp:ScriptManager id="_Script" runat="server" /> 

添加完成后,你就可以使用控件了。这些都是扩展控件,所以你需要使用TargetControlID属性来指出哪个Web窗体控件将扩展Juice UI的行为。这儿有一个精简了的例子,将DatePicker行为与一个TextBox挂钩:
   1:  <asp:TextBox runat="server" ID="DateSample" /> 
   2:  <Juice:Datepicker runat="server" TargetControlID="DateSample" /> 

另外我把一个可拖拽(Draggable )的行为指向一个Panel:
   1:  <asp:Panel runat="server" ID="DragBox" Style="border:1px solid; width:100px;"> 
   2:      Hi. You can drag me around. 
   3:  </asp:Panel> 
   4:  <Juice:Draggable runat="server" TargetControlID="DragBox" /> 

需要注意的是,这只是非常简单的例子并且没有CSS。在Juice UI源码里有很多更复杂的Juice UI样例。

运行这个页面,我们将会看见我们所期待的:一个拥有日期选择器的textbox和一个可以拖拽的panel。
2012-02-28 10h34_32
下面是这个页面的源代码:
   1:  <%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" 
   2:      CodeBehind="Default.aspx.cs" Inherits="Juice_Sample._Default" %> 
   3:  <asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent"> 
   4:  </asp:Content> 
   5:  <asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent"> 
   6:   
   7:      <asp:ScriptManager id="_Script" runat="server" /> 
   8:      
   9:      <asp:TextBox runat="server" ID="DateSample" /> 
  10:      <Juice:Datepicker runat="server" TargetControlID="DateSample" /> 
  11:      
  12:      <asp:Panel runat="server" ID="DragBox" Style="border:1px solid; width:100px;"> 
  13:          Hi. You can drag me around. 
  14:      </asp:Panel> 
  15:      <Juice:Draggable runat="server" TargetControlID="DragBox" /> 
  16:   
  17:  </asp:Content> 

如果你有兴趣的话,在浏览器中查看网页的源代码,你会发现web控件和JuiceUI行为已经整合了,使用的是HTML5的data-属性:
   1:  <input name="ctl00$MainContent$DateSample" type="text" 
   2:          id="MainContent_DateSample" 
   3:          data-ui-widget="datepicker" /> 
   4:  <div id="MainContent_DragBox" 
   5:          data-ui-widget="draggable" 
   6:          style="border:1px solid; width:100px;"> 
   7:      Hi. You can drag me around. 
   8:  </div> 


似乎很熟悉...

确实,Juice UI用起来非常像Ajax Control Toolkit,但它的核心是jQuery UI。从另一方面说,它是为所有jQuery UI里的部件(widgets)和效果(effects)创建了Web窗体扩展和脚本控制。


更多...

想要寻找更多关于Juice UI的资料?最好的地方是Juice UI site,里面有提供互动的例子和文档。
需要源代码的,可以从GitHub repository下载,里面包含了一个样例项目。
最后,特别推荐的是StackOverflow (using the juiceui tag)ASP.NET jQuery forum,经常逛逛可以获得不少帮助。


后记
个人觉得,Juice UI要被广泛接受还需要走很长的一段路,毕竟Ajax control Toolkit在不断更新,其长期发展方向也是jQuery,所以竞争力很强。不管怎样,Juice UI为我们提出了一个新的思路去整合现有的前端JS框架。Bonne idée, c'est parti!

mardi 20 mars 2012

学习之Bootstrap - Overview

今天是在DotNetNuke平台工作一周年的日子,值得纪念一下。回过头来看,这一年基本上是与DotNetNuke的bug斗争中走过的,同时见证了版本5到6的重大升级。DotNetNuke的框架是挺值得学习和借鉴的,非常全面的系统管理功能和超强的扩展能力让它始终在CMS这一块占据一席之地。
我大部分工作是在后台开发,也即开发或者更新一些模块(module)来迎合客户的需要。但有时候,在客户那里工作时(俗称外包),必须为他们的内部网站设计布局和页面。这是我相当头疼的问题,虽然客户只有一个要求就是漂亮好看,但我始终觉得Dotnetnuke是众多CMS中外观最丑的。
 幸运的是,DNN提供了异常方便和强大的Skin系统,可以让开发者随意便捷的设计主题。不幸的是,它过于有层次感,让我经常迷惑在CSS的覆盖和Javascript的冲突中。另外,不知道是不是因为我不是专业网站设计的缘故,自己搞出来的东东总是让我很郁闷。

在外包的日子,总有些闲暇的时间,我就会寻找或尝试一些CSS框架来为我的DNN主题设计找出路,这样不但可以方便我前端的工作,更重要的是,CSS框架可以帮助我搭建一个漂亮,简洁和清爽的网站。
我的第一个目标是Blueprint,它是一个CSS框架,其目的是减少你的开发时间。它提供了坚实的CSS基础,易使用的网格,合理的排版,有用的插件,甚至印刷样式让你轻松的建立项目。好景不长,没用几天就放弃了,原因有二:
  1. Doc看的比较吃力,思路不清晰。
  2. 没有想象中的强大,总觉得只有CSS不够用。
放弃之后,再也没有时间和心情继续我的DNN主题寻找之旅。直到最近,我在网上看到Twitter的前端工程们发布了新的Bootstrap v2.0.2,较以前成熟的1.4版本有很多Break的升级或改进。以less为基础构建css,新的布局能够定制和响应不同的终端设备,更多的组件和Javascript集成插件,这一切的一切,瞬间让我hold不住了。细细的看了它的在线文档后,突然明白,这就是我一直要找的前端框架,不仅仅只有CSS。
从那时起,我就走在了Bootstrap的路上。写这篇文章是想用来,记录我编程路上的所思所想,更希望的是有大牛能不吝赐教。
总体来说,Bootstrap现在包括四个部分:布局(Scaffolding),基础CSS(Base CSS),控件(Compoment)和Js插件(JavaScript Plugins)。里面各自包含什么,请看下图。不过最吸引我的东东在下图里没有表明出来:通过LESS,我们可以编写和生成我们自己的Bootstrap。LESS是一个CSS的预编译器,相当于赋予了CSS动态语言的特性,如变量,继承,运算,函数,它既可以在客户端上运行(支持IE 6+,Webkit,Firefox),也可以借助Node.js或者Rhino在服务端运行。
这里我想特别说说为什么这个图是英文的:
  1. 我始终觉得英文在这方面的表述要更清晰明了一些,
  2. 翻译不好怕误导大家,
我的Bootstrap还在学习中,尝试中,应用中,希望和大家一起共同学习共同进步。Profitez-le, allez!
P.S. 我学完之后,首先要用它给博客园和wordpress做个主题,写下来,督促自己。

lundi 19 mars 2012

如何在本地安装 DotNetNuke 6

DotNetNuke作为微软平台的第一款开源CMS已经走到了第六个版本,也从VB.NET转换到了C#. 作为一个Dotnetnuke开发者......
当我还想尝试写点开场白时,突然意识到为什么不直接开始呢?既经济又环保.....
我的本地环境:Windows 7 Pro, IIS 7.5, SQL Server 2005, .NET 4.0
总体来说,快速又干净的安装只需要5个步骤:
  1. 下载ZIP安装包
  2. 创建数据库和SQL Server账号
  3. 创建Website文件夹并解压已下载的ZIP安装包
  4. 在IIS里创建Site并配置
  5. 在浏览器中运行DNN安装向导

下面来详细的讲讲这五个步骤:

1. 下载ZIP安装包

现在要下载官方的DNN安装包,只能从http://dotnetnuke.codeplex.com/上下载。CodePlex是微软的开源项目托管平台,DNN作为.NET下最大的开源CMS,使用codeplex托管再正常不过了。不过CodePlex上确实有不少好的开源项目,建议大家没事可以常去转转。现在最新的稳定(Stable)版本是6.1.4,所以下载Dotnetnuke_Community_06.01.04_Install.zip安装包。

2. 创建数据库和SQL Server账号

在创建数据库之前,请确认你的SQL Server身份验证模式是否混合模式。如果不是,请在SQL Server Management Studio里右击你的SQL Server,选择属性,然后点击安全,将SQL Server身份验证模式修改为混合模式。
现在我们可以创建新数据库了(我把它命名为DNN614),具体步骤不用多说了,大家都知道。
接下来,需要给这个新数据库创建一个账户,好让DNN可以有权限读写
  • 展开SQL Server的安全节点
  • 右击Logins
  • 选择New Login
  • 输入Login的名字(比如login614)
  • 选择SQL Server Authentication模式,输入密码
  • 去掉Enforce Password expiration/User must change password at next login的选择
  • 在右边边框点击User Mapping
  • 在上面的Users mapped to this login框中选择你新创建的数据库
  • 然后在下面的Database role membership for框中选择db_owner
  • 点击OK
  • 现在你就可以在DNN614数据库的安全节点里看见新创建的账户了(如图所示)


3. 创建Website文件夹并解压已下载的ZIP安装包

这一步非常简单,就是把ZIP安装包解压到一个文件夹下,比如C:\Dev\WebDnnTest\DNN614。
不过要注意的一点就是,我们必须让用来进入DNN根文件夹的Windows account(例如NETWORK SERVICE)对其有完全的控制权。所以我们必须修改进入这个文件夹的权限:
  • 右击你网站的根目录(C:/Dev/WebDnnTest/DNN614),选择属性
  • 点击安全选项卡
  • 在这个选项卡中可以看见可以进入这个文件夹的用户列表,点击修改
  • 加入NETWORK SERVICE这个账户,保存修改
不过在我记忆中,某些情况,我们可以跳过这项配置。关键在于你在IIS是如何配置的。

4. 在IIS里创建Site并配置

目前为止,我们已经创建了新数据库和配置好了DNN根文件夹,下面我们将在IIS中创建新的Site:
  • 打开IIS并展开Sites节点
  • 右击并点击"Add a new Site"
  • 输入网站名字,选择DNN根目录的路径
  • 输入host名称,比如dnn614
  • 打开 C:/Windows/System32/drivers/etc/hosts 文件,加入新的一行"127.0.0.1  dnn614“,保存
  • 点击Ok完成创建
如果你想你的网站运行在.net 4.0上,请修改application pool为ASP.Net V4.0。

5.在浏览器中运行DNN安装向导

 在浏览器中打开http://dnn614/,你将会看见:



程序会测试文件夹的权限:



输入连接SQL Server的相关信息:



点击Next,你会看到安装向导正在运行每个版本的Script:



再点击Next,配置host账户,这个帐户拥有dnn网站的最高权限,完成后点击Next。如果一切顺利的话,一个全新的DNN6网站就会在你浏览器中出现了:




看到这里,可以告诉你的是,所有的DNN安装已经完成。 Enjoy it. Allez !!!

lundi 12 mars 2012

演化之编程语言

今天在译言网上看到这篇译文,感觉不错,和大家分享一下,顺便说说我自己对这些编程语言的认识。


说说译言网,这是个非常不错的网站,把很多外文(英文,法文...)的好文章都翻译称中文以飨读者,它的宗旨是:“发现 翻译 阅读 中文之外互联网精华”。绝对推荐给不习惯读外文的朋友或者翻译爱好者。

说说这篇文章吧,其实就是一张图,因为译言网不让随便转载,所以只能把地址帖出来,想看全文的可以移步到译言网:新读图时代:编程语言的演化过程。这里只会有大致内容和个人感慨而已。

下图展示了过去数十年来编程语言的演化过程,最先出现的语言是用于科学计算的Fortan和逻辑推演的LISP语言,现在用于网络编程的语言有 C#, Ruby on Rails, Node.JS, Java等等,每一种语言的出现基本上影响了一个时代,比如说C,Java;而在一个时代里,语言之间又有互相的影响,比如Ruby On Rails里MVC的概念;不过个人觉得硬件的发展是影响编程语言发展至关重要的催化剂,iPhone,iPad就是引领移动端编程的先锋。

The Evolution of Programming [Infographic]



Fortan: 现在依然广泛运用于科学和工程计算领域,特别是一些大学里的实验室,Fortan是必备的。

LISP :一种基于λ演算的函数式编程语言,很多牛人和大学里的教授都建议应该学一学的语言,可以帮助我们用另一种方式看待编程语言。
Cobol :看到有人在译言上回复说“现在还有人用Cobol吗?”,答案是当然有人用,特别是大公司,只不过一般人接触不到。
:不用多说,高级语言和低端语言完美结合者,现在依然牢牢的占据者编程语言使用份额排行榜的第二名。
Python : 一种面向对象,直译式计算机程序设计语言。Pour moi, il est un monstre, fort et à plaine puissance.
Java : 懒得说了,基本上无人不知无人不晓。牢牢占据着使用份额排行榜第一。
JavaScript : 浏览器端解释型语言,能让网页更加互动优美华丽。随着浏览器性能和对其支持不断的提搞,现在JavaScript站在了前所未有的高度上,框架层出不穷。不过这门语言对我来说,确实闹心,非常期待新的标准早日出来。
C# :微软家的,大部分对其不爽的,基本上都是对微软有偏见的。经过4个版本的发展,它已经相当强大了。不过每次在IE6和7里调试网页时,那种对微软的不爽蹭的一下就冒上来了,按都按不住。
.Net :微软面向平台的东东。
Ruby On Rails :Ruby是一种语言,日本人开发的,有在线学习的,强烈推荐 Another website for learning Ruby | 推荐一个学Ruby的网站 - Ruby和尚”。Rails是一个MVC框架。Rails对于Ruby就相当于Spring对于Java,不过Rails与Ruby的结合更加完美,他们合在一起就是一个可以使你开发、部署、维护web应用程序变得简单的框架。
Node.JS : 好吧,收回JavaScript只是浏览器端解释型语言,因为Node是一个可以让JavaScript运行在服务器端的解释器,它改变了服务器应该如何工作的概念。可以感觉到它正在引导一场服务器端语言编程的革命。So amazing...

最后,再向大家推荐一个网站,就是提供这个图片的网站 Service Angle. 它的小标题是 :"where technology innovation meets business performance, where computer science meets social science"。这个小标题就是我推荐的原因。一个优秀出色的技术革新没有出彩的商业化和用户体验化的引导和蜕变,被束之在实验室的高阁上是大多数的归宿。

vendredi 2 mars 2012

(Liberation.fr ) Diplômés non grata

L'article originale : Diplômés non grata

Moi, un autre victime potentielle de la circulaire 31 mai 2011......


Malgré de solides études et des promesses d’embauche, les étudiants étrangers se heurtent à la circulaire du printemps dernier qui durcit l’attribution du statut de salarié. Autour du Collectif du 31 mai, la riposte s’organise.

Son entreprise l’a prévenu : il sera licencié dans quelques jours. Tarik El-Hajjar, jeune Marocain de 25 ans, collait pourtant parfaitement au poste. Bardé de diplômes (double master obtenu en France), sourire hollywoodien, tee-shirt turquoise, regard franc. Il a décroché sans mal un poste de consultant junior chez Capgemini, une boîte de conseil. Promesse d’embauche signée avant la fin de ses études, c’est dire.
Mais depuis cinq mois, son avenir en France est en suspens. Il attend une réponse de la préfecture d’Amiens (Somme) à sa demande de changement de statut pour passer du visa d’étudiant à celui de salarié. Dans quelques jours, son titre de séjour arrive à expiration, il ne pourra plus travailler. «J’étais bien parti. J’ai réussi mes études, j’ai de l’ambition. Si j’en suis là, c’est grâce à la France. J’avais juste envie de rendre un peu de ce qu’on m’a donné en travaillant quelque temps ici, en payant des impôts. Ça n’allait pas plus loin. Nous dire non maintenant, c’est difficile à comprendre.»
Tarik fait partie du Collectif du 31 mai qui représente ces jeunes étrangers non-ressortissants de l’Union européenne, fraîchement diplômés en France, mais empêchés d’y travailler. Ils sont chinois, américains, canadiens, africains… Souvent issus de bonne famille, ils parlent plusieurs langues et leur profil séduit les entreprises. Mais dans le pays de Nicolas Sarkozy, ces talents que les économies du monde entier se disputent sont désormais persona non grata, au même titre que les sans-papiers.
Tout est parti de cette fameuse circulaire du 31 mai 2011. Les ministres de l’Intérieur et du Travail, Claude Guéant et Xavier Bertrand, exigent des préfectures qu’elles examinent avec «plus de rigueur» les demandes d’autorisation de travail des immigrés, étudiants compris, quel que soit leur niveau d’études, et même s’ils ont été formés en France.


jeudi 1 mars 2012

Type of Coffe (咖啡种类)



简单介绍俩种个人最爱的 café - Espresso 和 Irish Coffee,前面这个是工作必备,后面是没事就想尝尝的(但至今没喝过几次)。

Espresso :俗称 浓缩咖啡或意大利特浓,口感强烈,不过因冲磨时间短而使得咖啡因的成分较少。 它常作为其它咖啡饮料的基础,比如:拿铁,卡布奇诺,焦糖玛奇朵,摩卡等等。

Irish Coffee :爱尔兰咖啡是一种既像酒又像咖啡的咖啡,爱尔兰威士忌,Espresso,焦糖就可以了,个人不是很喜欢鲜奶油,有点腻。

Pour Débutants en français : 

L'expresso est un café très corsé(serré) avec un fort arôme, et un élément clé de la culture italienne. Il est servi un nombre incalculable de préparations :
  • Café américain : expresso auquel on rajoute de l'eau chaude, parfois en proportions égales ou réalisé avec un percolateur classique;
  • Café macchiato : avec un peu de mousse de lait;
  • Café latte : un grand bol de lait chaud avec un peu de café. Le petit déjeuner familial classique italien; on y trempe généralement des petits biscuits;
  • Café frappé(希腊法拉沛咖啡, 一种冰咖啡.) : expresso, sucre, vanille et glace passés au shaker;
  • Cappuccino : expresso dans une grande tasse complété d'une mousse de lait montée à la vapeur;
  • Irish coffee : un cocktail à base de café, de sucre, de whiskey et de crème.


学习之DOCTYPE

前段时间在园子里看到一篇讲Doctype的文章:正确使用DOCTYPE,就想起了自己在做DotNetNuke开发时也遇到过同样的问题,确实,这个问题说大不大,说小不小。平时在DotNetNuke里,按默认选择的就行了。不过有时同时创建俩个portals,就有俩个不同的skin,它们的DOCTYPE有时候就不一样,这时如果搞不清楚DOCTYPE就调整CSS,要想得到很好的效果和兼容性就很难了。


所以不管怎样,弄清楚DOCTYPE,对前段的开发总是有帮助的。下面就是我找了网上的一些资料总结出来的,保存下来以备不时之需,也同样分享给大家。




要说Doctype,得从浏览器解析不同文档时所使用的模式开始说起,



  • 针对text/html content的模式(Modes for text/html Content),这个模式下又有主要以下三个模式,而对text/html内容进行模式选择依赖于DOCTYPE嗅探(doctype sniffing

    • 怪癖模式(quirks mode)不同的浏览器实现了不同的怪癖行为。Internet Explorer中的怪癖模式会让IE的行为与(包含非标准特性的IE5.5相同;其他浏览器中,怪癖模式是对标准模式的少量偏移。
    • 标准模式(standards mode):这个模式中,浏览器尝试给符合标准的文档在规范上的正确处理达到在指定浏览器中的程度。不同的浏览器遵循不同的阶段,所以效果上会有差别。它和怪癖模式主要影响CSS内容的呈现,但在某些情况下也会影响到JavaScript的解释执行。
    • 准标准模式(almost standards mode):这种模式下的浏览器特性有很多都是符合标准的,但也不尽然,不标准的地方主要体现在处理图片间隙的时候(在表格中使用图片时问题最明显)。
  • 针对application/xhtml+xml的模式(XML Mode),这个模式下不要使用DOCTYPE

    • 在Firefox,Safari,Chrome和Opera中,将HTTP Content-type设置成application/xhtml+xml会触发XML模式。这些浏览器会在某种程度上尽量正确地对待遵守规范的XML文档。
    • IE 6, 7和8及Mac IE 5不支持application/xhtml+xml。

  • 非Web模式(Non-Web Modes),这里不讨论,实际应用中也只有少数引擎有针对非web内容的模式。
这样我们可以很清楚的知道,DOCTYPE主要运用于web文档是text/html content的时候,而DOCTYPE可以决定浏览器在解析文档时使用那种模式。所以下面的文章内容只会限定在针对text/html content的三个模式里。
浏览器模式的不同,肯定会造成一些效果的不同。以下从三个方面来看看浏览器模式的影响:
  • 布局(Layout): text/html中的模式主要会影响CSS布局(layout)。例如,不能让样式被继承至表格内部是一种怪异的地方(quirk)。对某些浏览器的怪异模式,盒模型(box model)会变更到IE5.5盒模型。等等。在准标准模式中(对于那些包含此模式的浏览器来说),和标准模式不同的地方是对于只包含图像的单元格高度的计算。
  • 解析(Parsing):也有一些怪异的地方会影响HTML和CSS的解析(parsing),并使得解析规范的页面失败了。这些怪异的地方主要是由怪异的布局(layout)引起。但值得注意的是,对比标准模式,怪异模式主要体现在CSS的布局和解析中,而不是HTML解析中。
  • 脚本(Script):虽然怪异模式主要和CSS相关,但还是有一些和脚本(scripting)有关的。比如,Firefox的怪异模式中,HTML中的属性id可以从脚本的全局作用域中建立对象引用,就和IE一样。比起其他浏览器,怪异模式对脚本的影响在IE8中尤其明显。


现在来看看,浏览器是如何确定模式的(Doctype sniffing):

现在的浏览器用doctype嗅探(doctype sniffing)方式来为text/html文档确定浏览器引擎模式。这意味着模式将会根据HTML文档开头的文档声明(document type declaration)来选定。(不适用于XML文档。)Doctype嗅探的产生是基于以下的实际情况:当doctype嗅探出来的那会,当doctype嗅探出来的那会,绝大多数“怪异的”文档既没有文档类型声明,也没有引用老的DTD。HTML5认识到了这个事实,而将text/html中的doctype定义为专门为了模式转换。
一个典型的前HTML5文档类型声明包含字符串“<!DOCTYPE”,根元素的通用标识符(“html”),字符串“PUBLIC”,一个引号括起来的DTD公共标识符,也可能包含一个此DTD的系统标识符(一个URL),以及字符“>”。这些东西都用空格隔开。此文档类型声明放在文档中的根元素之前。

  • 对于标准模式,可以通过使用下面任何一种文档类型来开启:

<!-- HTML 4.01 严格型 --> 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 

"http://www.w3.org/TR/html4/strict.dtd"> 

<!-- XHTML 1.0 严格型 --> 
<!DOCTYPE html PUBLIC 
"-//W3C//DTD XHTML 1.0 Strict//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 

  • 而对于准标准模式,则可以通过使用过渡型(transitional)或框架型(frameset)文档类型来触发,如下所示:



<!-- HTML 4.01 过渡型 --> 

<!DOCTYPE HTML PUBLIC 

"-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd"> 

<!-- HTML 4.01 框架集型 --> 
<!DOCTYPE HTML PUBLIC 
"-//W3C//DTD HTML 4.01 Frameset//EN" 
"http://www.w3.org/TR/html4/frameset.dtd"> 

<!-- XHTML 1.0 过渡型 --> 
<!DOCTYPE html PUBLIC 
"-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<!-- XHTML 1.0 框架集型 --> 
< !DOCTYPE html PUBLIC 
"-//W3C//DTD XHTML 1.0 Frameset//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> 

当然相同的模式不同的DOCTYPE声明之间,会有一些细微的差别,下文会提到。





好了,终于可以进入正题了,DOCTYPE:



  • DOCTYPE是什么?
简单地说,doctype就是位于html标签之前的一行声明,这个声明向浏览器指出了当前页面或文档使用了那种规范,(HTML-4 de transition ou strict, XHTML, etc...)。
更完整的DOCTYPE声明写法是:
<!DOCTYPE HTML PUBLIC "type_de_HTML" "adresse_de_DTD"> 其中:


    • type_de_HTML : 表明HTML的使用版本。
    • adresse_de_DTD : 指出了DTD(Document type declaration)的URL地址,用来描述文档的法定结构、元素和属性。


  • 为什么要声明DOCTYPE?
它指明了文档使用的(X)HTML版本,这是诸如浏览器之类的工具解析文档(processing the document)时最需要的信息。比如说,当我们使用Markup Validator来检查文档结构(Syntax)时,必须声明DOCTYPE。其实不用多说,上面的那些废话基本上都在说这个问题。



  • DOCTYPE不同的声明
    • HTML5 :
<!DOCTYPE html>
HTML5的新DOCTYPE标签,更加简单化。它不会让浏览器进入怪癖模式(Quirks mode)

    • HTML4.01 transitional

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
  • 文档是html的:不能被当作XML对待;
  • 没有<marquee><embed>, etc这些标签;
  • 这些元素areadtddplitheadtfootcolgroupcoltrth et td的关闭标签是可选的;
  • 标签不区分大小写 ;
  • 对于HTML的属性,当属性值只包括(a-zA-Z0-9-,_:) 时,引号可以省略。
  • <OPTION selected> 代替 <OPTION selected="selected">
  • 以下的元素或属性是允许的(在html页面中):
    • BASEFONT 和 FONT ;
    • CENTERUSTRIKE 和 S ;
    • BODY 元素的BALINKBACKGROUNDBGCOLORLINKVLINKTEXT 属性;
    • 表格元素的BGCOLORHEIGHTNOWRAPWIDTH 属性;
    • Image和Object的 BORDERHSPACEVSPACE 属性 ;
    • HR 元素的 CLEARNOSHADESIZEWIDTH 属性 ;
    • li元素的 COMPACTTYPE 属性, 和ol元素的 STARTVALUE 属性 ;
    • PRE 元素的 WIDTH 属性 ;
  • IFRAME 是允许的,但 FRAMESET 和 FRAME 不允许 ;

    • HTML4.01 strict
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd"> 
与HTML4.01 transitionnel不同的地方 :
  • 前面特别提出允许的元素和属性不再允许,他们应该在CSS里使用 ;
  • 链接的 target 属性不再被允许 ;
  • IFRAME, FRAMESET 和 FRAME 都不允许。

    • HTML4.01 frameset

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
   "http://www.w3.org/TR/html4/frameset.dtd">
规则基本上与HTML4.01 transitionnel相同, 但 BODY 元素不再存在. 它被可以包含多个 FRAME 元素的 FRAMESET 元素替代.

    • XHTML1.0 transitional :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
文档可以被当作HTML或者XML处理。
与HTML不同的syntax规则如下 :
  • 所有标签都应该关闭;
  • 所有的标签元素属性都应该是小写;
  • 只允许 <option selected="selected"> 这种写法
  • 所有的引号也是必须的 ;
简而言之: 可用的标签基本和HTML4.01 transitional一样, 但它的文法结构syntax要更严格一些.

    • XHTML1.0 strict :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
XHTML1.0 transitionnel一样, syntax的规则是严格的, 但与XHTML1.0 transitionnel不同的地方和HTML4.01 Strict 完全一样:
  • 前面特别提出允许的元素和属性不再允许,他们应该在CSS里使用 ;
  • 链接的 target 属性不再被允许 ;
  • IFRAME, FRAMESET 和 FRAME 都不允许。
简而言之: 可用的标签基本和HTML4.01 strict一样, 但它的文法结构syntax要更严格一些.

    • XHTML1.0 frameset

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
规则基本上与XHTML1.0 transitionnel相同, 但 BODY 元素不再存在. 它被可以包含多个 FRAME 元素的 FRAMESET 元素替代.
简而言之: 可用的标签基本和HTML4.01 frameset一样, 但它的文法结构syntax要更严格一些.

  • 如何选择DOCTYPE
推荐XHTML1.0 Strict;
如果你使用 iframe 或者 target属性, 使用 XHTML1.0 transitional.
如果你使用 frameset 和 frame, 使用XHTML1.0 frameset.
如果你使用 HTML5,直接使用<!doctype html>


  • 最后推荐一个创建(X)HTML结构的工具 :Squelettor