如何设计我的C#jQuery API,使其不会混淆使用?

我是making a jquery clone for C#.现在我已经设置好了,所以每个方法都是IEnumerable< HtmlNode>上的扩展方法.所以它适用于已经使用HtmlAgilityPack的现有项目.我以为我可以在不保留状态的情况下离开……然而,我注意到jQuery有两种方法.andSelf和.end“弹出”内部堆栈中最近匹配的元素.如果我改变我的类以便它总是在SharpQuery对象上运行而不是枚举,我可以模仿这个功能,但是仍然存在问题.

使用JavaScript,您可以自动获得Html文档,但在使用C#时,您必须明确加载它,如果需要,您可以使用多个文档.看来,当你调用$(‘xxx’)时,你实际上是在创建一个新的jQuery对象,并以空堆栈开始.在C#中,您不希望这样做,因为您不想从Web重新加载/重新获取文档.因此,您只需将其加载到SharpQuery对象中,或加载到HtmlNodes列表中(您只需要开始使用DocumentNode).

在jQuery文档中,他们给出了这个例子

$('ul.first').find('.foo')
  .css('background-color','red')
.end().find('.bar')
  .css('background-color','green')
.end();

我没有初始化方法,因为我不能重载()运算符,所以你只需要从sq.Find()开始,它在文档的根目录上运行,基本上做同样的事情.但是后来人们试着在一行上写sq.Find(),然后在某个地方写sq.Find(),并且(理所当然地)期望它再次在文档的根上运行……但是如果我维持状态,然后你刚刚在第一次调用修改了上下文.

那么……我应该如何设计我的API?我是否添加了另一个所有查询应该从重置堆栈开始的Init方法(但是我如何强制它们从那开始呢?),或者添加一个他们必须在行尾调用的Reset()?我是否重载[]而告诉他们从那开始?我会说“忘记它,没有人使用那些保存状态的功能吗?”

基本上,您希望如何用C#编写jQuery示例?

> sq [“ul.first”].查找(“.foo”)…
垮台:滥用[]属性.
> sq.Init(“ul.first”).查找(“.foo”)…
失败:除非我添加一些奇怪的“初始化”机制,否则没有什么能真正迫使程序员从Init开始;用户可能会尝试以.Find开始而不是获得他期望的结果.此外,无论如何,Init和Find几乎完全相同,除了前者也重置堆栈.
> sq.Find(“ul.first”).Find(“.foo”)….ClearStack()
垮台:程序员可能忘记清理堆栈.
>不能这样做.
end()没有实现.
>使用两个不同的对象.
也许使用HtmlDocument作为所有查询应该开始的基础,然后每个方法返回一个可以链接的SharpQuery对象.这样HtmlDocument始终保持初始状态,但SharpQuery对象可能具有不同的状态.遗憾的是,我必须实现两次(一次用于HtmlDocument,一次用于SharpQuery对象).
> new SharpQuery(sq).Find(“ul.first”).Find(“.foo”)…
构造函数复制对文档的引用,但重置堆栈.

最佳答案
我认为你遇到的主要绊脚石是,你正试图为每个文档只有一个SharpQuery对象.这不是jQuery的工作方式;通常,jQuery对象是不可变的.当您调用更改元素集的方法(如find或end或add)时,它不会更改现有对象,但会返回一个新对象:

var theBody = $('body');
// $('body')[0] is the 

(有关详细信息,请参阅documentation of end)

SharpQuery应该以相同的方式运行.使用文档创建SharpQuery对象后,方法调用应返回新的SharpQuery对象,引用同一文档的不同元素集.例如:

var sq = SharpQuery.Load(new Uri("http://api.jquery.com/category/selectors/"));
var header = sq.Find("h1"); // doesn't change sq
var allTheLinks = sq.Find(".title-link") // all .title-link in the whole document; also doesn't change sq
var someOfTheLinks = header.Find(".title-link"); // just the .title-link in the 

这种方法的好处有几个.因为sq,header,allTheLinks等都是同一个类,所以每个方法只有一个实现.然而,这些对象中的每一个都引用相同的文档,因此您没有每个节点的多个副本,并且对该节点的更改反映在该文档上的每个SharpQuery对象中(例如,在allTheLinks.text(“foo”)之后,someOfTheLinks. text()==“foo”.).

实现结束和其他基于堆栈的操作也变得容易.当每个方法从另一个方法创建一个新的,已过滤的SharpQuery对象时,它会保留对该父对象的引用(allTheLinks to header,header to sq).然后结束就像返回一个包含与父元素相同元素的新SharpQuery一样简单,如:

public SharpQuery end()
{
    return new SharpQuery(this.parent.GetAllElements());
}

(或者你的语法抖落了.)

我认为这种方法将为您提供最类似jQuery的行为,并且具有相当简单的实现.我一定会关注这个项目;这是一个好主意.

相关文章

页面搜索关键词突出 // 页面搜索关键词突出 $(function () {...
jQuery实时显示日期、时间 html: &lt;span id=&quot...
jQuery 添加水印 &lt;script src=&quot;../../../.....
中文:Sys.WebForms.PageRequestManagerParserErrorExceptio...
1. 用Response.Write方法 代码如下: Response.Write(&q...
Jquery实现按钮点击遮罩加载,处理完后恢复 思路: 1.点击按...