[转载]ASP.NET MVC开源项目--SusuCMS - HackerVirus - 博客园

mikel阅读(1241)

[转载]SusuCMS – HackerVirus – 博客园.

SusuCMS是一款免费开源的基于ASP.NET MVC开发的的CMS。我的目标是使他尽量对普通用户友好,对开发者友好。

1. 安装完SusuCMS后,使用网址:http://您的域名/admin 进入系统管理后台(默认用户名为admin,默认密码为admin)。 

 

2. 进入后台直接点击左边菜单的Sites,即可管理站点列表。SusuCMS是支持多站点的。这边我已经创建了4个不同的站点。

3. 点击Create按钮,你可以创建网站了。这边有个Template选项是提供站点模版的选择的,如果你想创建一个Blog类型的站点就可以选择Blog – Maximus4T选项。一旦创建网站点就不可更改。Url是网站的主地址,也支持子目录和ip,端口号之类的。点击保存后,系统会自动初始化数据,创建 一些基本的页面。

 

4. 创建页面。为了可以单独对单个站点进行编辑,你可以点击站点列表的扳手图标进入。或者点击左边菜单进入。

 

 

 5.页面管理。列表是树状的,在这里你可以修改页面状态。页面之间的父子关系。点击鼠标形状按钮即可进入页面可视化管理。

 

 

 

6. 页面Widget管理。Widget在使用之前需创建。

 

更多请访问: http://www.susucms.com

源码在http://sourceforge.net/projects/susucms 上,

[转载]ASP.NET MVC3关于生成纯静态后如何不再走路由直接访问静态页面_实用技巧_脚本之家

mikel阅读(1150)

[转载]ASP.NET MVC3关于生成纯静态后如何不再走路由直接访问静态页面_实用技巧_脚本之家.

高访问量类型的电子商务网站,需要将一些不是经常变化的页面生成静态页面,然后普通用户就可以直接访问这些静态页面而不用再访问需要连接数据库的动态页面。那么ASP.NET MVC3中如何做到这一点呢
要解决这个问题,我们需要先了解ASP.NET应用程序的生命周期,先看下面作者整理的一张图片:

从图中我们可以清楚的看到:通用IIS访问应用程序时,每次的单个页面URL访问时,都会先经过HttpApplication 管线处理请求,走过BeginRequest 事件之后才会去走路由访问具体的Controller和Action,最后结束的时候会请求EndRequest事件。下面用一张图来表示这个顺序:

注意图中标示的红色部分就是我们要实现的部分,实现如下:
1 新建MyHandler.cs

复制代码 代码如下:
public class MyHandler:IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
string filePath = context.Request.FilePath;
string fileExtension =
VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(“.html”))
{
context.Response.WriteFile(context.Server.MapPath(filePath));//直接走静态页面
//此处可以加入缓存,条件也可以根据需要来自己定义
context.Response.End();
}
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
string filePath = context.Request.FilePath;
string fileExtension =
VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(“.html”))
{
context.Response.Write(“<hr><h1><font color=red>” +
“HelloWorldModule: End of Request</font></h1>”);
}
}
public void Dispose() { }
}

2. web.config中加入以下代码,才会运行自定义的管道处理类
复制代码 代码如下:
<httpModules>
<add name=”MvcTest.MyHandler” type=”MvcTest.MyHandler”/>
</httpModules>

运行一下自己的代码,看看效果你就全明白了!
补充:根据@小尾鱼的提示,如果直接在自己的项目文件下生产了和URL中一样的目录文件,比如访问:yourdomin.com/product/1.html,你的项目文件夹下真的存在product/1.html这个路径,那么IIS会直接去请求这个静态页面,如果项目中使用了自定义的管道处理程序,那么这个静态页仍然会走我们的自定义管道处理程序,我们可以在这里通过缓存来实现要不要重新成长静态页或删除过期产品的静态页,如果不使用此方法,只能去写执行计划,定时跑这些静态文件了,修改Application_BeginRequest
复制代码 代码如下:
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
string filePath = context.Request.FilePath;
string fileExtension =
VirtualPathUtility.GetExtension(filePath);
if (fileExtension.Equals(“.html”))
{
//判断缓存是否存在,不存在加入缓存,调用生成静态的类和方法
//产品过期,移除静态文件,302重定向
if (System.IO.File.Exists(context.Server.MapPath(filePath)))
{
context.Response.WriteFile(context.Server.MapPath(filePath));
context.Response.End();
}
}

[转载]asp.net mvc3的静态化实现 - TerryLiang - 博客园

mikel阅读(1362)

[转载]asp.net mvc3的静态化实现 – TerryLiang – 博客园.

静态化处理,可以大大提高客户的访问浏览速度,提高用户体验,同时也降低了服务器本身的压力。在ASP.NET mvc3中,可以相对容易地处理静态化问题,不用过多考虑静态网页的同步,生成等等问题。我提供这个方法很简单,就需要在需要静态化处理的 Controller或Action上加一个Attribute就可以。下面是我写的一个生成静态文件的ActionFilterAttribute。

using System;
using System.IO;
     using System.Text;
     using System.Web;
     using System.Web.Mvc;
     using NLog;

     /// <summary>
     /// 生成静态文件
     /// </summary>
     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
     public class GenerateStaticFileAttribute : ActionFilterAttribute
     {
         #region 私有属性

         private static readonly Logger logger = LogManager.GetCurrentClassLogger();

         #endregion

         #region 公共属性

         /// <summary>
         /// 过期时间,以小时为单位
         /// </summary>
         public int Expiration { get; set; }

         /// <summary>
         /// 文件后缀名
         /// </summary>
         public string Suffix { get; set; }

         /// <summary>
         /// 缓存目录
         /// </summary>
         public string CacheDirectory { get; set; }

         /// <summary>
         /// 指定生成的文件名
         /// </summary>
         public string FileName { get; set; }

         #endregion

         #region 构造函数

         /// <summary>
         /// 默认构造函数
         /// </summary>
         public GenerateStaticFileAttribute()
         {
             Expiration = 1;
             CacheDirectory = AppDomain.CurrentDomain.BaseDirectory;
         }

         #endregion

         #region 方法

         public override void OnResultExecuted(ResultExecutedContext filterContext)
         {
             var fileInfo = GetCacheFileInfo(filterContext);

             if ((fileInfo.Exists && fileInfo.CreationTime.AddHours(Expiration) < DateTime.Now) || !fileInfo.Exists)
             {
                 var deleted = false;

                 try
                 {
                     if (fileInfo.Exists)
                     {
                         fileInfo.Delete();
                     }

                     deleted = true;
                 }
                 catch (Exception ex)
                 {
                     logger.Error("删除文件:{0}发生异常:{1}", fileInfo.FullName, ex.StackTrace);
                 }

                 var created = false;

                 try
                 {
                     if (!fileInfo.Directory.Exists)
                     {
                         fileInfo.Directory.Create();
                     }

                     created = true;
                 }
                 catch (IOException ex)
                 {
                     logger.Error("创建目录:{0}发生异常:{1}", fileInfo.DirectoryName, ex.StackTrace);
                 }

                 if (deleted && created)
                 {
                     FileStream fileStream = null;
                     StreamWriter streamWriter = null;

                     try
                     {
                         var viewResult = filterContext.Result as ViewResult;
                         fileStream = new FileStream(fileInfo.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.None);
                         streamWriter = new StreamWriter(fileStream);
                         var viewContext = new ViewContext(filterContext.Controller.ControllerContext, viewResult.View, viewResult.ViewData, viewResult.TempData, streamWriter);
                         viewResult.View.Render(viewContext, streamWriter);
                     }
                     catch (Exception ex)
                     {
                         logger.Error("生成缓存文件:{0}发生异常:{1}", fileInfo.FullName, ex.StackTrace);
                     }
                     finally
                     {
                         if (streamWriter != null)
                         {
                             streamWriter.Close();
                         }

                         if (fileStream != null)
                         {
                             fileStream.Close();
                         }
                     }
                 }
             }
         }

         /// <summary>
         /// 生成文件Key
         /// </summary>
         /// <param name="controllerContext">ControllerContext</param>
         /// <returns>文件Key</returns>
         protected virtual string GenerateKey(ControllerContext controllerContext)
         {
             var url = controllerContext.HttpContext.Request.Url.ToString();

             if (string.IsNullOrWhiteSpace(url))
             {
                 return null;
             }

             var th = new TigerHash();
             var data = th.ComputeHash(Encoding.Unicode.GetBytes(url));
             var key = Convert.ToBase64String(data, Base64FormattingOptions.None);
             key = HttpUtility.UrlEncode(key);

             return key;
         }

         /// <summary>
         /// 获取静态的文件信息
         /// </summary>
         /// <param name="controllerContext">ControllerContext</param>
         /// <returns>缓存文件信息</returns>
         protected virtual FileInfo GetCacheFileInfo(ControllerContext controllerContext)
         {
             var fileName = string.Empty;

             if (string.IsNullOrWhiteSpace(FileName))
             {
                 var key = GenerateKey(controllerContext);

                 if (!string.IsNullOrWhiteSpace(key))
                 {
                     fileName = Path.Combine(CacheDirectory, string.IsNullOrWhiteSpace(Suffix) ? key : string.Format("{0}.{1}", key, Suffix));
                 }
             }
             else
             {
                 fileName = Path.Combine(CacheDirectory, FileName);
             }

             return new FileInfo(fileName);
         }

         #endregion
     }

如果大家对于生成的文件和目录有特殊的要求,那可以重写GetCacheFileInfo方法,比如按照日期生成目录等等更复杂的目录和文件结构。当然以上代码只是提供了生成静态页的方法,但是访问如何解决呢? 访问静态文件和规则就需要在HttpApplication的Application_BeginRequest实现了。首先可以设置需要静态化访问的路由地址以html结尾。下面的是一个用于首页的静态化访问的实现,很简单,当然你可以实现比较复杂的逻辑,比如根据文件时间来判断是否应该访问静态文件等等。

protected void Application_BeginRequest(object sender, EventArgs e)
         {
             StaticContentRewrite();
         }

         /// <summary>
         /// 处理静态发布内容
         /// </summary>
         private void StaticContentRewrite()
         {
             if (Context.Request.FilePath == "/" || Context.Request.FilePath.StartsWith("/index.html", StringComparison.OrdinalIgnoreCase))
             {
                 if (File.Exists(Server.MapPath("index.html")))
                 {
                     Context.RewritePath("index.html");
                 }
             }

[转载]CSS z-index 属性的使用方法和层级树的概念 - NeoEase

mikel阅读(920)

[转载]CSS z-index 属性的使用方法和层级树的概念 – NeoEase.

CSS 中的 z-index 属性用 于设置节点的堆叠顺序, 拥有更高堆叠顺序的节点将显示在堆叠顺序较低的节点前面, 这是我们对 z-index 属性普遍的认识. 与此同时, 我们总是对堆叠顺序捉摸不透, 将 z-index 的值设得很大也未必能将节点显示在最前面. 本文将通过一些例子对 z-index 的使用方法进行分析, 并且为各位带入 z-index 层级树的概念.

 

这个星期我们团队做了一次内部的技术分享, 南瓜小米粥为我们分享了他对 CSS z-index 的理解和引入层级树这个概念. 这个分享的现场效果很好, 所以我也将 z-index 和层级树话题搬到博客来谈一谈.

本文谈及多个影响节点显示层级的规则, 其中用到的所有例子全部罗列在《position 属性和 z-index 属性对页面节点层级影响的例子》中.

目录

顺序规则

如果不对节点设定 position 属性, 位于文档流后面的节点会遮盖前面的节点.

<div id="a">A</div>
<div id="b">B</div>

CSS z-index 属性顺序规则的例子

定位规则

如果将 position 设为 static, 位于文档流后面的节点依然会遮盖前面的节点浮动, 所以 position:static 不会影响节点的遮盖关系.

<div id="a" style="position:static;">A</div>
<div id="b">B</div>

CSS z-index 属性定位规则的例子, static

如果将 position 设为 relative (相对定位), absolute (绝对定位) 或者 fixed (固定定位), 这样的节点会覆盖没有设置 position 属性或者属性值为 static 的节点, 说明前者比后者的默认层级高.

<div id="a" style="position:relative;">A</div>
<div id="b">B</div>

CSS z-index 属性定位规则的例子, relative | absolute | fixed

在没有 z-index 属性干扰的情况下, 根据这顺序规则和定位规则, 我们可以做出更加复杂的结构. 这里我们对 A 和 B 都不设定 position, 但对 A 的子节点 A-1 设定 position:relative. 根据顺序规则, B 会覆盖 A, 又根据定位规则 A’ 会覆盖 B.

<div id="a">
	<div id="a-1" style="position:relative;">A-1</div>
</div>
<div id="b">B</div>

CSS z-index 属性互相覆盖的例子

上面互相覆盖在什么时候用到这样的实现? 看起来偏门, 其实很常用, 比如说, 电子商务网站侧栏的类目展示列表就可以用这个技巧来实现.

下图是某网站的类目展示区域, 二级类目的悬浮层覆盖一级类目列表外框, 而一级类目的节点覆盖二级类目的悬浮层. 如果使用 CSS 实现展示效果, 一级类目的外框相当于上面例子中的 A, 一级类目的节点相当于 A-1, 二级类目的悬浮层相当于 B.

电子商务网站侧栏的类目展示列表

参与规则

我们尝试不用 position 属性, 但为节点加上 z-index 属性. 发现 z-index 对节点没起作用.

<div id="a" style="z-index:2;">A</div>
<div id="b" style="z-index:1;">B</div>
<div id="c" style="z-index:0;">C</div>

CSS z-index 属性参与规则的例子, 没有明确定位的时候

W3C 对 z-index 属性的描述中提到 在 z-index 属性仅在节点的 position 属性为 relative, absolute 或者 fixed 时生效.

The z-index property specifies the stack order of an element. Only works on positioned elements(position: absolute;, position: relative; or position: fixed;).

<div id="a" style="z-index:2;">A</div>
<div id="b" style="position:relative;z-index:1;">B</div>
<div id="c" style="position:relative;z-index:0;">C</div>

CSS z-index 属性参与规则的例子, 明确定位的节点才能使用 z-index 属性

默认值规则

如果所有节点都定义了 position:relative. z-index 为 0 的节点与没有定义 z-index 在同一层级内没有高低之分; 但 z-index 大于等于 1 的节点会遮盖没有定义 z-index 的节点; z-index 的值为负数的节点将被没有定义 z-index 的节点覆盖.

<div id="a" style="position:relative;z-index:1;">A</div>
<div id="b" style="position:relative;z-index:0;">B</div>
<div id="c" style="position:relative;">C</div>
<div id="d" style="position:relative;z-index:0;">D</div>

CSS z-index 属性默认值规则的例子

通过检查我们还发现, 当 position 设为 relative, absolute 或者 fixed, 而没有设置 z-index 时, IE8 以上和 W3C 浏览器 (下文我们统称为 W3C 浏览器) 的 z-index 默认值是 auto, 但 IE6 和 IE7 是 0.

从父规则

如果 A, B 节点都定义了 position:relative, A 节点的 z-index 比 B 节点大, 那么 A 的子节点必定覆盖在 B 的子节点前面.

<div id="a" style="position:relative;z-index:1;">
	<div id="a-1">A-1</div>
</div>

<div id="b" style="position:relative;z-index:0;">
	<div id="b-1">B-1</div>
</div>

CSS z-index 属性从父规则的例子, 子节点不设定层级

如果所有节点都定义了 position:relative, A 节点的 z-index 和 B 节点一样大, 但因为顺序规则, B 节点覆盖在 A 节点前面. 就算 A 的子节点 z-index 值比 B 的子节点大, B 的子节点还是会覆盖在 A 的子节点前面.

<div id="a" style="position:relative;z-index:0;">
	<div id="a-1" style="position:relative;z-index:2;">A-1</div>
</div>

<div id="b" style="position:relative;z-index:0;">
	<div id="b-1" style="position:relative;z-index:1;">B-1</div>
</div>

CSS z-index 属性从父规则的例子, 不可逾越的层级

很多人将 z-index 设得很大, 9999 什么的都出来了, 如果不考虑父节点的影响, 设得再大也没用, 那是无法逾越的层级.

层级树规则

可能你会觉得在 DOM 结构中的兄弟节点会拎出来进行比较并确定层级, 其实不然.

<div id="a" style="position:relative;z-index:2;">
	<div id="a-1" style="position:relative;z-index:0;">A-1</div>
</div>

<div id="b">
	<div id="b-1" style="position:relative;z-index:1;">B-1</div>
</div>

CSS z-index 属性层级树规则的例子

我们认为同时将 position 设为 relative, absolute 或者 fixed, 并且 z-index 经过整数赋值的节点, 会被放置到一个与 DOM 不一样的层级树里面, 并且在层级树中通过对比 z-index 决定显示的层级. 上面的例子如果用层级树来表示的话, 应该如下图所示.

CSS z-index 的层级树

图中虽然 A-1 (z-index:0) 的值比 B-1 (z-index:1) 小, 但因为在层级树里 A (z-index:2) 和 B-1 在一个层级, 而 A 的值比 B-1 大, 根据从父规则, A-1 显示在 B-1 前面.

参与规则 2

前面提到的参与规则认为只要节点的 position 属性为 relative, absolute 或者 fixed, 即可参与层级比较, 其实不准确. 如果所有节点都定义了 position:relative, 并且将 z-index 设为整数值, 根据从父规则, 父节点的层级决定了子节点所在层级.

<div id="a" style="position:relative;z-index:0;">
	<div id="a-1" style="position:relative;z-index:100;">A-1</div>
</div>

<div id="b">
	<div id="b-1" style="position:relative;z-index:0;">
		<div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
	</div>
</div>

<div id="c" style="position:relative;z-index:0;">
	<div id="c-1">
		<div id="c-1-1">
			<div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
		</div>
	</div>
</div>

例子中 A, B-1, C-1-1 作为父节点, z-index 的值相同, 根据顺序规则, C-1-1 在 B-1 之前, B-1 在 A 之前; 又根据从父规则, 无论子节点的 z-index 值是什么, C-1-1-1 在 B-1-1 之前, B-1-1 在 A-1 之前.

CSS z-index 属性参与规则 2 的例子, 所有节点参与层级比较

如果我们将所有父节点的 z-index 属性去除, 诡异的事情发生了. IE6 和 IE7 浏览器显示效果不变, 而 W3C 浏览器的子节点不再从父, 而是根据自身的 z-index 确定层级.

<div id="a" style="position:relative;">
	<div id="a-1" style="position:relative;z-index:100;">A-1</div>
</div>

<div id="b">
	<div id="b-1" style="position:relative;">
		<div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
	</div>
</div>

<div id="c" style="position:relative;">
	<div id="c-1">
		<div id="c-1-1">
			<div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
		</div>
	</div>
</div>

根据默认值规则, IE6 / IE7 和 W3C 浏览器上的元素存在 z-index 默认值的区别. 我们相信, 仅当 position 设为 relative, absolute 或者 fixed, 并且 z-index 赋整数值时, 节点被放置到层级树; 而 z-index 为默认值时, 只在 document 兄弟节点间比较层级. 在 W3C 浏览器中, A, B-1 和 C-1-1 的 z-index 均为 auto, 不参与层级比较.

CSS z-index 属性参与规则 2 的例子, z-index 为 auto 的节点不参与层级比较

而在 IE6 和 IE7 中, 因为 z-index 的默认值是 0, 所以也参与了层级比较.

CSS z-index 属性参与规则 2 的例子, IE6 和 IE7 中 z-index 默认为 0

设置了 position 而没有 z-index 的节点虽然不参与层级树的比较, 但还会在 DOM 中与兄弟节点进行层级比较.

<div id="a" style="position:relative;">
	<div id="a-1" style="position:relative;z-index:100;">A-1</div>
</div>

<div id="b">
	<div id="b-1">
		<div id="b-1-1" style="position:relative;z-index:10;">B-1-1</div>
	</div>
</div>

<div id="c" style="position:relative;">
	<div id="c-1">
		<div id="c-1-1">
			<div id="c-1-1-1" style="position:relative;z-index:1;">C-1-1-1</div>
		</div>
	</div>
</div>

我们对上个例子改造一下, 将 B-1 的 position 属性删除后, W3C 浏览器显示如下图. 根据定位规则, A 和 C-1-1 会显示在 B-1 的前面; 而根据顺序规则, C-1-1 又显示在 A 前面.

CSS z-index 属性参与规则 2 的例子, position 为 auto 的节点不参与层级树比较, 但仍参与 DOM 兄弟节点间的层级比较, W3C 浏览器

在 IE6 和 IE7 中, 因为 A 和 C-1-1 设置了 position:relative, 而且 z-index 的默认值为 0, 所以也参与层级树比较, 所以有如下效果.

CSS z-index 属性参与规则 2 的例子, position 为 auto 的节点不参与层级树比较, 但仍参与 DOM 兄弟节点间的层级比较, IE6 和 IE7

总结

浏览器节点显示层级是一个费力的活, 今天你觉得 A 区块会永远置顶, 但明天因为需求变动, 突然出现 B 元素需要置顶. 一层一层往上堆砌, 某天回头一看, 发现很多区块交错在一起, 而且他们的值一个比一个大, 根本搞不清头绪. 我觉得在操刀干活之前, 最好先将 position, z-index 和层级的关系搞搞清楚, 以免后患无穷.

另外, 非情非得已, 切勿用 JavaScript 计算 z-index, 并将某个节点的 z-index 设置成所有节点中层级最高.

因为篇幅太长, 本文仅从节点属性角度进行讨论, 没有涉及 select 和 iframe 等特殊页面节点考虑, 如果有机会下次再为大家分享.

[转载]jQuery之CSS 控制 - 逆心 - 博客园

mikel阅读(927)

[转载]jQuery之CSS – 逆心 – 博客园.

1、offset()获取匹配元素在相对浏览器窗口的偏移量  返回一个对象,包括两个属性。left:相对浏览器窗口左边的距离。top:相对浏览器顶部的距离。

$(“#div1”).offset().left;  //返回id为div1相对于浏览器窗口最左边的距离

$(“#div1”).offset().top;  //返回id为div1相对于浏览器窗口最顶部的距离

以下例子展示了,当点击文本框时,在下方显示一个日期div。紧紧贴住上面的文本框。并且不需要调div的css位置,无论上面的文本框位置如 果变化,都能够紧紧且住上面的文本框,记得在前几天搞爱的车轮战报名系统的js模拟下拉列表的时候是调CSS贴住上面的文本框的,这样一旦改变了文本框的 位置,模拟的下拉列表的div的css也要跟住调,其实这是很SB的。下面这个方法好。

复制代码
function showDiv(obj) {
  jQuery("#divShow").css("left", jQuery(obj).offset().left);  //设置#divShow与浏览器的左距离为文本框距离浏览器左边的距离。
  jQuery("#divShow").css("top", jQuery(obj).offset().top + jQuery(obj).outerHeight());  //设置#divShow距离顶部的距离为文本框距离顶部的距离加上自                                                 身高度。
  jQuery("#divShow").show();
}

<input type="text" value="ok" onclick="showDiv(this);" style="margin-left:100px;" />
<div id="divShow" style="display:none;position:absolute;">2010-03-22</div>
复制代码

2、position()获取匹配元素在相对父元素的偏移量  返回一个对象,包括两个属性。left:相对父元素最左边的距离。top:相对父元素最右边的距离。只对可见元素有效。

复制代码
<head>
    <title></title>
    <script src="jquery-1.7.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn1").click(function () {
                var left = $("#div2").position().left;  //21.11111
                var top = $("#div2").position().top;    //33.33333
                alert("距离父元素顶部的距离是:" + left + "; 距离父元素左边的距离是:" + top);
            })
        })
    </script>
</head>
<body>
    <div id="div1" style="width:200px;height:400px;border:10px solid #000; padding:20px 20px; margin:30px 30px; position:relative;">
        <div id="div2" style="width:100px;height:200px; background-color:Green; position:absolute; left:22px; top:34px;">我是一个div元素</div>
        <input id="btn1" type="button" value="查看" />
    </div>
</body>
复制代码

以上代码相当于JavaScript中的:

        function fun1() { var left = document.getElementById("div2").offsetLeft;  //21 var top = document.getElementById("div2").offsetTop;   //33 alert("距离父元素顶部的距离是:" + left + "; 距离父元素左边的距离是:" + top); }

JavaScriptJQuery不同一点的地方就是它输出的是整数21,33,但是跟CSS设置的却差了一个像素,JQuery还能够用Math里的方法来还原,但是JavaScript就不知道怎么搞了。

 

3、scrollTop()    获取匹配元素距离滚动条顶部的距离,说白了就是边框的最顶部与当前显示出来的最顶部的距离。

scrollTop(val)  设置匹配元素距离滚动条顶部的距离

该属性常常配合scroll()事件一起使用,能够实现元素随滚动条的滚动而滚动,类似于漂浮广告效果。

$(this).scroll(function(){

$(“#div1”).css(“top”, $(document).scrollTop());  //注意id为div1的div要设置为绝对定位。如果是底部漂浮,只需要$(document).scrollTop()加上相应的垂直距离就可以了。

  })

4、scrollLeft()     获取匹配元素距离滚动条顶部的距离,说白了就是边框的最左边与当前显示出来的最左边的距离。

scrollLeft(val)  设置匹配元素距离滚动条顶部的距离

复制代码
<head>
    <title></title>
    <script src="jquery-1.7.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn1").click(function () {
                var scrollTop = $("#div1").scrollTop();
                var scrollLeft = $("#div1").scrollLeft();
                alert("显示的最顶部距离真正的顶部的距离是:" + scrollTop + "; 显示的最左边距离真正的左边的距离是:" + scrollLeft);
            })
        })
    </script>
</head>
<body>
    <div id="div1" style="width:200px;height:400px;border:10px solid #000; padding:20px 20px; margin:30px 30px; overflow:scroll;">
        <div style="width:400px;height:800px;/*撑出滚动条*/">我是一个div元素</div>
        <input id="btn1" type="button" value="查看" />
    </div>
</body>
复制代码

5、height()    获取匹配元素的高度值  //不包括padding,不包括边框 val可以是字符串”300px”、也可以是数字300,还可以是一个函数,返回值作为参数

height(val)    设置匹配元素的高度值

6、 width()     获取匹配元素的宽度值  //不包括padding,不包括边框

width(val)     设置匹配元素的宽度值

复制代码
<head>
    <title></title>
    <script src="jquery-1.7.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn1").click(function () {
                var Width = $("#div1").width();   //200 css的width属性,不包括内边距、边框和外边距
                var Height = $("#div1").height(); //400 css的height属性,不包括内边距、边框和外边距
                alert("div1的宽度是:" + Width + "; div1的高度是:" + Height);
            })
        })
    </script>
</head>
<body>
    <div id="div1" style="width:200px;height:400px;border:10px solid #000; padding:20px 20px; margin:30px 30px;">
        我是一个div元素
        <input id="btn1" type="button" value="查看" />
    </div>
</body>
复制代码

7、innerHeight()    获取匹配元素的高度值   //包括padding但不包括border

innerHenght(val)  设置匹配元素的高度值

8、innerWidth()     获取匹配元素的宽度值  //包括padding但不包括border

innerWidth(val)     设置匹配元素的宽度值

复制代码
<head>
    <title></title>
    <script src="jquery-1.7.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn1").click(function () {
                var innerWidth = $("#div1").innerWidth();   //240 包括边框和内边距
                var innerHeight = $("#div1").innerHeight(); //440 包括边框和内边距
                alert("div1的宽度是:" + innerWidth + "; div1的高度是:" + innerHeight);
            })
        })
    </script>
</head>
<body>
    <div id="div1" style="width:200px;height:400px;border:10px solid #000; padding:20px 20px; margin:30px 30px;">
        我是一个div元素
        <input id="btn1" type="button" value="查看" />
    </div>
</body>
复制代码

以上的主JQuery相当于代码(javascript版):

function fun1() {
  var innerWidth = document.getElementById("div1").clientWidth;
  var innerHeight = document.getElementById("div1").clientHeight;
  alert("div1的宽度是:" + innerWidth + "div1的高度是:" + innerHeight);
}

9、 outerHeight()    获取元素的高度值  //包括padding和border

outerHeight(val)    设置元素的高度值

还可以接受一个参数,该参数代表是否计算外边距,如果为true则表示计算外边距。

10、outerWidth()    获取匹配元素的宽度值  //(包括padding和border)

outerWidth()     设置匹配元素的宽度值

还可以接受一个参数,该参数代表是否计算外边距,如果为true则表示计算外边距。

复制代码
<head>
    <title></title>
    <script src="jquery-1.7.1.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#btn1").click(function () {
                var outerWidth = $("#div1").outerWidth();   //260包括边框和内边距
                var outerHeight = $("#div1").outerHeight(); //460 包括边框和内边距
                alert("div1的宽度是:" + outerWidth + "; div1的高度是:" + outerHeight);

                var outerWidth1 = $("#div1").outerWidth(true);   //320 包括边框、外边距和内边距(也就是元素实际占用的大小)
                var outerHeight1 = $("#div1").outerHeight(true); //520 包括边框、外边距和内边距(也就是元素实际占用的大小)
                alert("div1的宽度是:" + outerWidth1 + "; div1的高度是:" + outerHeight1);
            })
        })
    </script>
</head>
<body>
    <div id="div1" style="width:200px;height:400px;border:10px solid #000; padding:20px 20px; margin:30px 30px;">
        我是一个div元素
        <input id="btn1" type="button" value="查看" />
    </div>
</body>
复制代码

jQuery的参数不为真的情况下,以上jQuery的主代码相当于:

        function fun1() {
            var outerWidth = document.getElementById("div1").offsetWidth;
            var outerHeight = document.getElementById("div1").offsetHeight;
            alert("div1的宽度是:" + outerWidth + "; div1的高度是:" + outerHeight);
        }

如果参数为真的情况下,就相当于javascript:

复制代码
        function fun1() {
            var div1 = document.getElementById("div1");
            var outerWidth1 = div1.offsetWidth + parseInt(div1.style.marginLeft) + parseInt(div1.style.marginRight);
            var outerHeight1 = div1.offsetHeight + parseInt(div1.style.marginTop) + parseInt(div1.style.marginBottom);
            alert("div1的宽度是:" + outerWidth1 + "; div1的高度是:" + outerHeight1);
        }
复制代码

此处可能写的不是很好,应该有更好的办法,本人javascript还在初学当中。

[转载]仿 Google Reader 随滚动条滚动加载页面效果 - wupingzsf - 博客园

mikel阅读(993)

转载仿 Google Reader 随滚动条滚动加载页面效果 – wupingzsf – 博客园.

Google阅读器上 有一个AJAXscollLoad效 果很不错,就是阅读项目时不需要翻页,浏览器滚动条往下拉到一定位置时自动加载新的一批项目进来,一直到所有项目加载完为止。对于我来说 再好不过了,因为我很不喜欢翻页,尤其是输入页码再定位到页。要知道,数据量增加很频繁时,要通过定位页码来找到目标数据似乎并没有什么意义。我觉得用户 体验成熟的WEB应用程序应当引导用户使用TAG或搜索等功能来找到目标数据。至于浏览数据,尤其是浏览最新的数据,利用浏览器滚动条来加载,是很好的尝 试……

我试着用JQuery来实现这个功能。先要得到滚动条的总长属性值:scrollHeight,还有滚动条当前位置属性 值:scrollTop。然后通过计算,若当前值位于总长值三分之二时加载新数据。假设DOM上有一个元素为<div id=”mypage”></div>,该元素overflow样式为scroll,也就是元素中的内容溢出元素指定高度时启用滚动 条。利用JQuery的load方法为元素加载一个已经存在的文件,我假设它是table.html。这个文件的内容可以是足以使浏览器滚屏的一张数据 表。

<script type=”text/JavaScript” src=”jquery.js“>//加载jQuery库</script>
<script type=”text/JavaScript”>

var hght=0;//初始化滚动条总长
var top=0;//初始化滚动条的当前位置
$(document).ready(function(){//DOM的onload事件
$(”#mypage”).load(”table.html”);//table.html的内容被加载到mypage元素

$(”#mypage”).scroll( function() {//定义滚动条位置改变时触发的事件。
hght=this.scrollHeight;//得到滚动条总长,赋给hght变量
top=this.scrollTop;//得到滚动条当前值,赋给top变量
});
});

setInterval(”cando();”,2000);//每隔2秒钟调用一次cando函数来判断当前滚动条位置。

function cando(){
if(top>parseInt(hght/3)*2)//判断滚动条当前位置是否超过总长的2/3,parseInt为取整函数
show();//如果是,调用show函数加载内容。
}

function show(){
$.get(”table.html”, function(data){//利用jQuery的get方法得到table.html内容
$(”#mypage”).append(data);//用append方法追加内容到mypage元素。
hght=0;//恢复滚动条总长,因为$(”#mypage”).scroll事件一触发,又会得到新值,不恢复的话可能会造成判断错误而再次加载……
top=0;//原因同上。
});
}

</script>
<div id=”mypage”></div>

为 什么要隔2秒钟调用一次判断呢?因为只要$(”#mypage”).scroll事件一被触发,就会影hght和top值,这个值可能总是满足cando 函数的判断,也就是top值总是位于hght的三分之二。因此可能会多次加载造成服务器负担加重。而每加载一次后把hght和top值赋0,也是这个原 因。

这段代码的效果就是只要元素mypage的滚动条位置位于滚动条总长的三分之二时,追加table.html的内容到元素mypage 中去。当然这样运行是无休止地加载下去。在真正的AJAX运用中,table.html可以换成asp或php脚本,接收get或post参数来进行处 理,然后返回有意义的数据。jQuery的get方法可以设置get方式的参数数据,比如:

$.get(”test.php”, { name: “boho”, id: “1″ } );

相当于http://hostlocal/test.php?name=boho&id=1这种形式的http访问。然后通过get方法的回调函数来获取test.php输出的内容:

$.get(”test.php”, {name:”boho”,id:”1″},function(data){
alert(”Data Loaded: ” + data);
});

[转载]15个非常不错的PHP 组件、工具和教程 - 好收藏 - 博客园

mikel阅读(945)

[转载]15个非常不错的PHP 组件、工具和教程 – 好收藏 – 博客园.

原文地址:http://www.goodfav.com/zh/15-useful-php-components-techniques-and-tutorials-384.html

PHP是一种用于创建动态Web应用程序最流行的开发语言。一些最有影响力和非常流行的开源CMS /出版平台,如WordPress,Joomla和Drupal的都是用PHP开发的。 PHP有很多有点,它快速,稳定,安全,易于使用并且开放源码。熟悉PHP的Web开发人员要想有一个良好的开发效率,一些工具箱是必不可少的。

在下面的这篇文章中,我整理了一份有用的PHP组件,工具和教程,有了它们,PHP开发人员的生活应该会轻松许多。

PHP 集成环境

XAMPP

PHP 框架

cakephp

CodeIgniter

pear.php.net

Symfony

PHP 绘图工具

pChart – a PHP class to build charts

Creating a Bar Graph using CSS and PHP

Libchart

JpGraph

PHP 教程、技巧和有用的组件

Query – PHP & Ajax with the Twitter API

Sanitize and Validate Data with PHP Filters

Backup Your Database into an XML File Using PHP

10 PHP code snippets for working with strings

Caching Dynamic PHP pages easily

3 ways to compress CSS files using PHP

How to Build a Login System for a Simple Website

PHP components: Autosuggest

 

详情请阅读:http://www.goodfav.com/zh/15-useful-php-components-techniques-and-tutorials-384.html

[转载]ASP.NET WebForm(MVC)下实现消息推送(提供简单Demo下载) - Good_Luck - 博客园

mikel阅读(944)

[转载]ASP.NET WebForm(MVC)下实现消息推送(提供简单Demo下载) – Good_Luck – 博客园.

由于项目需要,笔者最近需要实现Web客户端之间的消息的即时推送功能。

功能描述如下:

假设A,B,C用户登陆,内存记录下已登录的用户的信息,这时A在所在的客户端(SendInfo.aspx)页面向B发消息,则在B所在客户端页面(SendInfo.aspx)将弹出消息框。

关键点有两个:

1.保证客户端和服务端的连接

2.保证服务端能够向客户端广播消息

笔者是第一次做这样的实现,所以Google了一些资料,了解到可使用Comet,ajax轮询,WebSocket等技术实现,由于时间关系,发现有些技术不是很容易理解,这里做了一个简单Demo.希望能够达到抛砖引玉的作用,与大家分享,共同提高。

笔者做了两个框架下的实现,ASP.NET Web Form和ASP.NET MVC 下的尝试。

ASP.NET Web Form版:

项目组织结构

AsyncHandler.cs

View Code

复制代码
using System; using System.Collections.Generic; using System.Web; using System.Threading; namespace CometSample { public class WebIMAsyncHandler : IHttpAsyncHandler { #region IHttpAsyncHandler 成员

        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { string _UID = context.Request.Params["uid"]; WebIMClientAsyncResult _AsyncResult = new WebIMClientAsyncResult(context, cb, extraData); string _Content = context.Request.Params["content"]; string _Action = context.Request.Params["action"]; if (_Action == "login") { _UID = context.Request.Params["uid"]; _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Login(_UID, _AsyncResult); } else if (_Action == "logout") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Logout(_UID, _AsyncResult); } else if (_Action == "connect") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().Connect(_AsyncResult); } else if (_Action == "getuserlist") { _AsyncResult.LoginID = _UID; WebIMMessageHandler.Instance().GetUserList(_AsyncResult); } //增加消息发送
            else if (_Action == "sendmsg") { _AsyncResult.LoginID = _UID; //WebIMMessageHandler.Instance().GetUserList(_AsyncResult); //调用
 WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult); } //调用 //WebIMMessageHandler.Instance().AddMessage(_Content, _AsyncResult);
            return _AsyncResult; } public void EndProcessRequest(IAsyncResult result) { } #endregion

        #region IHttpHandler 成员

        public bool IsReusable { get { return false; ; } } public void ProcessRequest(HttpContext context) { throw new NotImplementedException(); } #endregion } public class WebIMClientAsyncResult : IAsyncResult { bool m_IsCompleted = false; private HttpContext m_Context; private AsyncCallback m_Callback; private object m_ExtraData; private string m_Content; private string m_LoginID = string.Empty; public WebIMClientAsyncResult(HttpContext p_Context, AsyncCallback p_Callback, object p_ExtraData) { this.m_Context = p_Context; this.m_Callback = p_Callback; this.m_ExtraData = p_ExtraData; } /// <summary>
        /// 用户编号 /// </summary>
        public string LoginID { get { return m_LoginID; } set { m_LoginID = value; } } /// <summary>
        /// 发送消息的内容,暂时未使用到 /// </summary>
        public string Content { get { return m_Content; } set { m_Content = value; } } #region IAsyncResult 成员

        public object AsyncState { get { return null; } } public WaitHandle AsyncWaitHandle { get { return null; } } public bool CompletedSynchronously { get { return false; } } public bool IsCompleted { get { return m_IsCompleted; } } #endregion

        /// <summary>
        /// 向客户端响应消息 /// </summary>
        /// <param name="data"></param>
        public void Send(object data) { try { m_Context.Response.Write(this.Content); if (m_Callback != null) { m_Callback(this); } } catch { } finally { m_IsCompleted = true; } } } }
复制代码

MessageHandler.cs

View Code

复制代码
using System; using System.Collections; using System.Collections.Generic; using System.Web; using System.Text; namespace CometSample { public class WebIMMessageHandler { private static readonly WebIMMessageHandler m_Instance = new WebIMMessageHandler(); //记录所有请求的客户端
        List<WebIMClientAsyncResult> m_Clients = new List<WebIMClientAsyncResult>(); //Dictionary<string,WebIMClientAsyncResult> m_Clients=new Dictionary<string,WebIMClientAsyncResult>();
        string m_Users = string.Empty; public WebIMMessageHandler() { } public static WebIMMessageHandler Instance() { return m_Instance; } /// <summary>
        /// 登录 /// </summary>
        /// <param name="p_LoginID"></param>
        /// <param name="p_ClientAsyncResult"></param>
        public void Login(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult) { bool _Logined = false; foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_LoginID) { p_ClientAsyncResult.Content = "你已登录"; _Logined = true; break; } } if (!_Logined) { //m_Clients.Add(p_ClientAsyncResult);
                p_ClientAsyncResult.Content = "OK"; } p_ClientAsyncResult.Send(null); } private string GetUsers() { /* string _Users = string.Empty; foreach (WebIMClientAsyncResult _Item in m_Clients) { _Users += _Item.LoginID + ","; } return _Users; */

            var sbUsers = new StringBuilder(); sbUsers.Append("Users:"); foreach (WebIMClientAsyncResult _Item in m_Clients) { sbUsers.Append(_Item.LoginID); sbUsers.Append(","); } return sbUsers.ToString(); } public void Logout(string p_LoginID, WebIMClientAsyncResult p_ClientAsyncResult) { foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_LoginID) { m_Clients.Remove(_Item); break; } } p_ClientAsyncResult.Content = "退出成功"; p_ClientAsyncResult.Send(null); //UpdateUserList();

            string _Users = GetUsers(); foreach (WebIMClientAsyncResult _Item in m_Clients) { _Item.Content = _Users; _Item.Send(null); } m_Clients.Clear(); } public void GetUserList(WebIMClientAsyncResult p_ClientAsyncResult) { Connect(p_ClientAsyncResult); string _Users = GetUsers(); foreach (WebIMClientAsyncResult _Item in m_Clients) { _Item.Content = _Users; _Item.Send(null); } m_Clients.Clear(); } public void Connect(WebIMClientAsyncResult p_Client) { bool _Exists = false; foreach (WebIMClientAsyncResult _Item in m_Clients) { if (_Item.LoginID == p_Client.LoginID) { _Exists = true; break; } } if (!_Exists) { m_Clients.Add(p_Client); } } /* public void UpdateUserList() { string _Users = GetUsers(); foreach (WebIMClientAsyncResult result in m_Clients) { result.Content = m_Users; result.Send(null); } m_Clients.Clear(); }*/

        /// <summary>
        /// 广播消息 /// </summary>
        /// <param name="p_Message"></param>
        /// <param name="p_AsyncResult"></param>
        public void AddMessage(string p_Message, WebIMClientAsyncResult p_ClientAsyncResult) { //保持连接
            if (p_Message == "-1") { m_Clients.Add(p_ClientAsyncResult); } else { //将当前请求的内容输出到客户端
                p_ClientAsyncResult.Content = p_Message; p_ClientAsyncResult.Send(null); //否则将遍历所有已缓存的client,并将当前内容输出到客户端
                foreach (WebIMClientAsyncResult result in m_Clients) { //发送给所有已经登录用户
                    var strMsg = string.Format("{0}{1}{2}{3}{4}",p_ClientAsyncResult.LoginID,"发送给",result.LoginID,"的消息:",p_Message); //result.Content = p_Message;
                    result.Content = strMsg; result.Send(null); //发送给指定用户
                    /* if (string.Equals(result.LoginID, "ZhangShan") && !string.Equals(p_ClientAsyncResult.LoginID, "ZhangShan")) { var strMsg = string.Format("{0}{1}{2}{3}{4}{5}","Msgs:", p_ClientAsyncResult.LoginID, "发送给", result.LoginID, "的消息:", p_Message); //result.Content = p_Message; result.Content = strMsg; result.Send(null); } */ } //清空所有缓存
 m_Clients.Clear(); } } } }
复制代码

Login.js

View Code

复制代码
/// <reference path="jquery-1.3.2.min.js" >
$(document).ready(function () { //登录,登录成功后,获取在线用户列表,
    function login() { //增加页面跳转
        var strUrl = '/SendInfo.aspx?strUid=' + $("#txtLoginID").val(); window.open(strUrl); } $("#btnLogin").click(function () { if ($("#txtLoginID").val() == '') alert('空'); login(); }); })
复制代码

WebIM.js

View Code

复制代码
/// <reference path="jquery-1.3.2.min.js" > //$(document).ready(function () {

    //状态,代表是否登录
    //var _logined = false;

    //登录,登录成功后,获取在线用户列表,
    function login() { //$.post("comet_broadcast.asyn", { action: 'login', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'login', uid: strUid }, function (data, status) { if (data == "OK") { _logined = true; getuserlist(); //增加页面跳转
                /*var strUrl = '\SendInfo.aspx?strUid=' + $("#txtLoginID").val(); window.open(strUrl); */ } else { alert(data); } }); } //获取在线用户列表,获取列表后,进入消息等待
    function getuserlist() { //$.post("comet_broadcast.asyn", { action: 'getuserlist', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'getuserlist', uid: strUid }, function (data, status) { //alert('getuserlist' + data);
            var result = $("#divResult"); result.html(result.html() + "<br/>" + "用户列表:" + data); wait(); }); } //退出
    function logout() { //$.post("comet_broadcast.asyn", { action: 'logout', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'logout', uid: strUid }, function (data, status) { _logined = false; alert(data); } ); } //消息等待,接收到消息后显示,发起下一次的消息等待
    function wait() { //$.post("comet_broadcast.asyn", { action: 'connect', uid: $("#txtLoginID").val() },
        $.post("comet_broadcast.asyn", { action: 'connect', uid: strUid }, function (data, status) { /* var result = $("#divResult"); result.html(result.html() + "<br/>" + "用户列表:" + data); */

               //2.窗口
               new Ext.ux.ToastWindow({ title: '提示窗口', html: data, iconCls: 'error' }).show(document); //服务器返回消息,再次建立连接
               if (_logined) { wait(); } }, "html"); } /*********** *********************消息发送部分*************************** ************/

    function send() { //$.post("comet_broadcast.asyn", { action: 'sendmsg', uid: $("#txtLoginID").val(), content: $("#content").val() },
        $.post("comet_broadcast.asyn", { action: 'sendmsg', uid: strUid, content: $("#content").val() }, function (data, status) { /* var result = $("#divResult"); result.html(result.html() + "<br/>" + "已发消息:" + data); */

            //发送方页面提示
            //潜规则:暂时不处理
            /* //2.窗口 new Ext.ux.ToastWindow({ title: '提示窗口', html: data, iconCls: 'error' }).show(document); */ }, "html" ); //向comet_broadcast.asyn发送请求,消息体为文本框content中的内容,请求接收类为AsnyHandler
        //$.post("comet_broadcast.asyn", { content: $("#content").val() });

        //清空内容
        $("#content").val(""); }; /** * 获取字符串中某个特殊字符首次出现的位置之前的子串 */
    function GetSubStrBySpecChar(strConnStr,strSplit){ var arrStr = strConnStr.split(strSplit); var strSubStr = arrStr[0]; return strSubStr; }
复制代码

Default.aspx

View Code

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CometSample._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="Scripts/Login.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="帐号"></asp:Label>
        <input id="txtLoginID" type="text" />
        <input id="btnLogin" type="button" value="Login" />
        <br />
        <div id="divUserList">
        </div>
    </div>
    </form>
</body>
</html>
复制代码

SendInfo.aspx

View Code

复制代码
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SendInfo.aspx.cs" Inherits="CometSample.SendInfo" %>

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

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>SendInfo</title>
    <script src="Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="Scripts/WebIM.js" type="text/javascript"></script>

    <link href="Scripts/ext-3.4.0/resources/css/ext-all.css" rel="stylesheet" type="text/css" />
    <script src="Scripts/ext-3.4.0/adapter/ext/ext-base.js" type="text/javascript"></script>
    <script src="Scripts/ext-3.4.0/ext-all.js" type="text/javascript"></script>
    <script src="Scripts/ToastWindow.js" type="text/javascript"></script>

    <script language="javascript" type="text/javascript">

        var strUid = "<%=strUid %>"; $(document).ready(function () { //状态,代表是否登录
            var _logined = false; //alert(strUid);
            //getuserlist_send();
 login(); $("#btnSend").click(function () { send(); }) $("#content").keypress(function (e) { var keyCode = null; if (e.which) keyCode = e.which; else if (e.keyCode) keyCode = e.keyCode; if (keyCode == 13) { send(); return false; } return true; }); }) </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <div id="divUserList">
        </div>
        <br /> 广播内容: <input type="text" id="content" /><br /> 消息记录: <div id="divResult">
        </div>
        <input type="button" id="btnSend" value="广播" />
    </div>
    <div>
        <input id="btnLogout" type="button" value="注销" onclick="logout();"/></div>
    </form>
</body>
</html>
复制代码

最后还需要关注的是配置文件中的路径

在web.config 文件的system.web之间加上

<httpHandlers>
            <add path="comet_broadcast.asyn" type="CometSample.WebIMAsyncHandler" verb="POST,GET"/>
        </httpHandlers>

 

好了运行程序,

效果如下:

登陆之后,跳转到sendinfo页面

 

笔者打开连个浏览器,模拟两个客户端登陆,并且模拟广播消息(能够广播,那么向指定客户端发消息也就很容易了)

我们可以看到在页面右下角,有消息弹出

在.NET WebForm下笔者实现了客户端之间即时消息的推送,但是在.NET MVC 2 下遇到了一些问题,因为mvc框架下对 ,NET WebForm中某些东西不支持。

[转载]ASP.NET MVC中加载WebForms用户控件(.ascx) - dudu - 博客园

mikel阅读(957)

[转载]ASP.NET MVC中加载WebForms用户控件(.ascx) – dudu – 博客园.

问题背景

博客园博客中的日历用的是ASP.NET WebForms的日历控件(System.Web.UI.WebControls.Calendar),它会为“上一月”、“下一月”的链接生成”__doPostBack()”的js调用,如下图:

目前发现它会带来两个问题:

1. 不支持IE10;

2. 某些电脑不允许执行__doPostBack。

问题提炼

前提:

  1. 我们想以最低的成本解决这个问题,也就是对当前代码尽可能少的改动。所以要尽可能重用现有的日历控件代码。
  2. 日历改为Ajax加载,点击“上一月”、“下一月”时Ajax更新日历内容。
  3. ASP.NET MVC处理Ajax请求。

要解决的问题:

如何在ASP.NET MVC Controller中加载包含WebForms日历控件的用户控件(.ascx),并得到其输出的字符串,然后将__doPostBack的代码替换为ajax调用代码。

核心问题:

如何在ASP.NET MVC Controller中得到用户控件(.ascx)输出的字符串。

解决方法

先看代码

复制代码
public ActionResult Calendar() { var page = new Page(); var form = new HtmlForm(); var calendar = page.LoadControl("~/Controls/CNBlogsCalendar.ascx"); form.Controls.Add(calendar); page.Controls.Add(form); using (var sw = new StringWriter()) { System.Web.HttpContext.Current.Server.Execute(page, sw, true); return Content(sw.ToString()); } }
复制代码

代码很简单,但得到这个代码花了今天一上午时间。

代码说明:

  • 必须要new Page(),只有Page才能LoadControl。
  • 必须要new HtmlForm(),因为日历控件必要要放在<form runat=”server”>之间。
  • 关键功臣是HttpContext.Current.Server.Execute,动态加载控件并输出字符串全靠它。这个功臣是在这篇文章中找到的(感谢Sam Mueller)。之前我用过的方法(继续不走寻常路:ASP.NET MVC中使用Web Forms用户控件)不仅麻烦,而且在这个场景下会有问题。

代码运行结果:

完整代码下载:

http://files.cnblogs.com/dudu/CNBlogsDemoMvcAscx.rar

[转载]技巧:使用User Control做HTML生成 - Jeffrey Zhao - 博客园

mikel阅读(1176)

[转载]技巧:使用User Control做HTML生成 – Jeffrey Zhao – 博客园.

User Control大家肯定不会陌生,在使用ASP.NET的过程中,除了aspx页面,最常见的就莫过于ascx了。ascx是一个有独立逻辑的组件,提供 了强大的复用特性,合理使用,能够大大提高开发效率。通过User Control直接生成HTML内容其实已经是一个比较常用的技巧了(尤其在AJAX时代),不过网络上这方面的内容比较少,很多人还是在苦苦地拼接字符 串,因此在这里我通过一个实例简单介绍一下这个技巧。

对一个对象(文章,图片,音乐,etc.)进行评论是应用中最常见的功能之一。首先,我们定义一个Comment类,以及其中会用到的“获取”方法:

public partial class Comment
{
public DateTime CreateTime { get; set; }

public string Content { get; set; }
}

public partial class Comment
{
private static List<Comment> s_comments = new List<Comment>
{
new Comment
{
CreateTime = DateTime.Parse("2007-1-1"),
Content = "今天天气不错"
},
new Comment
{
CreateTime = DateTime.Parse("2007-1-2"),
Content = "挺风和日丽的"
},
new Comment
{
CreateTime = DateTime.Parse("2007-1-3"),
Content = "我们下午没有课"
},
new Comment
{
CreateTime = DateTime.Parse("2007-1-1"),
Content = "这的确挺爽的"
}
};

public static List<Comment> GetComments(int pageSize, int pageIndex, out int totalCount)
{
totalCount = s_comments.Count;

List<Comment> comments = new List<Comment>(pageSize);

for (int i = pageSize * (pageIndex - 1);
i < pageSize * pageIndex && i < s_comments.Count; i++)
{
comments.Add(s_comments[i]);
}

return comments;
}
}

为了显示一个评论列表,我们可以使用一个用户控件(ItemComments.aspx)来封装。自然,分页也是必不可少的:

<asp:Repeater runat="server" ID="rptComments">
<ItemTemplate>
时间:<%# (Container.DataItem as Comment).CreateTime.ToString() %><br />
内容:<%# (Container.DataItem as Comment).Content %> </ItemTemplate>
<SeparatorTemplate>
<hr />
</SeparatorTemplate> <FooterTemplate> <hr /> </FooterTemplate>
</asp:Repeater>

<% if (this.PageIndex > 1)
{ %>
<a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页">上一页</a>&nbsp;
<% } %>

<% if (this.PageIndex * this.PageSize < this.TotalCount)
{ %>
<a href="/ViewItem.aspx?page=<%= this.PageIndex + 1 %>" title="上一页">下一页</a>
<% } %>

还有:

public partial class ItemComments : System.Web.UI.UserControl
{
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);

this.rptComments.DataSource = Comment.GetComments(this.PageSize,
this.PageIndex, out this.m_totalCount); this.DataBind();
}

public int PageIndex { get; set; }

public int PageSize { get; set; }

private int m_totalCount;
public int TotalCount
{
get
{
return this.m_totalCount;
}
}
}

然后再页面(ViewItem.aspx)中使用这个组件:

<div id="comments"><demo:ItemComments ID="itemComments" runat="server" /></div>

以及:

public partial class ViewItem : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.itemComments.PageIndex = this.PageIndex;
}

protected int PageIndex
{
get
{
int result = 0;
Int32.TryParse(this.Request.QueryString["page"], out result);

return result > 0 ? result : 1;
}
}
}

打开ViewItem.aspx之后效果如下:

时间:2007/1/1 0:00:00 内容:今天天气不错


时间:2007/1/2 0:00:00 内容:挺风和日丽的


时间:2007/1/3 0:00:00 内容:我们下午没有课


下一页

这 张页面的功能非常简单,那就是察看评论。当前评论的页码会使用QueryString的page项进行指定,然后在ViewItem.aspx里获取到并 且设置ItemComments.ascx控件的属性。ItemComments控件会根据自身属性来获取数据,进行绑定,至于显示内容,全都定义在 ascx中了。由于需要分页功能,这个评论控件中还包含了上一页和下一页的链接,他们链接的目标很简单,就是ViewItem.aspx页,并且加上页码 的Query String而已。

功能是完成了,不过用着用着忽然觉得不妥,为什么呢?因为我们在翻页,或者用户发布评论的时候,整张页 面都刷新了。这可不好,要知道可能ViewItem页中还有其他几个显示部分,它们可是不变的。而且如果其他几个部分也需要分页,那么可能就需要保留页面 上每一部分的当前页码,这样开发的复杂性还是比较高的。

那么我们不如用AJAX吧。无论是用户察看评论时进行翻页还是发表评论,都不会对页面上的其他内容造成影响。要开发这个功能,自然需要服务器端的支持,那么该怎么做呢?一般我们总是有两种选择:

  1. 服务器端返回JSON数据,在客户端操作DOM进行呈现。
  2. 服务器端直接返回HTML内容,然后在客户端设置容器(例如上面id为comments的div)。

不 过无论采用哪种做法,“呈现”的逻辑一般总是另写一遍(第一次的呈现逻辑写在了ItemComments.ascx中)。如果使用第1种做法,那么呈现逻 辑就需要在客户端通过操作DOM进行呈现;如果使用第2种做法,那么就要在服务器端进行字符串拼接。无论哪种做法都违背了DRY原则,当 ItemComments.ascx里的呈现方式修改时,另一处也要跟着修改。而且无论是操作DOM元素还是拼接字符串维护起来都比较麻烦,开发效率自然 也就不高了。

如果我们能够直接从ItemComments控件获得HTML内容该多好啊——那么我们就这么做吧。请看如下代码(GetComments.ashx):

public class GetComments : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";

ViewManager<ItemComments> viewManager = new ViewManager<ItemComments>();
ItemComments control = viewManager.LoadViewControl("~/ItemComments.ascx");

control.PageIndex = Int32.Parse(context.Request.QueryString["page"]);
control.PageSize = 3;

context.Response.Write(viewManager.RenderView(control));
}

public bool IsReusable { ... }
}

很简单的代码,不是吗?创建对象,设置属性,然后通过Response.Write输出而已。实在没什么大不了的——不过关键就在于ViewManager类,我们来看一下它是怎么实现的:

public class ViewManager<T> where T : UserControl
{
private Page m_pageHolder;

public T LoadViewControl(string path)
{
this.m_pageHolder = new Page();
return (T)this.m_pageHolder.LoadControl(path);
}

public string RenderView(T control)
{
StringWriter output = new StringWriter();

this.m_pageHolder.Controls.Add(control);
HttpContext.Current.Server.Execute(this.m_pageHolder, output, false);

return output.ToString();
}
}

ViewManager中只有两个方法:LoadViewControl和RenderView。LoadViewControl方法的作用是创 建一个Control实例并返回,RenderView方法的作用则就是生成HTML了。这个实现方式的技巧在于使用了一个新建的Page对象作为生成控 件的“容器”,而最后其实我们是将Page对象的整个生命周期运行一遍,并且将结果输出。由于这个空的Page对象不会产生任何其他代码,因此我们得到 的,就是用户控件生成的代码了。

不过要实现这个AJAX效果,还需要做两件事情。

第一,就是简单修改一下ItemComments控件中的翻页链接,让它被点击时调用一个JavaScript函数。例如“上一页”的代码就会变成:

<a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页"
onclick="return getComments(<%= this.PageIndex - 1 %>);">上一页</a>

第二,就是实现getComments这个客户端方法。在这里我使用了prototype框架,好处就是能够用相当简洁的代码来做到替换HTML的AJAX效果:

<script type="text/javascript" language="javascript">
function getComments(pageIndex)
{
new Ajax.Updater(
"comments",
"/GetComments.ashx?page=" + pageIndex + "&t=" + new Date(),
{ method: "get" }); 

return false; // IE only
}
</script>

大功告成。

其实就像之前所说的那样,使用UserControl进行HTML代码生成是一个十分常用的技巧。尤其在AJAX应用 越来越普及的情况下,合理使用上面提到的方式可以方便的为我们的应用添加AJAX效果。而且很多情况下,我们即使不需要在页面上显示内容,也可以将内容使 用UserControl进行编辑。因为编写UserControl比拼接字符串的方式无论是在开发效率上还是可维护性上都高出许多。由于这个方式其实使 用了WebForms这个久经考验的模型,因此在执行效率方面也是相当高的。此外,就刚才的例子来说,使用UserCotrol进行HTML生成还有其他 好处:

  1. 页面呈现逻辑只实现了一次,提高了可维护性。
  2. 不会影响页面的SEO,因为在客户端<a />的href还是有效的。

事 实上,WebForms是一个非常强大的模型,所以ASP.NET MVC的View也使用了WebForms的引擎。通过上面这个例子,我们其实还可以做到其他很多东西——例如用UserControl来生成XML数 据,因为UserControl本身不会带来任何额外的内容。