我是 制作jQuery克隆 对于C#。现在我已经设置了它,以便每种方法都是扩展方法 IEnumerable<HtmlNode> 因此,它可以与已经使用的现有项目合作 HtmlAgilityPack. 。我以为我可以在不保留状态的情况下逃脱...但是,我注意到jQuery有两种方法 .andSelf.end 它“流行”是最近匹配的内部堆栈中的元素。如果我更改课程,我可以模仿此功能,以便它总是在锋利的对象上运行,而不是枚举,但仍然存在问题。

使用JavaScript,您会自动授予HTML文档,但是在C#中工作时,您必须显式加载它,并且可以根据需要使用多个文档。看来当你打电话 $('xxx') 您本质上是创建一个新的jQuery对象,并从空堆栈开始新鲜。在C#中,您不想这样做,因为您不想从网络中重新加载/淘汰文档。因此,相反,您将其加载到锋利的对象或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示例?

  1. sq["ul.first"].Find(".foo") ...
    堕落:滥用 [] 财产。

  2. sq.Init("ul.first").Find(".foo") ...
    倒台:除非我添加一些怪异的“初始化”机制,否则没有什么真正迫使程序员开始从Init开始。用户可能会尝试从 .Find 而且没有得到他期望的结果。还, InitFind 无论如何,除了前者也重置堆栈外,几乎是相同的。

  3. sq.Find("ul.first").Find(".foo") ... .ClearStack()
    失败:程序员可能会忘记清除堆栈。

  4. 无法做到。
    end() 未实现。

  5. 使用两个不同的对象。
    也许使用 HtmlDocument 作为所有查询都应开始的基础,然后每种方法都返回 SharpQuery 可以链接的对象。这样 HtmlDocument 始终保持初始状态,但是 SharpQuery 对象可能具有不同的状态。不幸的是,这意味着我必须两次实现一堆东西(一次用于HTMLDOcument,一次是用于SharpQuery对象)。

  6. new SharpQuery(sq).Find("ul.first").Find(".foo") ...
    构造函数复制对文档的引用,但重置堆栈。

有帮助吗?

解决方案

我认为您在这里遇到的主要绊脚石是您试图摆脱一个 SharpQuery 每个文档的对象。那不是jQuery的工作方式;通常,jQuery对象是不可变的。当您调用更改元素集的方法时(例如 find 或者 end 或者 add),它不会改变现有对象,而是返回一个新对象:

var theBody = $('body');
// $('body')[0] is the <body>
theBody.find('div').text('This is a div');
// $('body')[0] is still the <body>

(请参阅 文档 end 有关更多信息)

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 <h1>; again, doesn't change sq or header

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

实施 end 而且其他基于堆栈的操作也变得容易。每种方法都会创建一个新的过滤 SharpQuery 从另一个对象,它保留对该父对象的引用(allTheLinksheader, headersq)。然后 end 就像返回新的一样简单 SharpQuery 包含与父母相同的元素,例如:

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

(或者您的语法摇摆不定。)

我认为这种方法将带给您最类似jQuery的行为,并具有相当容易的实现。我一定会关注这个项目;这是一个好主意。

其他提示

我会倾向于选项2上的变体。在jQuery $()中是一个函数调用。 C#没有全局函数,静态函数调用是最接近的。我会使用一种指示您创建的包装器的方法。

SharpQuery.Create("ul.first").Find(".foo")

我不会担心将Sharpquery缩短到SQ,因为Intellisense意味着用户不必键入整个内容(如果他们具有重能,则只需要键入SQ)即可。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top